Static Compilation with Golang
Building monolithic executables
Watch the video for this article here.
Golang already does a good job of statically compiling almost everything, but depending on your code you may need a few extra flags to make sure your executable is completely free of dependencies.
The first step is to build your project and then inspect the binary to see whether it has any dependencies.
On macOS, use the otool utility (object file displaying tool) with the -L flag (which lists the shared libraries in use), like this:
otool -L binaryname
On Linux, the equivalent command is ldd:
ldd binaryname
The file command can also give you hints about which shared libraries are being used.
CGO_ENABLED=0
If your binary shows no dependencies, there is nothing to do. In some cases, though, you need to disable cgo, which is done by setting the CGO_ENABLED=0 environment variable.
CGO_ENABLED=0 go build
In older versions of Go, you had to add the -tags netgo flag if you needed net support. That flag doesn’t cause errors, but it is no longer necessary.
If you are using external libraries, you will need to pass a few flags to the linker via -ldflags, like this:
CGO_ENABLED=0 go build -ldflags '-extldflags "-static"'
And if you want to be sure everything was really rebuilt, you can add the -a flag, which forces all packages to be recompiled even if they are already up to date.
Bonus
Since we’re talking about build flags, we can add two more linker flags that help shrink the final executable: -ldflags "-s -w".
The -s flag strips debug information from the executable, and -w prevents the generation of DWARF (Debugging With Attributed Record Formats). Of course, without them you can’t debug the binary, so this may not always be worth it.
To see these and other linker flags, run:
go tool link --help
The final command looks like this:
CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static" -s -w'