MacOS上进行Go应用编译至Linux

84

引言

在 macOS 上开发 Go 应用,但需要部署到 Linux 上时,跨平台编译可能会遇到一些坑。特别是当你的应用依赖需要 CGO 的库(比如 `libpq`)时,问题会更加复杂。今天就来聊聊我踩过的坑,以及如何解决这些问题。

首次尝试

最初,我认为将 Go 应用编译为 Linux 是相当简单的,只需要将 GOOS 环境变量设置为 linux 即可:

GOOS=linux  go build -o my-app

然而,在 Linux 服务器上执行生成的二进制文件时,报了以下错误

failed to initialize database, got error Binary was compiled with 'CGO_ENABLED=0', libpq requires cgo to work. This is a stub

提示 libpq 需要 CGO 才能正常工作。

再次尝试

为了解决这个问题,我启用了 CGO 再次编译了一次:

CGO_ENABLED=1 GOOS=linux   go build -o my-app

但是又出现了编译错误:

# runtime/cgo
linux_syscall.c:67:13: error: implicit declaration of function 'setresgid' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
...

经过一番搜索,发现在 macOS 上使用 CGO 进行跨平台编译需要 musl-cross 的支持。

解决方案

在 macOS 上安装 musl-cross 可以通过以下命令完成(会有点慢,耐心等待即可):

brew install FiloSottile/musl-cross/musl-cross

安装完成后,修改编译命令

CGO_ENABLED=1 GOOS=linux  GOARCH=amd64  CC=x86_64-linux-musl-gcc  CXX=x86_64-linux-musl-g++ go build -o my-app

成功了!编译过程没有问题。

部署方案

当我尝试在 Linux 服务器上运行生成的二进制文件时,又遇到了另一个错误:

: No such file or directory

回过头来再看,我发现 Linux 服务器也需要 musl 的支持。对于基于 Debian 的系统,这可以通过以下方式实现:

apt-get install -y musl

对于基于 Red Hat 的系统:

wget https://copr.fedorainfracloud.org/coprs/ngompa/musl-libc/repo/epel-7/ngompa-musl-libc-epel-7.repo -O /etc/yum.repos.d/ngompa-musl-libc-epel-7.repo
yum install -y musl-libc-static

最终,程序终于可以正常跑起来了。

结论

带有依赖 CGO 的库(如 libpq)的 Go 应用的跨平台编译可能会出现一些问题,特别是在 macOS 和 Linux 之间切换时。然而通过使用 musl-cross 并在目标 Linux 服务器上安装好必要的库,就可以成功地构建并运行应用了。