kota's memex

Easiest way to check if a program is statically compiled:
file hello_world

TLDR: If you're not using cgo, just:

CGO_ENABLED=0 go build

In general, cgo makes static linking a bit more challenging. There's a few ways to work around these issues:

avoidance

There are two packages in the standard library that use cgo:

os/user contains cgo code to use the standard C library to map user and group ids to user and group names. There is also a Go implementation which parses /etc/passwd and /etc/group. The advantage of using the C library is that it can also get user information from LDAP or NIS. If you don’t use that – most people don’t – then there is no real difference.

net can use the C standard library to resolve domain names, but by default it uses the Go client. The C library has a few more features (e.g. you can configure getaddrinfo() with /etc/gai.conf) and some platforms don’t have a resolv.conf (e.g. Android), but for most cases the Go library should work well.

Your binary will not be statically linked if your program imports one of those two packages, either directly through a dependency. Especially the net one is quite common.

You can use the osusergo and netgo build tags to skip building the cgo parts:

$ go build -tags osusergo
$ go build -tags netgo
$ go build -tags osusergo,netgo

For simple cases where you don’t use any other cgo code it’s probably easier to just disable cgo, since the cgo code is protected with +build cgo:

CGO_ENABLED=0 go build

passing options to the c linker

What if we want to use the cgo versions of the above? Or what if we want to use a cgo package such as SQLite? In those cases you can tell the C linker to statically link with -extldflags:

go build -ldflags="-extldflags=-static"