爬虫代码已复制

MacBook 实现CGO交叉编译的解决方案

背景

使用 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 地址及包名,以及我对应的环境:

它这个包的命名规则是:编译后的二进制文件要运行的 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 中的终端环境变量没刷新导致编译失败。