背景
使用 MacBook 作为开发环境,需要用 Golang 之类的编译型开发语言时,就避免不了交叉编译。因为阿里云、AWS 等云服务器都是使用的 Linux 操作系统,而且是 x86 架构的 CPU。
之前也分享过在 VSCode 中配置 Golang 交叉编译环境的文章,有兴趣的朋友可以翻看一下 《VSCode利用tasks.json实现交叉编译》。
但是这次写好代码,要编译 Linux amd64 版本上传到生产环境的云服务器时就出现了诡异的问题,报了一大堆的异常信息。要知道,写这个代码的过程中是经过了多次本地调试的,代码运行一直都没问题的。这次编译跟代码调试时也就是交叉编译的区别,但本地交叉编译的配置已经编译过好几个项目了,唯独这次出问题了。
编译异常问题分析
先看看异常信息:
# github.com/chai2010/webp
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:22:9: undefined: webpGetInfo
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:26:20: undefined: webpDecodeGray
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:39:20: undefined: webpDecodeRGB
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:52:20: undefined: webpDecodeRGBA
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:68:14: undefined: webpDecodeGrayToSize
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:82:14: undefined: webpDecodeRGBToSize
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:96:14: undefined: webpDecodeRGBAToSize
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:109:7: undefined: toGrayImage
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:110:14: undefined: webpEncodeGray
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:119:14: undefined: webpEncodeRGB
../../../go/pkg/mod/github.com/chai2010/webp@v1.4.0/webp.go:119:14: too many errors
* The terminal process "/usr/local/go/bin/go 'build', '-o', '/Users/user/makemoney/bin/makemoney_linux'" failed to launch (exit code: 1).
* Terminal will be reused by tasks, press any key to close it.
编译器很无奈地提示:too many errors,根据这些异常信息可以得知,主要是使用的 webp 的库引发的问题。就查了一下,发现这个 webp 库使用了C语言的库 libwebp,这就要用到C语言编译器。但我是配置好了 gcc 环境的。只能求助于AI了。
解决方案
经过 ChatGPT、Gork、DeepSeek、Gemini 几个 AI 平台一通折腾,顺利浪费了大半天时间,但好歹知道是需要跨平台的C语言编译器:macos-cross-toolchains。
但根据AI提示的命令,始终安装不成功,总会因为网络问题卡在一个包的下载上面。于是就在一堆命令异常信息里面抠出下载失败的包的链接,然后到 GitHub 上找到这个代码仓库,对着这个包名下载下来。
为了节省大家的时间,在这里直接放出 GitHub 地址及包名,以及我对应的环境:
- GitHub: https://github.com/messense/homebrew-macos-cross-toolchains/
- Package: v13.3.0/x86_64-unknown-linux-gnu-aarch64-darwin.tar.gz
- 编译环境:MacBook M芯片 arm64
它这个包的命名规则是:编译后的二进制文件要运行的 CPU 架构(x86_64) - 操作系统类型(unknown-linux-gnu) - 当前执行编译的环境(aarch64-darwin)。例如:我现在要在 MacBook 上运行这个编译器,就是 aarch64-darwin,要把代码编译成64位x86上的 linux 程序,就是 x86_64-unknown-linux-gnu。
把 x86_64-unknown-linux-gnu-aarch64-darwin.tar.gz 下载下来解压,随便放一个目录下面,然后把这个目录放到环境变量中,例如我是把解压的包放到 /usr/local/cross下面:
# 解压 x86_64-unknown-linux-gnu-aarch64-darwin.tar.gz
tar -xf x86_64-unknown-linux-gnu-aarch64-darwin.tar.gz
# 创建目标目录,这个路径随你喜欢
sudo mkdir -p /usr/local/cross
# 把解压后的目录移动到刚刚创建的目录
sudo mv x86_64-unknown-linux-gnu /usr/local/cross
# 设置环境变量并激活
echo 'export PATH="/usr/local/cross/x86_64-unknown-linux-gnu/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
这个时候在终端输入命令 x86_64-unknown-linux-gnu-gcc 测试一下,如果出现以下提示就说明配置成功了:
x86_64-unknown-linux-gnu-gcc: fatal error: no input files
compilation terminated.
VSCode tasks.json 配置 CGO 交叉编译
然后就可以回到 VSCode 中,配置 tasks.json,CGO 是需要额外加入配置的,主要是告诉 Golang 编译器启用 CGO 编译以及指定 CGO 的编译器。
CGO_ENABLED=1
CC=x86_64-unknown-linux-gnu-gcc
完整的 CGO 交叉编译 tasks.json 配置如下:
{
"version": "2.0.0",
"tasks": [
{
"type": "go",
"label": "makemoney_linux",
"command": "build",
"args": [
"-o",
"${workspaceFolder}/bin/makemoney_linux",
],
"options": {
"env": {
"GOOS": "linux",
"GOARCH": "amd64",
"CGO_ENABLED":1, // 加入这句
"CC": "x86_64-unknown-linux-gnu-gcc" // 指定 CGO 编译器
},
"cwd": "${workspaceFolder}/src"
},
"problemMatcher": [
"$go"
],
"group": "build",
"detail": "build linux amd64 version"
}
]
}
注意事项
需要注意的是,配置好 CGO 交叉编译的环境后,需要重启一下 VSCode,要彻底退出那种,否则有可能会因为 VSCode 中的终端环境变量没刷新导致编译失败。