Linux toolchain绿色改造

  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等文件的依赖时候也是如此。

绿化改造办法有两种:

  1. 如果你当前的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

  1. 反之,如果你当前的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下的所有可执行文件都有类似的问题,但我们只是交叉编译,不依赖这里的可执行文件,因此就不需要处理它们了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。