So today I was building Go binaries on a Arch Linux machine and deploying to an Ubuntu server, and go the following error when trying to run them:
/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found
This was odd because I’ve never had any problems with Go binary portability in the past. On the Gopher slack, it was suggested:
cgo is used by default if you use net or os/user
The go binary package from golang.org produced working binaries using the same combination of machines. Another solution suggested on slack was:
just build your stuff properly
CGO_ENABLED=0 go build ...
Disabling CGO worked.
Digging a little more, before I disabled CGO, the binaries had the following dependencies:
[cbrake@mars go]$ ldd is-portal linux-vdso.so.1 (0x00007ffe5dcd6000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f082b446000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f082b27d000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f082b4bb000)
After enabling CGO, there are no dynamically linked libraries:
[cbrake@mars go]$ ldd is-portal not a dynamic executable
After asking more questions, the reasons for this differing behavior was given:
because name resolution is complex and people sometimes want compatible behaviour, see https://golang.org/pkg/net/#hdr-Name_Resolution
And then from that page:
By default the pure Go resolver is used, because a blocked DNS request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the Go resolver does not implement, and when the name being looked up ends in .local or is an mDNS name.
So the bottom line – if you want to make sure you have portable Go binaries, disable CGO.
Thanks for your help Sean Liao – I learned something today!