Cross compile with CGO and GoReleaser
How to overcome errors using CGO and GoReleaser by using Docker
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-distA clean distribution directory is required this ensures it is removed.
snapshotBy 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.
rmStarts with a fresh docker container each time.
-v ($pwd):/go/src/github.com/:org/:repoCreates 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
Note: remember to replace
: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 /firstname.lastname@example.org/crypto/secp256k1 # github.com/ethereum/go-ethereum/rpc /email@example.com/rpc/endpoints.go:96:19: undefined: ipcListen /firstname.lastname@example.org/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,
email@example.com/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.
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
If you want to find out more about what we are building at Mailchain find us at https://github.com/mailchain/mailchain