Linux toolchain本质上是一个运行在x86_64 Linux上的软件,但是因为有时候高版本的toolchain依赖更高版本glibc里的特性,因此toolchain会内置一个高版本的libc.so.6,一般这类常见的toolchain如:poky和arago等,这类toolchain往往要有个安装过程,而不是单纯解压缩的方式提供,在安装过程会将一系列crosstool根内置的libc.so.6、ld-linux-x86-64.so.2等路径进行绑定,而且是绝对路径关联绑定,这就导致安装好的toolchain拷贝到别的电脑里不能运行的原因。遇到这列情况,很多人会妥协选择安装到docker里,然后统一提供部署好编译环境的docker,毕竟引入了额外的依赖,增加了小白的学习成本,而且还会给编译性能打折扣,不算是最佳选择。
poky和arago的toolchain目录结构比较类似,如下:
sysroots
├── aarch64-arago-linux
└── x86_64-arago-linux
├── bin
│ ├── xx
│ └── xx
├── etc
│ ├── xxx
│ └── xxx
├── lib
│ ├── ld-linux-x86-64.so.2
│ ├── libc.so.6
│ └── xxxx
├── sbin
│ ├── xxx
│ └── xxx
├── usr
│ ├── bin
│ │ ├── aarch64-oe-linux ------------------- # 改造的地方1
│ │ │ ├─aarch64-oe-linux-gcc
│ │ │ ├─aarch64-oe-linux-g++
│ │ │ └─xxx
│ │ ├── aarch64-oe-linux-musl
│ │ ├── xxx
│ │ └── xxx
│ ├── include
│ │ ├── xxx
│ │ └── xxx
│ ├── lib
│ │ ├── xxx
│ │ └── xxx
│ ├── libexec
│ │ ├── aarch64-oe-linux
│ │ │ └── gcc
│ │ │ └── aarch64-oe-linux
│ │ │ └── 13.3.0 ------------------- # 改造的地方2
│ │ │ ├── cc1
│ │ │ ├── collect2
│ │ │ ├── lto1
│ │ │ ├── cc1plus
│ │ │ └── xxx
│ │ ├── xxx
│ │ └── xxx
│ ├── share
│ │ ├── xxx
│ │ └── xxx
│ └── var
└── var
在sysroots下其中aarch64-arago-linux是真正的aarch64的目标文件系统,而x86_64-arago-linux里存放了用于交叉编译的crosstool。
首先,我们默认将其安装到了/opt/arago-2025.01
下,为了绿化它,随后给它赋予了所有权限并拷贝到/home/xxx/Downloads
下,随后开始分析并绿化它。
先拿aarch64-oe-linux-gcc
开头,通过直接ldd分析发现它除了依赖系统库,还额外依赖了/opt/arago-2025.01/sysroots/x86_64-arago-linux/lib/ld-linux-x86-64.so.2
, 即:安装目录里的ld-linux-x86-64.so.2
:
$ ldd aarch64-oe-linux-gcc
./aarch64-oe-linux-gcc: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by ./aarch64-oe-linux-gcc)
./aarch64-oe-linux-gcc: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.36' not found (required by ./aarch64-oe-linux-gcc)
linux-vdso.so.1 (0x00007ffd847bf000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x000078b6d652d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000078b6d6200000)
/opt/arago-2025.01/sysroots/x86_64-arago-linux/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000078b6d6627000)
看起来依赖的libm.so.6和libc.so.6都是来自系统目录的,实际也是依赖安装目录下的,否则就不会出现警告:
/lib/x86_64-linux-gnu/libc.so.6: version 'GLIBC_2.38' not found (required by ./aarch64-oe-linux-gcc)
。同理,当ldd 分析sysroots/x86_64-arago-linux/usr/libexec/aarch64-oe-linux/gcc/aarch64-oe-linux/13.3.0/cc1
等文件的依赖时候也是如此。
绿化改造办法有两种:
- 如果你当前的Linux操作系统版本够高,即:系统glibc版本高于crosstool所要求的glibc版本时候,可以直接通过patchelf修改interpreter指向系统自带的
ld-linux-x86-64.so.2
, 即:
sudo apt install patchelf -y
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 aarch64-oe-linux-gcc
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 aarch64-oe-linux-g++
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 other/execuable/file
...
同样的操作还需要修改sysroots/x86_64-arago-linux/usr/libexec/aarch64-oe-linux/gcc/aarch64-oe-linux/13.3.0
下的可执行文件,如:cc1、cc1plus等,注意里面有些软链接不用动,比如:gcc,cpp,nm等,他们指向sysroots/x86_64-arago-linux/usr/bin/aarch64-oe-linux
里的文件,因为前一笔我们已经对其修复过了。
查看目标文件内的关联的glibc版本:strings file_to_check | grep GLIBC
- 反之,如果你当前的Linux操作系统版本不够高,你就没办法通过修改interpreter 的方式了,因为interpreter 指向的路径必须是绝对路径,因此就办法以相对路径指向
sysroots/x86_64-arago-linux/lib/ld-linux-x86-64.so.2
了,即便用$ORIGIN
也不管用, 因此,剩余的办法就是:
- 重命名之前的bin文件,统一加个后缀,比如:"aarch64-oe-linux-gcc.real";
- 创建一个根之前的bin文件名一样的shell文件, 如:"aarch64-oe-linux-gcc", 并填充命令如下:
#!/bin/bash
ROOT="$(dirname "$(readlink -f "$0")")/../../../"
exec "$ROOT/lib/ld-linux-x86-64.so.2" \
--library-path "$ROOT/lib:$ROOT/usr/lib" \
"$ROOT/usr/bin/aarch64-oe-linux/aarch64-oe-linux-gcc.real" "$@"
以此类似替换剩余的bin文件,或许可能有些bin文件在交叉编译期间未必需要,可以看情况把剩余的文件进行处理。
同理,
sysroots/x86_64-arago-linux/usr/libexec/aarch64-oe-linux/gcc/aarch64-oe-linux/13.3.0
下的文件也需要类似处理,不过需要注意的是哪里的ROOT="$(dirname "$(readlink -f "$0")")/../../../"
需要调整,因为寻找ld-linux-x86-64.so.2
的相对目录不一样。
其实sysroots/x86_64-arago-linux/usr/bin
下的所有可执行文件都有类似的问题,但我们只是交叉编译,不依赖这里的可执行文件,因此就不需要处理它们了。