published on in blog
tags: neuling go build

Gobuild 1

So we’re not holding any punches. Rather we’re going to dive right into the go tooling and look at go build. I will caveat, however, that go build is quite a beefy tool. Just get to a command line and run go build –help. Yowza! But don’t be intimidated! We’ll look at all of the options, but not all at once. We’ll chunk this command up into two parts to make them more digestible. This is the first part, and should cover most of your goings with go build

Hello World

To demonstrate the build tool it would be nice to build something… The beginning seems like a good place to start: If you read my Hello World post, you might recall that Hello World (aka Hellow) is an excellent place to begin. The ‘official’ go Hellow, as found in The Go Programming Language:

// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
 
// See page 1.

// Helloworld is our first Go program.

package main

import "fmt"
 
func main() {
    fmt.Println("Hello, 世界")
}

So spin up your favorite editor, hammer in hellow, save it in a folder as main.go, and pull up a command prompt. Oh, and make sure you are working under your GOPATH/src directory. See my previous post or the official go doc for guidance. And trust me, don’t try to fight the GOPATH. I know it might feel constraining, but I’ve found the constraints to be …liberating. So just roll with it for a while, you might actually like it.

Just Build

If all you want is an executable or a library, just call go build. If your program is valid, build will spit it out. The executable will be named after the folder where your code resides. This is a reflection of go’s packaging expectations. Now let’s explore some build flags!

-v

The -v flag is the old standby for verbose. Every command line tool should have a -v flag! It just provides more information about the tool’s machinations. For go build it prints out the names of the packages being built. For our Hellow example, the output should be something like this:

$ go build -v
hellow

-a

The -a flag forces rebuilding all packages, even those that are already up to date. I’m not really sure about it’s usefulness. Maybe as a sanity check (did my updates REALLY get built???), total build time check, or maybe for a complete list of dependencies? I don’t know, do you have a compelling use case?
Regardless, we can see it’s effect when teamed up with -v

$ go build -v -a
runtime/internal/sys
runtime/internal/atomic
runtime
errors
internal/race
sync/atomic
internal/cpu
unicode/utf8
unicode
sync
math
io
syscall
strconv
reflect
time
internal/poll
os
fmt
hellow

As you can see, there are actually quite a few packages going into our simpy Hellow.

-n

The -n flag let’s you look before you leap: It prints commands but doesn’t execute them. It also gives a peak behind the curtain like -x.

$ go build -n

#
# hellow
#

mkdir -p $WORK/hellow/_obj/
mkdir -p $WORK/hellow/_obj/exe/
cd /home/harpercn/devel/go/src/hellow
/opt/go/pkg/tool/linux_amd64/compile -o $WORK/hellow.a -trimpath $WORK
-goversion go1.9.2 -p main -complete -buildid
ab46bfc350c11aa466e13db3f7a61b3bed81fce0 -D _/home/harpercn/devel/go/src/hellow
-I $WORK -pack ./main.go
cd .
/opt/go/pkg/tool/linux_amd64/link -o $WORK/hellow/_obj/exe/a.out -L $WORK
-extld=gcc -buildmode=exe -buildid=ab46bfc350c11aa466e13db3f7a61b3bed81fce0
$WORK/hellow.a
mv $WORK/hellow/_obj/exe/a.out hellow

I’m sorry if exposing the inner workings ruin some of the build tool magic. We can see the go build recipe now.

  • Make a temp directory.
  • Change to the project folder.
  • Call the compiler. (compile)
  • Call the linker. (link)
  • Move the executable from the temp directory to the project folder

If you are following along at home, your output may vary (especially if you have a different OS), but the gist will be the same.

-x

The -x flag is similar to -n: It prints the commands the build tool will run. However, unlike -n it also executes them.

$ go build -x
WORK=/tmp/go-build156488403
mkdir -p $WORK/hellow/_obj/
mkdir -p $WORK/hellow/_obj/exe/
cd /home/harpercn/devel/go/src/hellow
/opt/go/pkg/tool/linux_amd64/compile -o $WORK/hellow.a -trimpath $WORK
-goversion go1.9.2 -p main -complete -buildid
ab46bfc350c11aa466e13db3f7a61b3bed81fce0 -D _/home/harpercn/devel/go/src/hellow
-I $WORK -pack ./main.go
cd .
/opt/go/pkg/tool/linux_amd64/link -o $WORK/hellow/_obj/exe/a.out -L $WORK
-extld=gcc -buildmode=exe -buildid=ab46bfc350c11aa466e13db3f7a61b3bed81fce0
$WORK/hellow.a
mv $WORK/hellow/_obj/exe/a.out hellow

One interesting difference: The -x command shows the definition for $WORK whereas -n does not. I’m not sure if omitting $WORK from the -n flag was a design decision or just an oversight.

-p n

The -p flag tells the build process how many processi1 can be ran in parallel. It defaults to the number of CPU cores, which seems like a pretty reasonable setting. I rebuilt the hugo library with -p 1 and -p 6. The latter is an appreciably faster build.

-compiler name

Yes, that’s right! You get your choice of compiler! Sort of. There are two options gc and gccgo.

  • gc: The default go compiler written in go for go.
  • gccgo: A frontend for gcc.

The Reader’s Digest version: gc will serve you well unless you need to target a non-mainstream (read neither x86, ARM, PPC, nor MIPS) processor or you need to squeeze out every ounce of performance.

I’ve actually never used the gccgo compiler. When I invoke the command:

$ go build -compiler gccgo 
go build: when using gccgo toolchain, please pass compiler flags using
-gccgoflags, not -gcflags
cmd/go: gccgo: exec: "gccgo": executable file not found in $PATH

According to Setting up and using gccgo one might have to build gccgo or find a binary to download. I don’t have a compelling use case for gccgo so I haven’t messed with it. If you have, I’d love to hear about it!

-tags

Whew! This is the last flag we’ll talk about in this piece. But tags are important and they crop up from time to time.

In a nutshell, build tags are special comments that appear at the top of a source file. They take the form:

  // +build < <name>  
  

And these files will only be built if is specified in the build tag. Let’s try it out! Add

// +build foo

To the top of your main.go file. Now if we run a vanilla build command:

$ go build
can't load package: package hellow: build constraints exclude all Go files in
/home/harpercn/devel/go/src/hellow

Bummer! Let’s try it again with a foo build tag

go build -tags foo

This time no complaints!

Summary

This, I think, will cover the lion’s share go building. We’ll explore some of the other flags when we visit go build again!

Happy Coding,
C$


  1. Processi –> ‘cess’ should be pluralized ‘i.’ successi, abscessi, princessi, etc.
    [return]