Setting Compile-time Strings in Go

Jun 11 2014

It is handy to have a program be able to tell you its own version number. But it's a pain to maintain version strings manually. So why not let Go do it for you? It turns out to be pretty easy to do. When reading the code for Drone.io I ran across this cool trick for setting string values at compile time.

Here's a basic Go program that prints the version string and exits:

package main

import "fmt"

var version string

func main() {
    fmt.Printf("Version: %s\n", version)
}

Unsurprisingly, if we run this program, we get the following output:

$ go run showversion.go
Version:

Ideally, version info should be set at build time, when we know exactly what the version number should be. Go provides a way to do this in the form of the -X flag to the linker. This flag allows you to set a string variable to a specific value during the linking stage. But we don't usually invoke the linker directly when working with Go. So to pass the linker any options, we have to use the -ldflags flag on go build.

Say we want to override version in our main package above. We can do that with go build like this:

$ go build -ldflags "-x main.version 1.0.0" showversion.go

The above tells the linker to set the main.version variable to 1.0.0. Now if we run the resulting show version program, we get the following output:

$ ./showversion
Version: 1.0.0

We could get even fancier and have Git generate the version number for us, based on the tag and the SHA:

$ git tag 1.0.1
$ go build -ldflags "-x main.version $(git describe --tags)" showversion.go
$ ./showversion
Version: 1.0.1

And check out what happens when we make the next commit:

$ git commit -am "One more change after the tags"
$ go build -ldflags "-x main.version $(git describe --tags)" showversion.go
Version: 1.0.1-1-g7e60d6f

This is a great way to let tools do the maintenance work.