0. 系统环境
系统:
Arch Linux: 成文时间最新
工具版本:
- Binutils: 2.34-1
- GCC: 9.2.1+20200130-2
- GNU Make: 4.3
1. 编译交叉编译工具链
此部分参考博客.
交叉编译工具链需要用到至少七个工具(库):
- Binutils https://www.gnu.org/software/binutils/
- GCC https://gcc.gnu.org/
- glibc https://www.gnu.org/software/libc/
- Linux Kernel https://www.kernel.org/
- MPFR https://www.mpfr.org/
- GMP https://gmplib.org/
- MPC http://www.multiprecision.org/mpc
同时我们还有两个用于优化的库:
- http://isl.gforge.inria.fr/
- CLooG https://github.com/periscop/cloog
这两个库是可选的.
搭建完成后我们会获得一系列编译, 链接工具, 包括我们熟知的 gcc,ld 等.
1.1 准备工作
首先建立三个目录, 分别存放源码, 构建文件和编译结果(也即我们需要的交叉编译工具链)
- mkdir -p /path/to/cross-compile-src/
- mkdir -p /path/to/cross-compile-build/
- mkdir -p /path/to/cross-compile-install/
- export CROSS_COMPILE_SRC=/path/to/cross-compile-src/
- export CROSS_COMPILE_BUILD=/path/to/cross-compile-build/
- export CROSS_COMPILE_INSTALL=/path/to/cross-compile-install/
将安装目录内未来会生成的 bin 目录加入 PATH(我以为这一步只是为了省事, 为了不把环境变量搞乱我第一次尝试没有加, 结果编译失败)
export PATH=$CROSS_COMPILE_INSTALL/bin:$PATH
接下来下载相应的包, 笔者选用的软件包版本分别为(除 Linux Kernel 外均为成文时最新稳定)
软件名 | 版本 |
---|---|
Binutils | 2.34 |
GCC | 9.2.0 |
glibc | 2.31 |
Linux Kernel | 4.14.172 |
MPFR | 4.0.2 |
GMP | 6.2.0 |
MPC | 1.1.0 |
isl | 0.18 |
CLooG | 0.18.1 |
下载相应的包
- cd $CROSS_COMPILE_SRC
- export GNU_MIRROR_SITE=https://mirrors.tuna.tsinghua.edu.cn/gnu/
- export KERNEL_MIRROR_SITE=https://mirrors.tuna.tsinghua.edu.cn/kernel/
- wget $GNU_MIRROR_SITE/binutils/binutils-2.34.tar.xz # binutils
- wget $GNU_MIRROR_SITE/gcc/gcc-9.2.0/gcc-9.2.0.tar.xz # gcc
- wget $GNU_MIRROR_SITE/glibc/glibc-2.31.tar.xz # glibc
- wget $KERNEL_MIRROR_SITE/v4.x/Linux-4.14.172.tar.xz # kernel
- wget $GNU_MIRROR_SITE/mpfr/mpfr-4.0.2.tar.xz # mpfr
- wget $GNU_MIRROR_SITE/gmp/gmp-6.2.0.tar.xz # gmp
- wget $GNU_MIRROR_SITE/mpc/mpc-1.1.0.tar.gz # mpc
- # optional
- wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 # isl
- wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz # cloog
解压
- for f in *.tar.xz; do tar -xJf $f; done
- for f in *.tar.bz2; do tar -xjf $f; done
- for f in *.tar.gz; do tar -xzf $f; done
建立 GCC 依赖库们的软链接
- ln -s ../mfpr-4.0.2 gcc-9.2.0/mfpr # mfpr
- ln -s ../gmp-6.2.0 gcc-9.2.0/gmp # gmp
- ln -s ../mpc-1.1.0 gcc-9.2.0/mpc # mpc
- # optional
- ln -s ../isl-0.18 gcc-9.2.0/isl # isl
- ln -s ../cloog-0.18.1 gcc-9.2.0/cloog # cloog
设定编译时使用的线程数
export NPROC=`nproc` # use all processors
1.2. 编译安装 Binutils
这个工具包将会被安装在 /path/to/cross-compile-gcc/install/bin 内, 包括了交叉汇编器, 交叉链接器等工具.
- cd $CROSS_COMPILE_BUILD
- mkdir binutils
- cd binutils
- $CROSS_COMPILE_SRC/binutils-2.34/configure --prefix=$CROSS_COMPILE_INSTALL --target=aarch64-Linux --disable-multilib
- make -j$NPROC
- make install
1.3. 安装 Linux Kernel 头文件
这一步会将 Linux Kernel 头文件安装咋 $CROSS_COMPILE_INSTALL/aarch64-install/include, 这样交叉编译链编译出的软件可以在目标平台中使用 Linux 系统调用.
- cd $CROSS_COMPILE_SRC/Linux-4.14.172
- make ARCH=arm64 INSTALL_HDR_PATH=$CROSS_COMPILE_INSTALL/aarch64-Linux headers_install
1.4. 编译安装 GCC 和 glibc
这是很长的一步, 我们将要轮流编译属于两个库 (GCC 和 glibc) 的组件, 并最终全部编译完成. 编译顺序如下(图源为参考博客)
1.4.1. 编译器
这一步只会安装 C/C++ 交叉编译器本身, 它们会被安装在 $CROSS_COMPILE_INSTALL/bin.
- cd $CROSS_COMPILE_BUILD
- mkdir gcc
- cd gcc
- $CROSS_COMPILE_SRC/gcc-9.2.0/configure --prefix=$CROSS_COMPILE_INSTALL --target=aarch64-Linux --enable-language=c,c++ --disable-multilib
- make -j$NPROC all-gcc
- make install-gcc
这一步要编译个十分钟左右, 可以去喝口水, 打个飞机什么的.
1.4.2. 标准 C 头文件和启动文件
这一步里我们将所有的标准 C 头文件安装在 $CROSS_COMPILE_INSTALL/aarch64-Linux/include 内. 同时我们还会编译一些启动文件并安装在 $CROSS_COMPILE_INSTALL/aarch64-Linux/lib 内, 这些文件将被下一步用到, 并在下下步被替换.
注意: 如果前面没有把 $CROSS_COMPILE_INSTALL/bin 加入到 PATH 中的话这一步会报错.
- cd $CROSS_COMPILE_BUILD
- mkdir glibc
- cd glibc
- $CROSS_COMPILE_SRC/glibc-2.31/configure --prefix=$CROSS_COMPILE_INSTALL/aarch64-Linux --build=$MACHTYPE --host=aarch64-Linux --target=aarch64-Linux --with-headers=$CROSS_COMPILE_INSTALL/aarch64-Linux/include --disable-multilib libc_cv_forced_unwind=yes
- make install-Bootstrap-headers=yes install-headers
- make -j$NPROC csu/subdir_lib
- install csu/crt1.o csu/crti.o csu/crtn.o $CROSS_COMPILE_INSTALL/aarch64-Linux/lib
- aarch64-Linux-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $CROSS_COMPILE_INSTALL/aarch64-Linux/lib/libc.so
- touch $CROSS_COMPILE_INSTALL/aarch64-Linux/include/gnu/stubs.h
1.4.3. 编译器支持库
这一步我们使用前面编译得到的交叉编译器来编译编译器支持库.
- cd $CROSS_COMPILE_BUILD/gcc
- make -j$NPORC all-target-libgcc
- make install-target-libgcc
1.4.4. 编译标准 C 库
这一步我们可以完成 glibc 的编译安装. 标准 C 库将被安装于 $CROSS_COMPILE_INSTALL/aarch64_linux/lib.
- cd $CROSS_COMPILE_BUILD/glibc
- make -j$NPROC
- make install
这一步依然要十来分钟, 可以再来一发.
1.4.5. 编译标准 C++ 库
这一步我们可以完成 GCC 的编译安装. 标准 C++ 库将被安装于 $CROSS_COMPILE_INSTALL/aarch64_linux/lib64.
- cd $CROSS_COMPILE_BUILD/gcc
- make -j$NPROC
- make install
注意: 这一步可能出现如下错误
- error: 'PATH_MAX' was not declared in this scope
- 216 | char filename[PATH_MAX];
- | ^~~~~~~~
看了编译命令发现没有将我们导入的 Linux 头文件加入 include 范围, 因此编译时 include 的头文件来自系统的 Linux 头文件. 因为编译 GCC 使用的头文件不一定是 GCC 运行时使用的头文件, 所以这个问题理论上不会影响交叉编译的结果. 我们只需要简单地修改下源码, 将
- #ifndef PATH_MAX
- # define PATH_MAX 4096
- #endif // PATH_MAX
加入 $CROSS_COMPILE_SRC/gcc-9.2.0/libsanitizer/asan/asan_linux.cc 即可.(如果有更好的方法请一定告诉我)
1.5. 测试交叉编译器
- aarch64-Linux-gcc helloworld.c -o a.out
- aarch64-Linux-objdump -d a.out
1.6. 吐槽
你问我为什么不用 community 源里的 aarch64-Linux-gnu-*?
因为我瞎我没看到(哭).
2. 交叉编译内核
3. 安装内核
来源: http://www.bubuko.com/infodetail-3460631.html