最近,研究了一下交叉编译技术。主要涉及的语言包括Go
和C
。其中Go
的交叉编译相对来说比较容易,C
的交叉编译在环境配置上有一些难度和繁琐。在研究过程中,踩了不少坑,特此记录。
Go
语言的交叉编译比较容易,基本上就是参数上设置正确就OK了。静态编译的时候,可执行文件相对比较大,这在MIPS
设备中,会有些不适合。因为MIPS
设备存储容量比较小,内存也比较小,如果静态编译出来的文件过大,可能无法下载到设备中,更有甚者无法加载可执行文件,这种情况基本上就只能靠C
语言来进行交叉编译可执行文件了。Go
交叉编译的情况,可以参考链接1所示,我觉得写的不错。对于Go
支持的操作系统和具体版本,可以参考Github Go wiki。如关于ARM
的链接2,关于MIPS
的链接3.
主要来讲C
的交叉编译,毕竟坑多,配置繁琐。
我使用过的交叉编译工具或者环境如下:dockcross
,Buildroot
,crosstool-NG
.
dockcross
相对来说简单方便,基于docker
,能够满足一般需求。可以参考链接4.
我这里出现的情况是,dockcross
解决不了我面临的现实问题。静态编译的可执行文件在设备上运行的时候,提示kernel old
错误。这里的原因是dockcross-arm docker
采用的linux
内核版本太高,其实动态编译得到的可执行程序是能在设备上执行成功的。glibc
向下兼容,所以执行成功了。这是我后续测试发现的。动态编译文件还小,如果能够跑起来,其实动态编译就好了。因为内核版本高了,那就找个内核版本和设备差不多的。然而,dockcross
构建的docker
镜像里,没有符合我要求的。
遇到问题,那就解决问题。找到Buildroot,看着口号是让嵌入式linux
环境构建更加容易。我下载了最新版,看了一下说明文档,配置起来果然方便。make menuconfig
进行配置,然后make
就可以了。make menuconfig
选择它支持的kernel
版本,有个小坑。虽然配置选项可以选择kernel 2.6.x
版本,但是在make
的时候,下载kernel
的时候会出现404错误。buildroot
官方的下载地址已经没有2.6.x
版本的内核了,最低版本是3.2.101
。如果选择了2.6.x
版本的kernel
,需要让其到cdn.kernel网站上去下载对应文件,主要是参考cdn.kernel
网站上,对应kernel
文件名,填入URL of custom kernel tarball
中。C
运行库有uClibc
、glibc
、musl
可以选择。glibc
编译出来的静态文件相对较大,uClibc
编译出来的静态文件相对较小,优先选择uClibc
,musl
我暂时还没用到,这里不评价。
crosstool-NG本来想用,后来看到Buildroot
解决了我的问题,就把它暂时搁置了。看着crosstool-NG
配置和Buildroot
大同小异,这里占个位置,后续使用到了,再来填坑。
其实,最后我还用到了qemu-mips-static
来加载uClibc
。因为我遇到一个很老的MIPS
系统,内核版本是2.4.x
,这在dockcross
构建的环境里面没有,Buildroot
高版本已经不支持kernel2.4.x
了。使用高版本的kernel
进行构建交叉编译工具,最后编译出来的可执行程序在设备上跑不起来,问题如下:
line 1: syntax error: unexpected “(”
我琢磨还是内核版本不兼容导致的。最直接的版本就是安装一个内核版本相同的系统,然后进行交叉编译。说干就干。
尝试安装ubuntu6.06.1
、redhat 9.0
这些古老的linux
系统结合buildroot-0.9.27
来交叉编译,很不幸老旧的linux
发行版不支持包更新了,我只能断了这个念头。无意中我在uClibc官网发现可以挂载编译好的基于Buildroot-0.9.27
的uClibc
来进行交叉编译任务。我真是喜出望外,其实是我没仔细看官网,不然前面安装老旧版本的linux
工作就可以免了。uClibc官网的下载地址挂了,用这个地址下载吧。以root_fs_mips
为例,来进行挂载。主要命令如下:
1 | bunzip2 root_fs_mips.bz2 |
这里有个小坑,因为本机是linux
,在挂载root_fs_mips
的时候出现如下错误:
chroot: failed to run command '/bin/bash': Exec format error
原因是系统架构不同导致的错误。解决办法就是借助qemu-mips-static
。qemu
的安装如下
1 | apt install qemu-user-static |
最后借助qemu_mips_static
挂载root_fs_mips
的命令如下:
1 | cp /usr/bin/qemu-mips-static root_fs_mips/usr/bin |
对于老旧版本的MIPS
,这样进行交叉编译待执行程序,就可以解决问题了。