1 基础知识

1.1 查看目标target主机软件版本

  1. 查看glibc版本(glibc在后续编译gcc过程中会用到

     ldd --version
    
  2. 查看gcc版本
     gcc -v
    
  3. 查看linux内核的版本
     uname -r
    

1.2 机器名称命名规则

gcc编译过程中,一般需要给你三个机器名称,即编译系统(build)、运行系统(host)、目标系统(target),以便编译器生成对应机器的二进制代码。

  • build:是指目前我们正在用那个平台来构建。如果不指定,系统会根据当前环境进行猜测。

  • host:我们使用那个平台来运行已经构建好的代码。

    • 我进行分析:在编译glibc的时候,host=aarch64-linux-gnu,是因为编译的程序和库都是为了在aarch64上面运行,所以此时要使用交叉编译aarch64-linux-gnu-gcc
    • 在编译binutils、gcc的时候,host=x86_64-linux-gnu,是因为编译好的二进制程序和库都是要在x86_64上面运行,这些二进制程序和库是为了编译target运行的代码。
  • target: 指的是运行最终生成的代码在那个机器上面运行。

命名规则:<architecture>-<vendor>-<operating_system>[-<kernel>]

  • architecture:处理器架构,如 x86_64、arm、aarch64、mips 等。

  • vendor(可选):供应商标识,如 pc、apple、unknown 等。(如果省略这一项,自动就会是unknown)

  • operating_system:操作系统标识,如 linux、gnu、darwin、windows 等。

  • kernel(可选):内核标识,如 gnu(对于 GNU/Linux)等。

alt text

我们从binutils源代码的文件中,查看configure文件,可以看到支持的汇编器(as)、连接器(ld)类型:

alt text

如果我们指定的架构类型,相关汇编器不支持,就会报错:

alt text

2.1 准备工作

提前安装依赖

sudo apt-get install -y texinfo libgmp-dev libmpfr-dev libmpc-dev libisl-dev gawk

声明以下环境变量,后续编译的时候会用到。

export PREFIX=/home/lieryang/Documents/jetson_tool/gcc-jetson-9.4-x86_64-aarch64-linux-gnu
export TARGET=aarch64-linux-gnu
export PATH="$PREFIX/bin:$PATH"

2.1 编译binutils

gcc是一个工具链,使用的是binutils提供的汇编器、链接器、归档器等。 binnutils的版本无所谓,因为arm架构指令集不会因为binutils版本变化发生改变。

binutils提供了:as(汇编器)、ld(链接器)、ar(归档器)等。

Binutils下载:https://ftp.gnu.org/gnu/binutils/

mkdir build && cd build

../configure --prefix=$PREFIX \
--build=$MACHTYPE \
--host=$MACHTYPE \
--target=$TARGET \
--with-sysroot="$PREFIX/$TARGET/sys-root" \
--disable-multilib \
--disable-shared \ 
--disable-nls

make -j20
make install

–disable-multilib:用于禁用对多架构(multilib)支持的构建,禁用多架构后,GCC只能编译64位代码,不能再编译32位代码。禁用多架构支持可以避免不必要的复杂性,并确保构建过程和工具链的行为更加一致和可预测。

–disable-shared:选项在构建过程中禁用共享库的生成,仅构建静态库。(不会编译生成共享库,而是生成静态库)。

–disable-nls:于禁用本地化支持(NLS,National Language Support)。比如:消息翻译、字符编码、日期、时间、货币格式的呢个。

–with-sysroot:是一个配置选项,用于指定交叉编译环境中的系统根目录(sysroot)。系统根目录是一个目录树,其中包含目标系统的头文件和库文件。通过指定 –with-sysroot,可以让编译器和链接器在正确的位置查找这些文件,从而生成正确的目标代码。

编译安装完成后,可以通过 --version 查看

alt text

$PREFIX/$TARGET/sys-root/这是我们交叉编译目标系统的根目录,下面Linux内核头文件,都会安装到里面。

2.2 安装Linux内核头文件到sys-root

Linux内核下载:https://mirrors.ustc.edu.cn/kernel.org/linux/kernel/

接下来编译 glibc 库依赖于 Linux内核头文件

make ARCH=arm64 INSTALL_HDR_PATH="$PREFIX/$TARGET/sys-root/usr" headers_install

安装Linux内核头文件到 /home/lieryang/Documents/jetson_tool/gcc-jetson-9.4-x86_64-aarch64-linux-gnu/aarch64-linux-gnu/sys-root/usr/include,这个目录下面编译glibc的时候会用到。

alt text

2.3 第一次编译GCC

gcc下载:https://ftp.gnu.org/gnu/gcc/

../configure --prefix=$PREFIX \
--build=$MACHTYPE --host=$MACHTYPE \
--target=$TARGET \
--with-sysroot="$PREFIX/$TARGET/sys-root" \
--with-build-sysroot="$PREFIX/$TARGET/sys-root" \
--disable-multilib \
--disable-shared \
--disable-nls \
--with-zstd \
--with-mpc \
--with-gmp \
--with-isl \
--with-mpfr \
--enable-languages=c,c++,fortran
make -j20 all-gcc # 一定要指定是all-gcc,否则会出错
make install-gcc
我只是使用的有mpc、gmp、isl、mpfr选项,并没有根据`参考1`,把以上相关文件放入gcc目录,我安装的以上四种dev包,就不会报错。 我认为可能并不需要这几种额外的包。因为host有就可以。

–with-zstd:可以开启比默认Zlib压缩算法更高效的Zstd压缩算法。编译流程中的链接时优化(LTO, Link-Time Optimization)通常需要处理大量数据,因而需要高效的压缩算法。据报道,Zstd压缩算法可以在压缩比率相近的条件下,提高4-8倍链接速度。

–with-build-sysroot:用于在构建交叉编译工具链(如 GCC)时指定一个系统根目录(sysroot)。这个选项告诉构建系统在编译器自身构建过程中,应该在哪个目录中查找头文件和库文件。这个文件夹包含构建编译器时候使用的头文件目录

2.4 第一次编译glibc

glibc下载:https://ftp.gnu.org/gnu/glibc/

export CC=$TARGET-gcc
export LD=$TARGET-ld
export AR=$TARGET-ar
export RANLIB=$TARGET-ranlib

../configure --prefix=/usr \
--build=$MACHTYPE --host=$TARGET \
--target=$TARGET \
--with-headers="$PREFIX/$TARGET/sys-root/usr/include" \
--disable-multilib \
--disable-werror \
libc_cv_forced_unwind=yes

先编译安装一部分到交叉编译目标系统目录

make install-bootstrap-headers=yes install_root=$PREFIX/$TARGET/sys-root install-headers
make -j6 csu/subdir_lib
mkdir $PREFIX/$TARGET/sys-root/usr/lib
install csu/crt1.o csu/crti.o csu/crtn.o $PREFIX/$TARGET/sys-root/usr/lib
# Create dummy libc.so and stubs.h
$TARGET-gcc \
    -nostdlib \
    -nostartfiles \
    -shared \
    -x c /dev/null \
    -o $PREFIX/$TARGET/sys-root/usr/lib/libc.so
touch $PREFIX/$TARGET/sys-root/usr/include/gnu/stubs.h

2.5 进入gcc编译libgcc

rm gcc/stmp-fixinc
make -j20 all-target-libgcc
make install-target-libgcc

2.6 第二次编译glibc

要有安装跟系统前缀

make -j20
make install_root="$PREFIX/$TARGET/sys-root" install

2.7 第二次编译gcc

make -j20
make install

参考

参考1:「天龙八部」年轻人的第一个GCC交叉编译器(主要参考)

参考2:从零开始编译一个gcc的交叉编译工具链

参考3:全手工制作arm-linux交叉编译工具链