Setting up a Go Development Environment 24 Mar 2013
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.