Setting up a Go Development Environment

I quite like Go, but some things about its standard practices are downright weird if you are coming from a more standard, project-centric approach to hackery. I don’t always (okay, usually) follow these standard practices personally, but anyone coming to Go should probably understand them and work with them, so that things in the wider community make sense. Everything I say here is my understanding of practices, and is probably wrong, so correct me if I am, for the sake of anyone else finding this article!

Workspace

The first thing to grok is the idea of workspaces. I don’t know if this is any kind of commonly accepted term, but I have seen it used in #go-nuts and elsewhere, so I use it as well. A workspace is a space which holds projects, yours and anything you depend on (and usually a spattering of random things you experimented with and forgot about). You want to check out your project into your workspace, at the correct path.

We’ll make our hypothetical workspace at ~/src/gospace.

$ mkdir -p ~/src/gospace
$ export GOPATH=~/src/gospace
$ export PATH=~/src/gospace/bin:$PATH
$ cd ~/src/gospace

Within this workspace we have three root directories, src which hold source code, pkg which holds compiled bits, and bin which holds executables.

We set the GOPATH to point at your workspace, and add the bin/ for the workspace to our PATH. You can have multiple paths in your GOPATH if you want to, and I know of folks who do, but I haven’t figured out how it makes life easier yet, so I don’t.

(update: Charles Hooper pointed out src/, pkg/, and bin/ subdirectories in the workspace will be created automatically when they are needed.)

Your Project

Let’s say you want to work on a project called variant, and you will host the source code on Github at github.com/brianm/variant. You will need to check this out to ~/src/gospace/src/github.com/brianm/variant. This is awkward, so we’ll just check it out via go get and fix it up:

$ cd ~/src/gospace
$ go get github.com/brianm/variant
$ cd src/github.com/brianm/variant
$ git checkout master

This works if your project already exists, if it doesn’t, you’ll need to go make the directories and set up the project basics, something like:

$ cd ~/src/gospace
$ mkdir -p src/github.com/brianm/variant
$ cd src/github.com/brianm/variant
$ touch README.md
$ git init
$ git remote add origin https://github.com/brianm/variant.git
$ git push -u origin master

Assuming the github repo is waiting for you. This isn’t a git/github tutorial though :-)

Your project’s place in the workspace is intimately tied to the source repo for it as Go’s dependency resolution mechanism relies on import paths matching up with source repos. It is kind of weird, and has some drawbacks, but is also really convenient (when you don’t hit those drawbacks).

Working on Your Project

For the package you are hacking on, cd into the dir of the package, hack, run go test or go build or go install as you want. Both default to the “current dir” which does a reasonable job of figuring things out (as long as you don’t have symlinks involved, Go hates symlinks for some reason).

Dependencies

If you want to fetch something else, go get it. If you want to use the MyMySql driver/library you can go get github.com/ziutek/mymysql and it will fetch and build it for you (and its dependencies). The source will be at ~/src/gospace/src/github.com/ziutek/mymysql, just like your project sources. It will be a git clone of repo. If you want a specific version (say the v1.4.5 tag), cd over to it and git checkout v1.4.5.

If you want to install a utility written in Go, go get it as well. For example, to install dotCloud’s Docker you can go get github.com/dotcloud/docker/docker. The target for the go get is the package name (that would be imported) for the main package of what you want. It will fetch it, build it, and put the binary in ~/src/gospace/bin for you. (update: Jeff Hodges noted go get will install things as happily as go install, so I simplified this and just used go get instead of the earlier described go install.)

Conclusions

Working on stuff in Go like this is fairly painless while you are working in it but gets kind of painful when you want to do some things that are otherwise totally rational – like have repeatable builds (when you have dependencies) based on a tag in your project, or being able to just check out a project and build it without setting up a bunch of magical directories you just have to know about.

To be honest, these things, and a couple other odd caveats, deserve a post on their own, so with that, we’ll adjourn until then.

Please Correct Me!

If you have a better setup, or I thoroughly misunderstand something, please comment. I am still trying to figure out the best ways of doing things, and am very confident that I don’t have anything optimal yet.