You don’t need to set GOROOT, really

Introduction

This is a short post to explain why it is not necessary to set $GOROOT when compiling or using Go.

TL;DR

In general1 it is not necessary to set the $GOROOT environment variable when compiling or using Go 1.0 or later. In fact, setting $GOROOT can lead to hard to debug problems if you have multiple versions of Go present on your computer.

You still need to set $GOPATH. Since Go 1.0 setting $GOPATH has been highly recommended, and with the release of Go 1.1, it is considered mandatory.

Why isn’t GOROOT required anymore ?

You’re still reading ? Excellent. Now for some history.

The history of the GO* environment variables

Go old timers may remember when not only $GOROOT, but $GOOS and $GOARCH were required environment variables. These were required because the Makefile based build system used lots of includes which used $GOROOT as their base path.

By the time the go tool was introduced, prior to Go 1.0, $GOOS and $GOARCH were optional as the build scripts were able to detect the host’s operating system and cpu architecture. With the release of Go 1.0, and the introduction of the cmd/dist bootstrap build tool, $GOOS and $GOARCH became truly optional. They are now only used when cross compiling.

Go 1.0 also introduced $GOPATH based workspaces. If you’ve read this far, you probably know what a $GOPATH workspace is. But in case you don’t, this is documented on the golang.org website, and in this screencast.

Okay, so I don’t need $GOOS or $GOARCH, but what about $GOROOT ?

$GOROOT has always been defined as a pointer to the root of your Go installation. In the old Makefile based build system, it was used as the base path for including other Makefiles, and since Go 1.0 it is used by the go tool to find the compiler (stored in $GOROOT/pkg/tool/$GOOS_$GOARCH) and the standard library (also in $GOROOT/pkg/$GOOS_$GOARCH). If you are a Java user, $GOROOT is similar in effect to $JAVA_HOME.

When you compile Go from source, the value of $GOROOT is automatically discovered2 (it is one directory up from the all.bash script) and then embedded into the go tool built from that source tree. You can see this when you run go env

% echo $GOROOT

% go env GOROOT
/home/dfc/go

The binary distributions you download from the golang.org website, or install from your operating system distribution also have the correct $GOROOT value embedded into the go tool binary. Here is an example from a Ubuntu 12.04 system which ships with Go 1.0.

% dpkg -l golang-{go,src} | grep ^ii
ii  golang-go        2:1-5        Go programming language compiler
ii  golang-src       2:1-5        Go programming language compiler - source files
% which go
/usr/bin/go
% go env GOROOT
/usr/lib/go

You can see that the go tool is installed in /usr/bin/go and $GOROOT is embedded as /usr/lib/go.

So, why shouldn’t I set $GOROOT anymore ?

You should not set $GOROOT because the correct value is already embedded in the go tool.

Setting $GOROOT will override the value stored in the go tool which could lead to the go tool from one version of Go pointing to the compiler and standard library from another version.

There are only two cases that where you may have to set a $GOROOT environment. These are both described in the installation page on the golang.org website. For completeness I will recap them here

  • You are a Linux, FreeBSD or OS X user using the the zip or tarball binary downloads from the golang.org website. These binaries have a $GOROOT value of /usr/local/go and recommend you unpack them into that location. If you choose not to do this, then you must set $GOROOT to the location you chose.
  • You are a Windows user using the zip binary download from the golang.org website. These binaries have a $GOROOT value of C:\Go. If you place Go somewhere else on your system then you must set $GOROOT to the location you chose.

Super nerdy bonus detail

This post has explained how $GOROOT is automatically discovered when compiling from source. I’ve also shown that the build scripts can detect when that value doesn’t match the path that all.bash is invoked from. So, how do operating system distributions set $GOROOT when they normally compile Go in a temporary build directory or chroot? The answer is the $GOROOT_FINAL value, which is used to override the $GOROOT location stored in the go tool.

For example, the Debian/Ubuntu build process will supply a value for $GOROOT_FINAL of /usr/lib/go. This frees it to leave $GOROOT unset, making the build process happy. After the build, the build process will install the go tool in /usr/bin, and the compilers, sources and packages in /usr/lib/go.


  1. There are a few cases where it is required if using the binary distributions of Go, which are described in this post.
  2. That is, if you haven’t set $GOROOT. Although the build system will detect when the parent directory of all.bash does not match $GOROOT.

14 thoughts on “You don’t need to set GOROOT, really

  1. Pingback: あなたがGOROOTを本当に設定しなくていい理由 | Androg

  2. Russel Winder

    In the past I found I had to set GOBIN in order for the build of Go to use a platform dependent location for the build. This is required for me as I have a shared filestore with Linux 64-bit and OS X 64-bit builds in it; without GOBIN set the two builds would use the same target directory. GOBIN depends on GOROOT, so I had to set GOROOT. Is this no longer the case? Can you set GOBIN without setting GOROOT?

    1. Dave Cheney Post author

      I’m almost certain that GOBIN does not depend on GOROOT. If you are cross compiling you might want to use the -o option for go build and that using go install.

  3. metaleap

    “If you place Go somewhere else on your system then you must set $GOROOT to the location you chose.” — so there we go: many of us pretty much totally DO need to set GOROOT in fact. ;)

    1. Dave Cheney Post author

      I’m concerned that you missed the point of my post, being that $GOROOT is an optional setting and has a specialised use. This is very similar to my rant about folks who stick

      runtime.GOMAXPROCS(runtime.NumCPU())

      in their main functions by rote.

      I do not believe, nor have any supporting evidence, that people using the binary zip/tarball installs of Go are in the majority, nor of that subset, do many of them choose to stray from the default install location.

      1. Greg

        Putting something in /usr manually is a bit unusual. That area is usually handled by the distribution’s package management system. For hand-jamming installations, for the whole system as root, the more canonical location is /opt. For installing in your own local account, ~/.local is a per-user facsimile of the operating system /usr file tree. (And then you can make a symlink in ~/bin.)

        So, it seems to me, you don’t need to mess with $GOROOT if you are installing a packaged version, but you basically always will need it if using the binary distribution. Unless you want to risk a conflict with your package manager’s notion of who owns what files and install manually to /usr.

        1. Dave Cheney Post author

          It’s not /usr, it is /usr/local/go. There is a difference. Again, everyone keeps missing the point. The point is not the default installation location is wrong, incorrect, or doesn’t suit people. The point of this article was, GOROOT was manditory, but now it is optional. All the cases pointed out by yourself and the other folks who have commented, while valid, are not a justification to set GOROOT by rote.

      2. metaleap

        Might well be — you probably have a better idea of what the “majority” are up to than me. That said, as opposed to the “binary” distribution, are you suggesting the majority are building Go from source? That’d be quite impressive, though I have no idea why the majority would really bother with that. Then again, I remember from my Linux days that often “installing” equals running make scripts ;D

        If I was on a Unix, I’d still definitely prefer manual versioned $home sub-folders as in ~/go-1.0.3, ~/go-1.1, ~/go-1.1.1 and set GOROOT and PATH to whatever Go install I wanna use—but since I’m on Win7 currently / for the time being, I still prefer those, on a separate drive, to c:\go — but I agree I’m definitely not the majority. But I’m pretty sure I’m also not the only one like this. Developers are an opinionated bunch after all =)

        And as soon as I’m not in the default location c:\go — “go build” fails if no GOROOT is set, at least at my end. Your headline made me hopeful that just running go.exe will have it auto-detect the folder it is executed from to determine GOROOT dynamically. And that certainly doesn’t seem to be the case.

    1. Dave Cheney Post author

      Yup, and the contribution guidelines also reference $GOROOT when using the codereview plugin. I don’t think either of these qualifies as a significant exception.

  4. foljs

    OK, here’s my use case.

    I clone the go repo in a folder, say ~/gorepo/

    I want to build an install go in ~/go/ and I want to be able to have my src and pkgs I “go install” go there.

    I al so want, from time to time, to be able to update the repo in ~/gorepo/ and build/install the new version in ~/go/

    How should I go about it? I still need GOROOT, right?

    1. Dave Cheney Post author

      If you are checking Go out to ~/gorepo then you could use GOROOT_FINAL=$HOME/go. It does sound like you’re fighting upstream, why not just do the checkout to ~/go in the first place.

Comments are closed.