编译 mattn/go-sqlite3 久病成医,把踩过的坑都写一轮,先从 Linux 说起
Linux
glibc
我自己常用的大多数 Linux 发行版都是自带 glibc 的(Debian/Ubuntu...),默认使用动态链接,这玩意不论是官方还是民间讨论都不建议做静态编译,即使是动态编译,也是清一色的建议用古董版本的 Linux 发行版来干
要找合适的版本可以参考 pypa/manylinux,这仓库列出了用于 python 库构建的版本的建议,鉴于 python 有一堆 C/C++ 的库,拿来给 cgo 参考也是足够的
当然啦,硬要上静态编译也是可以的
GOOS=linux GOARCH=arm64 CGO_LDFLAGS="-static" CGO_ENABLED=1 \
go build -ldflags "-linkmode external -extldflags -static" -tags "netgo sqlite_omit_load_extension osusergo"
Linux 编译带上 osusergo 会导致在 termux 运行跳 Bad System Call,应该不会有人无聊到编译一个 cli 程序到 Android 设备上用 termux 跑的……对吧?
musl
给嵌入式设备用的,还有那个经典的 docker 镜像底包 Alpine Linux 用的也是 musl,最大的优势就是静态编译友好,一处编译,随处可用,不用头疼找旧系统来编译
虽然有人会说要踩 DNS 的坑,但跟我 netgo 有什么关系呢~
# apt install -y musl-dev
CC=musl-gcc CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static" -tags netgo
属于是 go-sqlite3 给部分系统推荐的 CC
MacOS
由于在非 Mac 平台编译需要用到自己准备的 SDK(包括后文的 zig),这玩意只能自己在 MacOS 提取或者在网上找别人分享出来的,凑齐了以后就可以自行编译了,不过我纠结了半天最后决定用 Actions 的 MacOS runner 来解决
尽管官网还没更新,从 go1.25.0 开始最低只能运行在 MacOS 12 Monterey,直接编译打包会导致 minos 被设置成 12,不过手动设置 -mmacosx-version-min=11.0 就可以改回去了
# arm
CGO_CFLAGS="-mmacosx-version-min=11.0 -arch arm64" CGO_LDFLAGS="-mmacosx-version-min=11.0 -arch arm64" GOOS=darwin GOARCH=arm64 go build -tags netgo
# x86_64
CGO_CFLAGS="-mmacosx-version-min=11.0 -arch x86_64" CGO_LDFLAGS="-mmacosx-version-min=11.0 -arch x86_64" GOOS=darwin GOARCH=amd64 go build -tags netgo
如果不用 cgo 怎么办,那不靠奇技淫巧就只能到 12 了
Windows
Windows 的兼容性不用担心,最近十年来也就只有 10 和 11 两代(以及基于它们的的各种分支版本),直接编译就好了
选择 MinGW-w64 和 MSVC 最后运行起来都差不多
# dumpbin /DEPENDENTS filename.exe | findstr ".dll"
# MinGW-w64
KERNEL32.dll
msvcrt.dll
# MSVC
KERNEL32.dll
api-ms-win-crt-environment-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-private-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
跨平台
zig
zig targets 找到合适的 CC,选完再编译# https://ziglang.org/download/
CC="zig cc -target x86_64-linux-musl" GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static" -tags netgo
CC="zig cc -target x86_64-windows-gnu -O2" GOOS=windows GOARCH=amd64 CGO_ENABLED=1 go build -tags netgo -ldflags "-linkmode external"
xgo
坏处就是依赖 docker,镜像超级大,调用 Github Actions 编译时 workflow 大量时间都花在下载,而且体积过大还导致 Cache 并不能保存,每次启动都要 pull 这个巨大的镜像
# go install src.techknowlogick.com/xgo@v1.8.1-0.20250401170454-4b368d8a5afa
# docker pull ghcr.io/techknowlogick/xgo:go-1.25.6
CGO_ENABLED=1 $HOME/go/bin/xgo -go go-1.25.6 -tags netgo --targets=windows/amd64,darwin/amd64,darwin/arm64 ./
cgo-free
太麻烦了,有没有不用 cgo 的办法,有的还真有,比如 gitlab:cznic/sqlite
由于是用纯 Go 来翻译 C 库,所以支持的系统范围就有限了