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 Makefile
s, 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 ofC:\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
.
- There are a few cases where it is required if using the binary distributions of Go, which are described in this post.
- That is, if you haven’t set
$GOROOT
. Although the build system will detect when the parent directory ofall.bash
does not match$GOROOT
.
Pingback: あなたがGOROOTを本当に設定しなくていい理由 | Androg
Good post.
(stored in $GOROOT/pkg/tool/$GOOS_$GOARCH) and the standard library (also in $GOROOT/pkg/$GOOS_$GOARCH) isn’t it?
Ohh, good catch. Thank you very much.
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?
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.
“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. ;)
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
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.
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.
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 setGOROOT
by rote.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.
I use GOROOT in my .vimrc:
set runtimepath+=$GOROOT/misc/vim
Yup, and the contribution guidelines also reference
$GOROOT
when using thecodereview
plugin. I don’t think either of these qualifies as a significant exception.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?
If you are checking Go out to
~/gorepo
then you could useGOROOT_FINAL=$HOME/go
. It does sound like you’re fighting upstream, why not just do the checkout to~/go
in the first place.