As of Go 1.14, modules are ready for production. Compared to GOPATH, they make it much easier to keep workspaces clean by managing dependencies out of sight, and by letting you clone projects anywhere. However, there is no good way to simply install a Go binary from source, yet.

The core reason for this is that go get is a software development tool, not a software distribution tool, and binaries should be distributed through package managers. However, many tools are not packaged.

Back in the GOPATH days I had a script, brew-go-get, which would run go get in a temporary GOPATH and then use Homebrew to safely link the binary in place, so that you could track the installation with brew list and remove it with brew uninstall.

I have updated the script for modules, and it works a lot better!

Introducing brew gomod.

$ brew install FiloSottile/gomod/brew-gomod
$ brew gomod github.com/maruel/panicparse/cmd/pp
go: creating new go.mod: module gomod-pp/2020-03-15
go: downloading github.com/maruel/panicparse v1.3.0
go: found github.com/maruel/panicparse/cmd/pp in github.com/maruel/panicparse v1.3.0
go: downloading github.com/mattn/go-isatty v0.0.7
go: downloading github.com/mattn/go-colorable v0.1.1
go: downloading github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b
go: downloading golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
Linking /usr/local/Cellar/gomod-pp/2020-03-15...  1 symlinks created
$ pp -help
Usage of pp: [...]
$ brew uninstall gomod-pp
Uninstalling /usr/local/Cellar/gomod-pp/2020-03-15... (3 files, 4.8MB)

Here's how it works:

  1. it creates a new Go module at /usr/local/Cellar/gomod-$name/$date/libexec/mod (the Cellar is where Homebrew software is installed, and libexec is a magic path that doesn't get linked into /usr/local)
  2. within that module, it runs go get with a GOBIN set to /usr/local/Cellar/gomod-$name/$date/bin
  3. it runs brew link gomod-$name to get the binary linked into /usr/local/bin

Like any Homebrew installation, it's easy to track and uninstall, and manual installations like this are officially supported. The modules solution also has a number of advantages over the GOPATH solution:

  • it's secured by the Go checksum database agains tampering
  • it uses the system module and build cache, avoiding duplicate downloads and source trees
  • it leaves behind the exact versions used in libexec/mod/go.mod
  • the built binaries have access to their own version via debug.BuildInfo

Install the command easily with

$ brew install FiloSottile/gomod/brew-gomod

and let me know on Twitter how it works.