Golang: Modules and Build Tools

Isshiki🐈
2 min readJan 16, 2021

--

Based on this Stack Overflow answer

Before the introduction of Go modules, the file structure of local Go projects were like

// an executable
$GOPATH/github.com/you/project1
-> $GOPATH/github.com/you/project1/package_main
-> $GOPATH/github.com/you/project1/package1
-> $GOPATH/github.com/user_a/project1/package2 // imports project3
-> $GOPATH/github.com/user_a/project1/package3
// an executable
$GOPATH/github.com/user_b/project2
-> $GOPATH/github.com/user_b/project2/main_package
-> $GOPATH/github.com/user_b/project2/package_a
-> $GOPATH/github.com/user_b/project2/package_b
// a library
$GOPATH/github.com/user_c/project3
-> $GOPATH/github.com/user_b/project2/package_a
-> $GOPATH/github.com/user_b/project2/package_b

While it’s simple, it’s also cumbersome and error-prone.

After the introduction of Go modules, project management gets more convenient but also more complicated. The old way still works, of course, but is no longer recommended, and you can now place your project anywhere you like, like $HOME/projects/my_go_project and initialize your project as go mod init github.com/you/my_go_project. However, it’s where things can get complicated, and as you will see shortly, github.com/you/my_go_project is now more like a name and has nothing to do with the actual path to where the code lives. Let’s say you currently have three projects as listed below:

$GOPATH/github.com/user_b/project2
-> $GOPATH/github.com/user_b/project2/main_package
-> $GOPATH/github.com/user_b/project2/package_a
-> $GOPATH/github.com/user_b/project2/package_b
// a library
$GOPATH/github.com/user_c/project3
-> $GOPATH/github.com/user_b/project2/package_a
-> $GOPATH/github.com/user_b/project2/package_b
...$HOME/somewhere_you_like/project
-> $HOME/somewhere_you_like/project/main_package
-> $HOME/somewhere_you_like/project/package_a
-> $HOME/somewhere_you_like/project/package_b

How do you import package_a now? Definitely not like import $HOME/somewhere_you_like/project/package_a, right? It will break if someone else downloads and wants to compile your code. Actually, according to the How to Write Go Code tutorial, you should still write imports like import github.com/you/project/package_n and go’s build tools will handle the rest for you, and that’s also why I said github.com/you/project is more of a name than its actual path.

To sum up, if you run go get, the downloaded files will go to $GOPATH; if you run go build from a non-main package, you will get nothing (the result will be cached somewhere though), and if you run go build from the main package, you will get a binary alongside existing files; if you run go install from a non-main package, you will get a binary file installed under the $GOPATH/pkg directory and if you run go install from the main package, you will get an executable file under $GOPATH/bin.

Read Go’s offcial blog for more information on this topic.

--

--