为了避免和host的编译系统耦合,很多sdk和需要和客户联编的软件都会提供自己的工具链或者要求客户的系统满足某种工具链要求。
大概梳理下来独立的ToolChain 有如下一些好处:
1. 不用关心host操作系统,只要下载toolchain,随时随地(前提是x86的Linux操作系统,Windows和arm的Linux上也可以做,不过需要单独做,每增加一套,会有更多的维护成本)可以编译。
2. 部分编译器补丁,操作系统不一定会发,这时需要对toolchain单独打补丁,如果用host的编译工具,要考虑补丁之后和OS本身的兼容性。
3. arm当前本身性能比x86还是差不少,而且公司内部arm的服务器数量有限,这都要求在x86服务器上进行交叉编译。
1 安装包下载
apt-get install libgmp-dev libmpfr-dev libmpc-dev g++ make gawk
下载编译需要的源代码包(上面用apt命令下载的gmp,mpfr和mpc也可以下载源代码包编译,上面为了省事直接下载了安装源上的包)
wget
wget
wget
如果这3个组建是源代码编译的话,记得在gcc编译目录下面建立软连接,方便编译器能自动搜索到,否则需要单独指定代码目录
ln -s ../mpfr-4.1.0 mpfr ln -s ../gmp-6.2.1 gmp ln -s ../mpc-1.2.1 mpc
binutils也可以取最新版本的,这个无所谓:
wget
gcc取了ubuntu18和ubuntu20上的7.x和9.x系列的最新版本,也可以取11.x,一般来说版本越新,功能越强大:
wget
wget
wget
内核版本之前下载这个只是为了和host上的尽量保持一致,这样内核版本和glibc的版本匹配关系不用自己摸索了,实际上其他匹配的组合也可以:
wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.15.1.tar.xz
glibc的版本很重要,决定了编译出来的版本能运行的最小支持版本,如果目标机器上的glibc版本比这个更老,则无法运行,2.23是ubuntu 16上的glibc版本:
wget
为什么都下载xz版本的?因为比其他版本小啊
2 程序的交叉编译和执行过程
在host服务器上安装了c和c++的交叉编译工具链(假定目标系统是aarch64的系统),编译过程中会将c或者c++程序先编译成汇编临时文件,然后依赖本地的汇编器as编译成目标文件,再用链接器ld链接生成可执行文件,但这个可执行文件的格式是按目标系统来构建的,所以在host服务器上无法运行。
编译完的可执行文件通过版本发布或者拷贝到方式下载的目标系统上,例如最简单的a.out小程序,如果该程序依赖C++的库,则在目标系统上加载的过程中会先对C++的标准库进行动态链接,然后链接底层的C标准库(基本上所有编程语言底层都是基于C标准库),加载完之后内核的调度器会将该程序从入口运行起来。
3 编译过程 3.0 编译准备
解压缩上面下载的包。
创建编译目标目录。
燧原很多产品都是xxx开头,虽然我还不知道这3个字母是什么都缩写,但我还是沿用了,其实用其他路径名也可以的。
如果是直接在host上编译的话,尽量不要用root用户来操作,免得把host操作系统搞挂了痛不欲生。如果是在容器里面编译就随意了,容器的root文件系统弄坏大不了删掉当前容器重新启动一个。
目录里面最好包含gcc版本号、glibc版本号和目标硬件架构名,免得进去了之后猜:
mkdir -p /opt/xxx/xxx_aarch64_gcc9.4.0_glibc2.23linux更新好PATH全局变量,确保后面编译过程中使用的工具都是新编译出来的,而不是host上的:
export PATH=/opt/xxx/xxx_aarch64_gcc9.4.0_glibc2.23linux/bin:$PATH3.1 编译binutils
正式编译gcc之前,需要先编译一个编译gcc的工具,也就是binutils包。
cd binutils-2.28.1
mkdir xxx_aarch64_gcc9.4.0_glibc2.23linux_build
cd xxx_aarch64_gcc9.4.0_glibc2.23linux_build
--disable-multilib的含义是不需要考虑同一个系列硬件架构下面的兼容性,例如aarch64目标机能运行,是否需要做aarch32上运行?x86_64的程序是否需要做i586上运行等等,一般应该没这种需求。
../configure --prefix=/opt/xxx/xxx_aarch64_gcc9.4.0_glibc2.23linux --target=aarch64-linux-gnu --disable-multilib