Is it true that GOPATH and GOROOT are no longer needed?

It so happened that developers who are just starting to get acquainted with Go often encounter the problem of choosing a working directory for Go projects. So in the chat of the GolangConf conference this question was also asked. New gophers often scare each other with the words GOPATH and GOROOT . However, in the quick start guides with the current version of Go (1.13), these two β€œscary” words are not mentioned at all.







Let's see why. For the purity of the experiment, I deployed fresh Ubuntu to a virtual machine and installed Go according to the instructions from the Wiki :







sudo add-apt-repository ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install golang-go
      
      





Go 1.13 is installed and ready to use:







 $ go version go version go1.13 linux/amd64 $ which go /usr/bin/go $ whereis go go: /usr/bin/go /usr/lib/go /usr/share/go /usr/share/man/man1/go.1.gz
      
      





GOROOT



About GOROOT



has already been perfectly written in the article of 2015 , and this information is still relevant.







It's funny that among the list of directories issued by the last command ( whereis go



), GOROOT



is actually not:







 $ go env GOROOT /usr/lib/go-1.13
      
      





So, for example, if for the IDE I need to specify the path to the files of the standard Go library, I will specify /usr/lib/go-1.13



. Perhaps, in this scenario, the use of GOROOT



in everyday life ends.







GOPATH and modules



It would seem that in this place you need to rush to install GOPATH



, but I will not do this. Actually GOPATH



already set:







 $ go env GOPATH /home/elena/go
      
      





I'm comfortable with the GOPATH



in ~/go



, which means I won’t change it.







I will immediately create a directory for my first project on Go. This can be done anywhere, for example, right in your home directory. Also, I will immediately start working with the Go Modules tool:







 $ mkdir ~/hello $ go mod init github.com/rumyantseva/hello go: creating new go.mod: module github.com/rumyantseva/hello
      
      





For the go mod init



command, I specified a unique module module path for my project. If necessary, a proxy or other tool will be able to find my project files along this path.







After calling the go mod init



command, the go mod init



directory appeared in my home directory:







 $ tree ~/go /home/elena/go └── pkg └── mod └── cache └── lock 3 directories, 1 file
      
      





In this case, the lock-file (at the very bottom of the tree) is still empty.







The go.mod



file appeared in the ~/hello



go.mod



with the following contents:







 module github.com/rumyantseva/hello go 1.13
      
      





It is in go.mod



that all information about the dependencies of my module will subsequently be stored.







Let's now write an application using an external dependency. In the ~/hello



directory, I create the main.go



file and write the following code into it:







 package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, world!") }
      
      





Of course in real life for writing "Hello, world!" logrus can be dispensed with, but in this example, this library will help us find out where external dependency files are stored.







I launch the application in the simplest way:







 $ go run main.go go: finding github.com/sirupsen/logrus v1.4.2 go: downloading github.com/sirupsen/logrus v1.4.2 go: extracting github.com/sirupsen/logrus v1.4.2 go: downloading golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: extracting golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: finding golang.org/x/sys v0.0.0-20190422165155-953cdadca894 INFO[0000] Hello, world!
      
      





Before the application was built and launched, the go mod



tool worked. He defined my external dependency github.com/sirupsen/logrus



, took its latest version v1.4.2



at the moment and went for transitive dependencies.







A line with a description of the dependence on logrus



added to the logrus



:







 module github.com/rumyantseva/hello go 1.13 require github.com/sirupsen/logrus v1.4.2 // indirect
      
      





The go.sum



file also appeared, which in addition to the logrus



dependency logrus



contains information about the hashes of transitive dependencies:







 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
      
      





Where is the dependency code itself? It can be found in ~/go/pkg/mod



. Also, checksums and other overhead information for working with dependencies will be stored in ~/go/pkg



.







If you've already come across the go get



tool, you know that when pulling dependencies, it actually clones the repositories (for example, in the case of git with git clone



). But go mod



doesn't work that way. For go mod



main unit of code is the module. Modules are archives. When working with go mod



dependencies, it explicitly (if you invoked the go mod download



command) or implicitly (if you started compiling the application) downloads and unpacks archives via GOPROXY



. Let's see how the proxy is set in Go 1.13 by default:







 $ go env GOPROXY https://proxy.golang.org,direct
      
      





So, as a proxy when building my "Hello, World!" used by proxy.golang.org . Of course, this variable can be changed by choosing a different repository of modules. For example, you can deploy your own internal proxy company, which will be stored, including internal libraries, the code of which was not published in open source.







In general, if I am starting a new project and do not mind using Go Modules, I may not know anything about GOPATH



. Go will create the ~/go



directory on its own when it is needed.







When is GOPATH needed?



If you basically do not use Go Modules (for example, in a legacy project), getting away from more explicit work with GOPATH



may not be so simple.







To see what will happen to my project, if I decide not to use go mod



, delete the files ~/hello/go.mod



and ~/hello/go.sum



. I will also remove ~/go



to return to the state of the system that I had at the very beginning:







 rm -rf ~/go ~/hello/go.mod ~/hello/go.sum
      
      





Only the main.go



file remains in the ~/hello



main.go



. What happens now if I try to run it with go run



?







 $ go run main.go main.go:4:2: cannot find package "github.com/sirupsen/logrus" in any of: /usr/lib/go-1.13/src/github.com/sirupsen/logrus (from $GOROOT) /home/elena/go/src/github.com/sirupsen/logrus (from $GOPATH)
      
      





Here they are, these scary GOROOT



and GOPATH



:)







In order to compile the application, I need to pull up the dependency in GOPATH



. I do this with the good old go get



:







 $ go get -v github.com/sirupsen/logrus github.com/sirupsen/logrus (download) created GOPATH=/home/elena/go; see 'go help gopath' get "golang.org/x/sys/unix": found meta tag get.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at //golang.org/x/sys/unix?go-get=1 get "golang.org/x/sys/unix": verifying non-authoritative meta tag golang.org/x/sys (download) golang.org/x/sys/unix github.com/sirupsen/logrus
      
      





What happened First of all, go get



created the ~/go



directory (the one specified as GOPATH



). Then the process of cloning the repositories with dependencies began. It's funny that cloning repositories looks noticeably slower than the option when we used go mod



to download and unpack modules. However, the dependency code can now be found inside ~/go/src/



.







By the way, there was still no git client on my clean Ubuntu installation, and in order for go get



work, I had to install it.







I launch the application:







 $ go run main.go INFO[0000] Hello, world!
      
      





Works!







That's just at the application level, I now do not track the version of external dependencies. What if, due to a vulnerability, at some point in the github.com/sirupsen/logrus



repository is not the logger I expected, but some malicious code? Sooner or later, I still need a tool for working with dependencies, and if Go Modules for some reason does not fit, you have to look for something else ...







Conclusion



This article did not address some specific points, and working with external dependencies in Go can still cause a lot of questions. However, new versions of Go at least do not impose restrictions on where the working directories of your projects can be created.







If you are starting a new project, try Go Modules! Reverting to the old approach to working with dependencies makes sense only if something goes wrong. By the way, if you prefer to store all the dependencies inside the project, Go Modules supports vendor mode.







If you need to work with an existing project, and for some reason you do not want to translate it into Go Modules, it is important to indicate the features of its deployment and dependency management in the project documentation. If newcomers unfamiliar with the old approaches to working with dependencies come to the project, it will be much easier for them to deal with the project if all the documentation is in place.







By the way, on October 7th at the GolangConf conference, as one of the special activities, we are planning an expert zone where anyone can ask any questions about Go to members of the conference program committee and enthusiasts of the Russian Go-community. Install Go? Deal with addictions? Write a microservice? This is for us!








All Articles