66

If I had a compiled Golang program that I wanted to install such that I could run it with a bash command from anywhere on my computer, how would I do that? For example, in nodejs

npm install -g express

Installs express such that I can run the command

express myapp

and express will generate a file directory for a node application called "myapp" in whatever my current directory is. Is there an equivalent command for go? I believe now with the "go install" command you have to be in the directory that contains the executable in order to run it

Thanks in advance!

Ryan
  • 1,131
  • 3
  • 13
  • 17
  • you add GOPATH/bin to your PATH? (or are you looking for some sort of [go package manager](https://github.com/golang/go/wiki/PackageManagementTools)?) – JimB Apr 15 '16 at 14:40

8 Answers8

49

Update: If you're using Go 1.16, this answer still works, but go install has changed and is now the recommended method for installing executable packages. See Karim's answer for an explanation: https://stackoverflow.com/a/68559728/10490740

Using Go >= 1.11, if your current directory is within a module-based project, or you've set GO111MODULE=on in your environment, go get will not install packages "globally". It will add them to your project's go.mod file instead.

As of Go 1.11.1, setting GO111MODULE=off works to circumvent this behavior:

GO111MODULE=off go get github.com/usr/repo

Basically, by disabling the module feature for this single command, it will install to GOPATH as expected.

Projects not using modules can still go get normally to install binaries to $GOPATH/bin.

There's a lengthy conversation and multiple issues logged about this change in behavior branching from here: golang/go - cmd/go: go get should not add a dependency to go.mod #27643.

Alec
  • 490
  • 1
  • 4
  • 8
35

Starting with Go >= 1.16 the recommended way to install an executable is to use

go install package@version

For example, go install github.com/fatih/gomodifytags@latest.

Executables (main packages) are installed to the directory named by the GOBIN environment variable, which defaults to $GOPATH/bin or $HOME/go/bin if the GOPATH environment variable is not set. You need to add this directory to your PATH variable to run executables globally. In my case, I've added this line to my ~/.zshrc file. (if you are using bash, add it to the ~/.bash_profile file):

export PATH="$HOME/go/bin:$PATH"

Go team published a blog post about this change, here's the explanation quote:

We used to recommend go get -u program to install an executable, but this use caused too much confusion with the meaning of go get for adding or changing module version requirements in go.mod.

Refer to go install documentation for more details

Karim
  • 2,388
  • 1
  • 19
  • 13
  • I am using go 1.19, I have GO111MODULE=on and GOMODCACHE set to some directory - $HOME/go/pkg/mod. I see go install @version is downloading in GOMODCACHE directory. Why is this happening any idea? – Rajendra Gosavi Jan 04 '23 at 09:15
24

As far as I know, there is no direct equivalent to npm install -g. The closest equivalent would not be go install, but go get. From the help page (go help get):

usage: go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]

Get downloads and installs the packages named by the import paths, along with their dependencies.

By default, go get installs binaries to $GOPATH/bin, so the easiest way to make those binaries callable from everywhere is to add that directory to your $PATH.

For this, put the following line into your .bashrc (or .zshrc, depending on which shell you're using):

export PATH="$PATH:$GOPATH/bin"

Alternatively, you could also copy or link the executables to /usr/local/bin:

ln -s $GOPATH/bin/some-binary /usr/local/bin/some-binary
helmbert
  • 35,797
  • 13
  • 82
  • 95
  • 2
    At the time this was correct (and thank you for your help) but it's worth noting for anyone who comes across this question that there is now a `go install` that builds a binary and puts it in your `$GOPATH/bin` – Ryan Nov 16 '17 at 14:22
  • 1
    I have to install all the dependencies listed in the go.mod file. I can do it one my one using the go get command, but is there any other alternative to this? Something like npm i and it installs the required dependencies all at once. – Om Gupta Jul 03 '21 at 07:14
9

Short solution for Linux users:

  1. Use the go get command as usual
  2. Add the following lines to .bashrc:
# This is the default GOPATH, you should confirm with the 'go env' command
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
  1. Restart terminal or source it. Installed binaries will be available globally.

For Go v1.8+

  1. go install package_name@latest
Mohamed Sohail
  • 1,659
  • 12
  • 23
5

Caveat: this answer is outdated following the 2020 deprecation of go get. The solution presented here won't work with newer Go runtime installs.

The closest analogue of this in Go would be go get. By default, it will fetch a Go package from a supplied repository URL, and requires a $GOPATH variable to be set in your shell so that Go knows where to store the packages (and subsequently where to find them when compiling code depending on go get-ted packages).

Example syntax:

$ go get github.com/user/repo

The behaviour supplied by npm's -g flag is default, and packages installed using go get are normally available globally.

See go get --help for more information about the command.

As mentioned by @helmbert, adding your $GOPATH to your $PATH is useful if you're installing standalone packages.

Jules
  • 14,200
  • 13
  • 56
  • 101
  • When I use this, the go/bin folder is invariant. Is there anywhere else the files could go? – kendfss Mar 20 '21 at 15:32
  • @kendfss a bit late to the party (and I imagine you've found a solution by now), but at some point between this answer and your comment, Go saw a fairly major rework of how packages are vendored. Most notably, [`go get` is deprecated since 2020](https://go.dev/doc/go-get-install-deprecation). I haven't used Go as a main programming language in a while so I can't give much more advice beyond following that official doc. – Jules Nov 24 '22 at 04:43
2

if you are using zsh :

first: install your package using :

go install package@version

then , you edit your .zshrc file

nano ~/.zshrc

Add this line to the end of .zshrc file :

export PATH="$HOME/go/bin:$PATH"

last but not least :

source ~/.zshrc

then open a new terminal and execute your command :)

0

TL;DR at the bottom. I'm going to walk you through how I came to this conclusion, and why the more obvious solutions don't work.


Upon seeing this question, I thought "If I could set root's GOPATH=/usr, it would install things in /usr/bin/ and /usr/src!"

So I tried the obvious thing:

  1. Add GOPATH=/usr to root's .bashrc.
    And it worked!
    Sort of.
    Not really.
    Turns out, sudo doesn't execute root's .bashrc. For "security" or something like that.

  2. Do env_set or something in /etc/sudoers
    Turns out, /etc/sudoers can only remove environment variables. There's no env_set directive.
    (As far as I can find)

  3. Dig through man sudoers.
    Where does sudo get it's default set of environment variables from?
    Well, the first one in the list is /etc/environment, so that's the one I used.


sudo echo "GOPATH=/usr" >> /etc/environment
sudo go get <repo>

Binaries will be put in /usr/bin, and sources will be put in /usr/src.

Running go as non-root will use GOPATH the "normal" way.

SIGSTACKFAULT
  • 919
  • 1
  • 12
  • 31
  • you could also `GOPATH=/` and install in `/bin` and `/src`. – SIGSTACKFAULT Jul 11 '19 at 14:24
  • Typically, `/bin` and `/usr/bin` should only be modified by your distro package manager. `/usr/local` is a much better place to put system-wide modifications. You won't accidentally step on your package manager's toes, and permissions are often more amenable to unprivileged alteration (e.g., on macOS). – Mr. DOS Nov 30 '20 at 09:56
0

If you don't have go installed, you may use the gobinaries. it builds an on-demand binary of the project from github repo.

The command to install the go package would be:

curl -sf https://gobinaries.com/rakyll/hey | sh
rezam
  • 627
  • 1
  • 12
  • 17