-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CGO 交叉静态编译 #27
Comments
感谢指正 |
我想问一下,如果我想在windows下交叉编译cgo到linux上,我该怎么安装或者寻找对应的linux上需要的gcc和g++编译器呢,我甚至都不知道搜索关键词该怎么查找。。。。 |
@yingyi666 你需要的应该是运行在 windows 系统下能编译到 linux 的 gcc 和 g++ ,这个你可能在这里能找到 https://musl.cc/ ,具体是哪一个我也不确定,也可能没有,不过如果你换个方式,在 linux 下能交叉编译到其他平台的 gcc 应该还是很好找的 |
感谢,我目前的代替方案是使用docker自行构建一个开启了cgo的镜像,然后创建容器编译 |
如果CGO程序中需要dlopen依赖库,是不是没法静态编译。我尝试在mac上交叉编译包含CGO的代码到linux平台的时候,使用musl-cross虽然能编译成功,但是在linux上执行的时候,会报错undefined symbol |
目前cgo是无法静态编译的,除非你可以配置好对应平台的工具链,然后在编译的期间指定工具链 |
在新的项目中,由于必须要使用sqlite数据库,所以引入了
go-sqlite3
库,而且目标还是安卓开发板,板子是aarch64
架构,也就是说,目的是要把启用了CGO的项目交叉编译到 aarch64 安卓系统。本篇文章不局限于 aarch64 架构,其他架构同理,只是到时候下载的工具包不太一样
名词解释:
无CGO项目的交叉静态编译
在不启用CGO的情况下,交叉编译是非常简单的,因为 golang 本身的交叉编译做的非常好
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags '-s -w --extldflags "-static -fpic"' main.go
CGO_ENABLED=0
这个值默认是1,也就是开启的,需要手动指定为关闭,因为CGO是不支持交叉编译的,使用go env CGO_ENABLED
查看默认值GOOS=linux
是因为安卓底层就是linux,aarch64 架构直接使用 arm64,如果GOARCH=arm
,则要使用GOARM=7
,指定arm版本可选5,6,7,在这里看完整支持列表-ldflags
编译选项,-s -w
去掉调试信息,可以减小构建后文件体积,--extldflags "-static -fpic"
完全静态编译,要交叉编译放到其他系统和架构中运行,静态编译是最好的,不然启动的时候会提示找不到依赖的so文件这样编译生成的文件就可以任意放到指定平台下运行不会有问题。如果没有CGO,一切都很完美。
CGO 项目的交叉静态编译
记录一下在 CGO 交叉编译过程
交叉编译
刚开始,静态编译是不敢想的了,也只有交叉编译可以试一试,安装两个包,如果是其他架构和系统,安装其他对应的包就行了,本文章都以 aarch64 的 linux 为例子
安装好以后,指定gcc和g++编译器为上面两个
命令解释
CGO_ENABLED=1
开启CGO,因为项目用到了C语言的代码CC=aarch64-linux-gnu-gcc
指定gcc的编译器为aarch64-linux-gnu-gcc
,这个默认值是gcc,也就是当前操作系统和架构使用的gcc,使用命令$(go env CC) --target-help
可以看看默认gcc支持什么平台CXX=aarch64-linux-gnu-g++
指定g++的编译器为aarch64-linux-gnu-g++
,规则和CC
一样,只是用来编C++代码的,如果还用到了C++代码,必须指定该项-ldflags '-s -w'
go编译选项,-s -w
去掉调试信息,可以减小构建后文件体积这样编出来是成功的,整个过程应该会很顺畅,但是把文件放到对应的平台运行,如果运气好,那肯定是运行起来了。如果运气一般会发现提示
这时候可以用 ldd 看一下
会发现依赖的so文件好像都有,可以去依赖目录
/system/lib
(这是安卓的)看看 ,但是运行的时候就是不成功,这里原因我不是太确定。我猜测是这样的,编译器依赖的这些 so 其实是编译器带的那些so,并不是系统的那些,所以在执行的时候这些依赖虽然有,但是并不是执行文件需要的。这时候,把编译器下面的这几个依赖复制出来,然后执行放到和执行文件同一个目录,这样去执行,应该是可以成功执行的
这样子手动的执行依赖库,就能成功的启动起来了,如果还不行的话,继续往下看吧,下面有把所有so静态编译进去的方法。
静态编译
回看刚刚交叉编译时候的命令,我们是不是在
-ldflags
那里漏掉了刚开始的那个--extldflags "-static -fpic"
,现在把它加上去好吧,报错了。
我不太懂C语言,但是根据错误信息能得知,有些库文件是不能被静态链接的,gcc 编译器不支持。也就是说
cpp-aarch64-linux-gnu
这个编译器不支持静态编译。MUSL GCC
事实上这卡住了我很长一段时间,直到后面在玩 RUST 的时候发现了个好东西,就是支持gcc静态编译的 musl gcc,才终于解决 CGO 静态编译
先下载 musl 对应的平台的编译器,进入 这里 能发现 musl 其实只能在 x86_64 架构下的 linux 系统才能运行,也就是说只能在 linux 系统下去交叉编译其他平台的执行文件(也不知道我说的对不对)
下载 aarch64 linux 的编译器: https://musl.cc/aarch64-linux-musl-cross.tgz
解压,然后把解压好的目录下 bin 文件路径放到
PATH
环境变量中,再把编译器换成这个没有报错,成功编译了,不用做什么其他操作,把可执行文件放到对应平台上运行,正常。
完成了,折腾到此结束
The text was updated successfully, but these errors were encountered: