Cross compile with CGO and GoReleaser

How to overcome errors using CGO and GoReleaser by using Docker

Rob De Feo
May 10 · 3 min read

I contribute to an open source project, Mailchain, developed in Golang. I want to easily create releases using CI/CD. Golang is a compiled language that allows for a simple way to compile your code, to execute on different operating systems. I found the fantastic tool, https://goreleaser.com/ which builds, releases, and publishes the binaries.

This is the command to build on a Mac.

  • rm-dist A clean distribution directory is required this ensures it is removed.
  • snapshot By default a release is set to publish. This flag turns off this action.

When I ran this on my Mac, it fails when building the binary for linux.

• releasing using goreleaser 0.106.0...
• loading config file file=.goreleaser.yml
... [TRUNCATED]
• BUILDING BINARIES
• building binary=dist/darwin_amd64/mailchain
• building binary=dist/linux_amd64/mailchain
⨯ release failed after 9.40s error=failed to build for linux_amd64: # os/user
/usr/local/Cellar/go/1.12.4/libexec/src/os/user/getgrouplist_unix.go:16:35: warning: passing 'gid_t *' (aka 'unsigned int *') to parameter of type 'int *' converts between pointers to integer types with different sign [-Wpointer-sign]
... [TRUNCATED]
ld: warning: option -s is obsolete and being ignored
ld: warning: ignoring file
... [TRUNCATED]
"__cgoexp_07a0021afc18_secp256k1GoPanicError", referenced from:
_secp256k1GoPanicError in 000023.o
"__cgoexp_07a0021afc18_secp256k1GoPanicIllegal", referenced from:
_secp256k1GoPanicIllegal in 000023.o
"_crosscall2", referenced from:
_secp256k1GoPanicIllegal in 000023.o
_secp256k1GoPanicError in 000023.o
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Whats going on???

The problem is that one library has a dependency on C and requires CGO. I like having GoReleaser in my tool kit, a lot! I looked deeper into the issue. It’s a case of ensuring all the right libraries are installed for CGO to compile against different operating systems. Docker seems and excellent fit, there’s even a docker container for CGO.

  • rm Starts with a fresh docker container each time.
  • -v ($pwd):/go/src/github.com/:org/:repo Creates a volume on the docker container with the contents on of the current directory.
  • -w /go/src/github.com/:org/:repoSets the working directory to the code that was created in the go/srcdirectory.

Note: remember to replace :organd :repo with your repository details.

releasing using goreleaser 0.106.0...
loading config file file=.goreleaser.
... [TRUNCATED]
building binary=dist/darwin_amd64/mailchain
⨯ release failed after 163.82s error=failed to build for darwin_amd64: go build github.com/ethereum/go-ethereum/crypto/secp256k1: build constraints exclude all Go files in /go/pkg/mod/github.com/ethereum/go-ethereum@v1.8.26/crypto/secp256k1
# github.com/ethereum/go-ethereum/rpc
/go/pkg/mod/github.com/ethereum/go-ethereum@v1.8.26/rpc/endpoints.go:96:19: undefined: ipcListen
/go/pkg/mod/github.com/ethereum/go-ethereum@v1.8.26/rpc/ipc.go:50:10: undefined: newIPCConnection

We are making progress…

But I get a different error this time that does not look related to CGO. It is though, github.com/ethereum/go-ethereum@v.1.8.26/crypto/secp256k1 is the location of the C dependency. Looks like I need is a docker container that has CGO libraries and is able to cross compile into Linux, OSX, and Windows. Enter goreleaser-xcgo, a docker container with all of the required binaries and the latest version of GoReleaser. Usage is similar to before.

Success!!! :)

This time it creates all the binaries are built.

• releasing using goreleaser 0.106.0...
... [TRUNCATED]
• BUILDING BINARIES
• building binary=dist/darwin_amd64/mailchain
• building binary=dist/linux_amd64/mailchain
• building binary=dist/windows_amd64/mailchain.exe
... [TRUNCATED]
• release succeeded after 330.99s

To see it working the configuration file .goreleaser.yml is here, to see how its integrated with travis here is the .travis.yml configuration.

If you want to find out more about what we are building at Mailchain find us at https://github.com/mailchain/mailchain

Thanks