Mac x86交叉编译带cgo的Go项目到M1出现arm64未定义符号错误
交叉编译M1平台Go应用报错问题排查与解决
问题根因
- 编译参数携带
-race:报错中所有未定义的__tsan_*符号均来自线程 sanitizer(race检测器)依赖库,Go 1.16版本未支持darwin/arm64架构的race检测能力,且当前使用的x86架构clang默认未携带arm64版本的tsan库,链接阶段无法找到对应符号。 - Go版本过低:Go 1.16是首个初步支持Apple Silicon架构的版本,对CGO混合编译、跨架构交叉编译的支持存在大量缺陷,不符合当前混合C/Objective-C代码的编译需求。
- CGO交叉编译未指定目标架构:当前clang默认目标架构为x86_64-apple-darwin,开启CGO时编译出的C/Objective-C目标文件为x86架构,无法与arm64架构的Go代码链接。
- Go环境配置冲突:命令行指定
GOARCH=arm64,但全局go env中配置的GOARCH=amd64、GOROOT指向x86架构的Go安装包,编译阶段存在配置冲突。
解决步骤
- 若无需在arm64版本中开启线程检测,直接移除
-race编译参数,同时指定clang的目标架构执行编译即可,编译命令参考:
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 CC="clang -target arm64-apple-darwin20.6.0" CXX="clang++ -target arm64-apple-darwin20.6.0" /usr/bin/go build -o "~/Example/project/obj/mac-arm64/dummy" -gcflags "-N -l" -ldflags "-w" dummy
- 若必须开启arm64版本的race检测,需完成两个升级操作:
- 升级Go版本至1.19及以上,该版本起正式支持darwin/arm64架构的race检测能力
- 升级Xcode命令行工具至13.4及以上,确保clang工具链携带arm64架构的tsan依赖库
- 验证编译能力时可先执行纯Go代码的编译测试,将
CGO_ENABLED=0后执行编译,排除Go本身交叉编译链路的问题后,再逐步恢复CGO配置。 - 若需要同时兼容x86与M1平台,可分别编译两个架构的产物后用lipo合并为通用二进制,操作参考:
# 编译x86_64版本 CGO_ENABLED=1 GOARCH=amd64 go build -o dummy-amd64 dummy # 编译arm64版本 CGO_ENABLED=1 GOARCH=arm64 CC="clang -target arm64-apple-darwin20.6.0" CXX="clang++ -target arm64-apple-darwin20.6.0" go build -o dummy-arm64 dummy # 合并为通用二进制 lipo -create -output dummy dummy-amd64 dummy-arm64
内容的提问来源于stack exchange,提问作者Gaurav Joshi
相关产品推荐
相关产品推荐

