跳过正文

GCC 交叉编译工具链

·
Gnu Compiler Glibc Gcc
目录
gnu-toolchain - 这篇文章属于一个选集。
§ 4: 本文

交叉编译是指编译器能生成和它执行环境不同的 CPU 架构的二进制,例如在 arm64 机器上编译出在 x86_64 机器上运行的二进制。

本文分别以常用的 ubuntu aarch64 和 fedora 40 x86_64 编译环境为例,介绍这两个问题的解决方案。

target triplet
#

格式:“cpu-vendor-os”, 其中 os 可以是 system 或 kernel-system。

  • cpu:一般使用 uname -m 命令来获取,如 arm64 CPU 使用的是 aarch64, arm32 CPU 使用的是 arm。
  • vendor:一般为 pc(windows 硬件)、apple(苹果硬件)、unknown(未知、通用);
  • kernel:linux、none(不带内核的裸机程序)
  • system:
    • gnu:通用的,使用 GNU ABI,链接 glibc;
    • gnueabi:一般是 arm32 在用,使用 GNU EAPI,链接 glibc;
    • gnueabihf:一般是 arm32 在用,使用 GNU EABI(嵌入式 ABI 接口),链接 glibc,使用硬件浮点 (hard-float);
    • musl:链接一个专为嵌入式系统设计的轻量级 C 库 musl ,目标是提供与 glibc 相似的功能,但占用更少的资源。常用的场景是实现 libc 库的静态链接, 以解决运行时机器上的 glibc 缺失或版本太老的问题;
    • elf:不适用内核和操作系统的裸机程序;

triplet 示例:

## arm64(ARMv8 及以上处理器,默认硬件浮点计算)
aarch64-apple-darwin

aarch64-unknown-linux-gnu # 使用 GNU ABI 和链接 glibc 《-- 主流
aarch64-unknown-linux-gnu_ilp32
aarch64-unknown-linux-musl
aarch64-unknown-none # 不使用内核和 glibc,如逻辑 elf 程序

aarch64-none-elf:用于裸机(无操作系统)的 64 位 ARM 开发,遵循 ELF 格式。

## arm32 (ARMv7 及以前的处理器)
arm-unknown-linux-gnueabi   # 链接 glibc
arm-unknown-linux-gnueabihf # hf 表示硬件浮点 hard-float 《-- 主流
arm-unknown-linux-musleabi  # 链接 musl
arm-unknown-linux-musleabihf

x86_64-unknown-linux-gnu  《-- 主流
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-linux-none

gcc 工具链一般是只支持编译生成特定架构的二进制,而不能生成其它架构的二进制。

使用 gcc -dumpmachine 命令查看支持的 triplet:

alizj@ubuntu:~$ gcc -dumpmachine
aarch64-linux-gnu

Ubuntu、RedHat 系统支持安装多套交叉编译工具链,它们使用不同的 target-triplet 和目录结构来区分:

  • 如 x86_64-unknown-linux-gnu-gcc 能生成 x86_64 架构的二进制,它也会自动调用 x86_64-unknown-linux-gnu- 前缀的其它命令。
  • /usr/x86_64-unknown-linux-gnu 作为该交叉编译工具链的第二目录层次,下面的 bin、lib 等保存该架构的 binutils 命令、头文件、libc 标准库、gcc 命令和库等。

对于 autoconf、make、go build 等命令,可以通过 CC 环境变量来指定使用的工具链,或 –host=aarch64-linux-gnu 来指定架构前缀。

例如,当交叉编译时,configure 会查找带有 target triplet 前缀的工具,如 compilers, linkers, assemblers,如指定运行编译产物的 –host=aarch64-linux-gnu 时,使用的 C 编译器是 aarch64-linux-gnu-gcc,pkg-config 是 aarch64-linux-gnu-pkg-config,这样可以避免找到了错误类型的工具链。

cpp:预处理器
#

相关包:

alizj@ubuntu:~$ apt list |grep cpp |grep installed |grep -v x86
cpp-13-aarch64-linux-gnu/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
cpp-13/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
cpp-aarch64-linux-gnu/noble,now 4:13.2.0-7ubuntu1 arm64 [installed,automatic]
cpp/noble,now 4:13.2.0-7ubuntu1 arm64 [installed,automatic]

提供 cpp/cpp-13/aarch64-linux-gnu-cpp-13 命令,以及 gcc -E 自动调用的 cc1 程序。

alizj@ubuntu:~$ dpkg -L cpp
...
/usr/bin/cpp
...

alizj@ubuntu:~$ dpkg -L cpp-13
...
/usr/bin/cpp-13
...

alizj@ubuntu:~$ dpkg -L cpp-13-aarch64-linux-gnu
...
/usr/bin/aarch64-linux-gnu-cpp-13
...
/usr/libexec/gcc/aarch64-linux-gnu/13/cc1

alizj@ubuntu:~$ dpkg -L cpp-aarch64-linux-gnu
...
/usr/bin/aarch64-linux-gnu-cpp

gcc 编译器使用的是内置的预处理器(gcc -E)通过 cc1 来进行预处理,独立 cpp 命令是历史兼容性场景。

gcc:编译器
#

相关包:

alizj@ubuntu:~$ apt list --installed |grep gcc |grep arm64 |grep -v x86-64
gcc-13-aarch64-linux-gnu/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
gcc-13-base/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
gcc-13/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
gcc-14-base/noble-updates,noble-security,now 14.2.0-4ubuntu2~24.04 arm64 [installed]
gcc-aarch64-linux-gnu/noble,now 4:13.2.0-7ubuntu1 arm64 [installed,automatic]
gcc-doc/noble,now 4:13.2.0-7ubuntu1 arm64 [installed]
gcc/noble,now 4:13.2.0-7ubuntu1 arm64 [installed,automatic]
libgcc-13-dev/noble-updates,noble-security,now 13.3.0-6ubuntu2~24.04 arm64 [installed,automatic]
libgcc-s1/noble-updates,noble-security,now 14.2.0-4ubuntu2~24.04 arm64 [installed]

提供:

  1. /usr/bin/gcc 和 /usr/bin/aarch64-linux-gnu-* 等二进制;
  2. /usr/lib/gcc/aarch64-linux-gnu/13/usr/libexec/gcc/aarch64-linux-gnu/13: 包含 GCC 自身的头文件、库文件和调用的二进制。

二进制链接关系:gcc -> gcc-13 -> aarch64-linux-gnu-gcc-13

alizj@ubuntu:~$ ls -l /usr/bin/gcc
lrwxrwxrwx 1 root root 6 Jan 31  2024 /usr/bin/gcc -> gcc-13
alizj@ubuntu:~$ ls -l /usr/bin/gcc-13
lrwxrwxrwx 1 root root 24 Sep  4 22:44 /usr/bin/gcc-13 -> aarch64-linux-gnu-gcc-13
alizj@ubuntu:~$ ls -l /usr/bin/aarch64-linux-gnu-gcc-13
-rwxr-xr-x 1 root root 990040 Sep  4 22:44 /usr/bin/aarch64-linux-gnu-gcc-13

alizj@ubuntu:~$ dpkg -L gcc
...
/usr/bin/c89-gcc
/usr/bin/c99-gcc
/usr/lib/bfd-plugins
...
/usr/bin/gcc
/usr/bin/gcc-ar         # 打包为静态库
/usr/bin/gcc-nm         # 解析 ELF 符号
/usr/bin/gcc-ranlib     # 为静态库生成索引
/usr/bin/gcov
/usr/bin/gcov-dump
/usr/bin/gcov-tool
/usr/bin/lto-dump
/usr/lib/bfd-plugins/liblto_plugin.so

alizj@ubuntu:~$ dpkg -L gcc-13
...
/usr/bin/gcc-13
/usr/bin/gcc-ar-13
/usr/bin/gcc-nm-13
/usr/bin/gcc-ranlib-13
/usr/bin/gcov-13
/usr/bin/gcov-dump-13
/usr/bin/gcov-tool-13
/usr/bin/lto-dump-13
...

alizj@ubuntu:~$ dpkg -L gcc-aarch64-linux-gnu
...
/usr/bin/aarch64-linux-gnu-gcc
/usr/bin/aarch64-linux-gnu-gcc-ar
/usr/bin/aarch64-linux-gnu-gcc-nm
/usr/bin/aarch64-linux-gnu-gcc-ranlib
/usr/bin/aarch64-linux-gnu-gcov
/usr/bin/aarch64-linux-gnu-gcov-dump
/usr/bin/aarch64-linux-gnu-gcov-tool
/usr/bin/aarch64-linux-gnu-lto-dump
...

alizj@ubuntu:~$ dpkg -L gcc-13-aarch64-linux-gnu
...
/usr/bin/aarch64-linux-gnu-gcc-13
/usr/bin/aarch64-linux-gnu-gcc-ar-13
/usr/bin/aarch64-linux-gnu-gcc-nm-13
/usr/bin/aarch64-linux-gnu-gcc-ranlib-13
/usr/bin/aarch64-linux-gnu-gcov-13
/usr/bin/aarch64-linux-gnu-gcov-dump-13
/usr/bin/aarch64-linux-gnu-gcov-tool-13
/usr/bin/aarch64-linux-gnu-lto-dump-13
...
/usr/lib/gcc/aarch64-linux-gnu/13
/usr/lib/gcc/aarch64-linux-gnu/13/libgomp.spec
/usr/lib/gcc/aarch64-linux-gnu/13/libhwasan_preinit.o
/usr/lib/gcc/aarch64-linux-gnu/13/libitm.spec
/usr/lib/gcc/aarch64-linux-gnu/13/libsanitizer.spec
/usr/lib/gcc/aarch64-linux-gnu/13/plugin
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcc1plugin.so.0.0.0
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcp1plugin.so.0.0.0
...
# /usr/libexec/gcc 保存 gcc 调用的内部命令和库
/usr/libexec/gcc/aarch64-linux-gnu
/usr/libexec/gcc/aarch64-linux-gnu/13
/usr/libexec/gcc/aarch64-linux-gnu/13/collect2
/usr/libexec/gcc/aarch64-linux-gnu/13/liblto_plugin.so
/usr/libexec/gcc/aarch64-linux-gnu/13/lto-wrapper
/usr/libexec/gcc/aarch64-linux-gnu/13/lto1
...
/usr/lib/gcc/aarch64-linux-gnu/13/libcc1.so
/usr/lib/gcc/aarch64-linux-gnu/13/liblto_plugin.so
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcc1plugin.so
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcc1plugin.so.0
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcp1plugin.so
/usr/lib/gcc/aarch64-linux-gnu/13/plugin/libcp1plugin.so.0
/usr/share/doc/gcc-13-aarch64-linux-gnu

# libgcc-13-dev 包提供了 gcc 提供的内建函数实现的动态库、静态库以及对应头文件,
# 它们会被链接到 C 程序中,提供了 main 函数前后逻辑:
alizj@ubuntu:~$ dpkg -L libgcc-13-dev
...
# C 启动例程,调用 main 函数
/usr/lib/gcc/aarch64-linux-gnu/13/crtbegin.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtbeginS.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtbeginT.o
# C 结束例程,main 返回后执行
/usr/lib/gcc/aarch64-linux-gnu/13/crtend.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtendS.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtfastmath.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtoffloadbegin.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtoffloadend.o
/usr/lib/gcc/aarch64-linux-gnu/13/crtoffloadtable.o
# GCC 相关头文件
/usr/lib/gcc/aarch64-linux-gnu/13/include
/usr/lib/gcc/aarch64-linux-gnu/13/include/backtrace.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/float.h
...
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdalign.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdarg.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdatomic.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdbool.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stddef.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdfix.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdint-gcc.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdint.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/stdnoreturn.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/syslimits.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/unwind.h
/usr/lib/gcc/aarch64-linux-gnu/13/include/varargs.h
# GCC 自身使用的库
/usr/lib/gcc/aarch64-linux-gnu/13/libasan.a
/usr/lib/gcc/aarch64-linux-gnu/13/libasan_preinit.o
/usr/lib/gcc/aarch64-linux-gnu/13/libatomic.a
/usr/lib/gcc/aarch64-linux-gnu/13/libbacktrace.a
/usr/lib/gcc/aarch64-linux-gnu/13/libgcc.a
/usr/lib/gcc/aarch64-linux-gnu/13/libgcc_eh.a
/usr/lib/gcc/aarch64-linux-gnu/13/libgcc_s.so
/usr/lib/gcc/aarch64-linux-gnu/13/libgcov.a
/usr/lib/gcc/aarch64-linux-gnu/13/libgomp.a
/usr/lib/gcc/aarch64-linux-gnu/13/libhwasan.a
/usr/lib/gcc/aarch64-linux-gnu/13/libitm.a
/usr/lib/gcc/aarch64-linux-gnu/13/liblsan.a
/usr/lib/gcc/aarch64-linux-gnu/13/liblsan_preinit.o
/usr/lib/gcc/aarch64-linux-gnu/13/libssp_nonshared.a
/usr/lib/gcc/aarch64-linux-gnu/13/libtsan.a
/usr/lib/gcc/aarch64-linux-gnu/13/libtsan_preinit.o
/usr/lib/gcc/aarch64-linux-gnu/13/libubsan.a
/usr/lib/gcc/aarch64-linux-gnu/13/libasan.so
/usr/lib/gcc/aarch64-linux-gnu/13/libatomic.so
/usr/lib/gcc/aarch64-linux-gnu/13/libgomp.so
/usr/lib/gcc/aarch64-linux-gnu/13/libhwasan.so
/usr/lib/gcc/aarch64-linux-gnu/13/libitm.so
/usr/lib/gcc/aarch64-linux-gnu/13/liblsan.so
/usr/lib/gcc/aarch64-linux-gnu/13/libtsan.so
/usr/lib/gcc/aarch64-linux-gnu/13/libubsan.so
/usr/share/doc/libgcc-13-dev

gcc 内置了内部二进制搜索路径,以及 gcc 和 glibc 库的搜索路径,它们都是和 target triplet 相关的,所以系统可以按照多个 triplet 的编译工具链和 glibc 库,而不会相互混淆:

alizj@ubuntu:~$ gcc -print-search-dirs
install: /usr/lib/gcc/aarch64-linux-gnu/13/
programs: =/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/
libraries: =/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../lib/:/lib/aarch64-linux-gnu/13/:/lib/aarch64-linux-gnu/:/lib/../lib/:/usr/lib/aarch64-linux-gnu/13/:/usr/lib/aarch64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../:/lib/:/usr/lib/

binutils:汇编&链接和二进制工具
#

安装的包:

alizj@ubuntu:~$ apt list --installed binutils*
binutils-aarch64-linux-gnu/noble-updates,noble-security,now 2.42-4ubuntu2.3 arm64 [installed,automatic]
binutils-common/noble-updates,noble-security,now 2.42-4ubuntu2.3 arm64 [installed,automatic]
binutils-x86-64-linux-gnu/noble-updates,noble-security,now 2.42-4ubuntu2.3 arm64 [installed,automatic]
binutils/noble-updates,noble-security,now 2.42-4ubuntu2.3 arm64 [installed,automatic]
binutils-dev/noble-updates,noble-security 2.42-4ubuntu2.3 arm64

提供的二进制工具,它们可以对 ELF 文件进行操作:

  1. as:汇编器;
  2. ld/ld.bfd/ld.gold :链接器及链接脚本;
  3. gprof/gprofng/addr2line
  4. ar:静态库惯例工具
  5. elfedit/readelf/ranlib
  6. objcopy/objdump/nm/addr2line
  7. size/strings/strip

binutils 还提供了 bfd 头文件和库文件,用于解析、反汇编 ELF 文件。

alizj@ubuntu:~$ dpkg -L binutils|sort
...
/usr/bin/addr2line
/usr/bin/ar
/usr/bin/as
/usr/bin/c++filt
/usr/bin/dwp
/usr/bin/elfedit
/usr/bin/gold
/usr/bin/gp-archive
/usr/bin/gp-collect-app
/usr/bin/gp-display-html
/usr/bin/gp-display-src
/usr/bin/gp-display-text
/usr/bin/gprof
/usr/bin/gprofng
/usr/bin/ld
/usr/bin/ld.bfd
/usr/bin/ld.gold
/usr/bin/nm
/usr/bin/objcopy
/usr/bin/objdump
/usr/bin/ranlib
/usr/bin/readelf
/usr/bin/size
/usr/bin/strings
/usr/bin/strip
# 链接器
/usr/lib/compat-ld
/usr/lib/compat-ld/ld
/usr/lib/gold-ld
/usr/lib/gold-ld/ld
...

alizj@ubuntu:~$ dpkg -L binutils-aarch64-linux-gnu | sort
/.
/usr
/usr/bin
/usr/bin/aarch64-linux-gnu-addr2line
/usr/bin/aarch64-linux-gnu-ar
/usr/bin/aarch64-linux-gnu-as
/usr/bin/aarch64-linux-gnu-c++filt
/usr/bin/aarch64-linux-gnu-dwp
/usr/bin/aarch64-linux-gnu-elfedit
/usr/bin/aarch64-linux-gnu-gold
/usr/bin/aarch64-linux-gnu-gp-archive
/usr/bin/aarch64-linux-gnu-gp-collect-app
/usr/bin/aarch64-linux-gnu-gp-display-html
/usr/bin/aarch64-linux-gnu-gp-display-src
/usr/bin/aarch64-linux-gnu-gp-display-text
/usr/bin/aarch64-linux-gnu-gprof
/usr/bin/aarch64-linux-gnu-gprofng
/usr/bin/aarch64-linux-gnu-ld
/usr/bin/aarch64-linux-gnu-ld.bfd
/usr/bin/aarch64-linux-gnu-ld.gold
/usr/bin/aarch64-linux-gnu-nm
/usr/bin/aarch64-linux-gnu-objcopy
/usr/bin/aarch64-linux-gnu-objdump
/usr/bin/aarch64-linux-gnu-ranlib
/usr/bin/aarch64-linux-gnu-readelf
/usr/bin/aarch64-linux-gnu-size
/usr/bin/aarch64-linux-gnu-strings
/usr/bin/aarch64-linux-gnu-strip
...
/usr/lib/aarch64-linux-gnu/bfd-plugins
/usr/lib/aarch64-linux-gnu/bfd-plugins/libdep.so
# 各种架构的链接脚本
/usr/lib/aarch64-linux-gnu/ldscripts
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64elf32b.x
...
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linuxb.xwe
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linux.x
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linux.xbn
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linux.xc
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linux.xce
/usr/lib/aarch64-linux-gnu/ldscripts/aarch64linux.xd
...
/usr/lib/aarch64-linux-gnu/ldscripts/stamp
...

# bfd 头文件和 libbfd 库文件
alizj@ubuntu:~$ dpkg -L binutils-dev | sort
...
/usr/include/ansidecl.h
/usr/include/bfd.h
/usr/include/bfdlink.h
/usr/include/collectorAPI.h
/usr/include/ctf-api.h
/usr/include/ctf.h
/usr/include/diagnostics.h
/usr/include/dis-asm.h
/usr/include/libcollector.h
/usr/include/libfcollector.h
/usr/include/plugin-api.h
/usr/include/sframe-api.h
/usr/include/sframe.h
/usr/include/symcat.h
...
/usr/lib/aarch64-linux-gnu/libbfd.a
/usr/lib/aarch64-linux-gnu/libbfd_pic.a
/usr/lib/aarch64-linux-gnu/libbfd.so
/usr/lib/aarch64-linux-gnu/libctf.a
/usr/lib/aarch64-linux-gnu/libctf-nobfd.a
/usr/lib/aarch64-linux-gnu/libctf-nobfd.so
/usr/lib/aarch64-linux-gnu/libctf.so
/usr/lib/aarch64-linux-gnu/libgprofng.a
/usr/lib/aarch64-linux-gnu/libgprofng.so
/usr/lib/aarch64-linux-gnu/libopcodes.a
/usr/lib/aarch64-linux-gnu/libopcodes_pic.a
/usr/lib/aarch64-linux-gnu/libopcodes.so
/usr/lib/aarch64-linux-gnu/libsframe.a
/usr/lib/aarch64-linux-gnu/libsframe.so

binutils 提供两种类型链接器: bfd(默认) 和 gold,另外两种常用的链接器分别是 lld 和 mold。

alizj@lima-dev2:~$ dpkg -S /usr/bin/ld*
binutils: /usr/bin/ld
binutils: /usr/bin/ld.bfd
binutils: /usr/bin/ld.gold
libc-bin: /usr/bin/ld.so
libc-bin: /usr/bin/ldd

alizj@ubuntu:~$ ls -l /usr/bin/ld
lrwxrwxrwx 1 root root 20 Aug  7 18:15 /usr/bin/ld -> aarch64-linux-gnu-ld
alizj@ubuntu:~$ ls -l /usr/bin/aarch64-linux-gnu-ld
lrwxrwxrwx 1 root root 24 Aug  7 18:15 /usr/bin/aarch64-linux-gnu-ld -> aarch64-linux-gnu-ld.bfd
alizj@ubuntu:~$ ls -l /usr/bin/aarch64-linux-gnu-ld.bfd
-rwxr-xr-x 1 root root 1710520 Aug  7 18:15 /usr/bin/aarch64-linux-gnu-ld.bfd

gcc 和 binutils 都提供了 ar/nm 等二进制工具,但前缀不同,系统默认使用的是 binutils 提供的版本:

alizj@ubuntu:~$ dpkg -S /usr/bin/aarch64-linux-gnu-*nm*
gcc-aarch64-linux-gnu: /usr/bin/aarch64-linux-gnu-gcc-nm
gcc-13-aarch64-linux-gnu: /usr/bin/aarch64-linux-gnu-gcc-nm-13
binutils-aarch64-linux-gnu: /usr/bin/aarch64-linux-gnu-nm

alizj@ubuntu:~$ which ar
/usr/bin/ar
alizj@ubuntu:~$ ls -l /usr/bin/ar
lrwxrwxrwx 1 root root 20 Aug  7 18:15 /usr/bin/ar -> aarch64-linux-gnu-ar
alizj@ubuntu:~$ dpkg -S /usr/bin/aarch64-linux-gnu-ar
binutils-aarch64-linux-gnu: /usr/bin/aarch64-linux-gnu-ar

libc 和动态链接器
#

libc 涉及的包:

  • libc-bin:提供 ldd 动态库链接器,locale、tzselect 等国际化支持;
  • libc-dev-bin:仅提供 gencat 命令;
  • libc-devtools:提供 memusage、mtrace、sprof 等不常用的内存分析命令;
  • libc6-dbg: libc 库 debuginfo 调试符号;
  • libc6-dev: libc 库标准头文件和 libc.a 静态库文件;
  • libc6:glibc 库;
  • linux-libc-dev:提供给 libc 使用的内核头文件
alizj@ubuntu:~$ sudo apt list |grep libc |grep installed |grep -v x86 |grep -v amd64
glibc-source/noble-updates,noble-security,noble-updates,noble-security,now 2.39-0ubuntu8.3 all [installed]
libc-bin/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed]
libc-dev-bin/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed,automatic]
libc-devtools/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed,automatic]
libc6-dbg/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed]
libc6-dev/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed,automatic]
libc6/noble-updates,noble-security,now 2.39-0ubuntu8.3 arm64 [installed]
linux-libc-dev/noble-updates,noble-security,now 6.8.0-52.53 arm64 [installed,automatic]

glibc 是架构相关的,位于 /usr/lib/ 目录下,如 /usr/lib/aarch64-linux-gnu 或 /usr/lib/x86_64-linux-gnu。

glibc 标准头文件位于 /usr/include/aarch64-linux-gnu 和 /usr/include 目录下;

root@lima-dev2:/home/alizj.linux# dpkg -L libc6
# libc 动态链接器配置
/etc/ld.so.conf.d
/etc/ld.so.conf.d/aarch64-linux-gnu.conf

# 架构相关的 libc 库目录
/lib/aarch64-linux-gnu
/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1  #动态链接器
/lib/aarch64-linux-gnu/libBrokenLocale.so.1
/lib/aarch64-linux-gnu/libanl.so.1
# GNU glibc 库
/lib/aarch64-linux-gnu/libc.so.6
/lib/aarch64-linux-gnu/libc_malloc_debug.so.0
/lib/aarch64-linux-gnu/libdl.so.2
/lib/aarch64-linux-gnu/libm.so.6
/lib/aarch64-linux-gnu/libmemusage.so
/lib/aarch64-linux-gnu/libmvec.so.1
/lib/aarch64-linux-gnu/libnsl.so.1
/lib/aarch64-linux-gnu/libnss_compat.so.2
/lib/aarch64-linux-gnu/libnss_dns.so.2
/lib/aarch64-linux-gnu/libnss_files.so.2
/lib/aarch64-linux-gnu/libnss_hesiod.so.2
/lib/aarch64-linux-gnu/libpcprofile.so
/lib/aarch64-linux-gnu/libpthread.so.0
/lib/aarch64-linux-gnu/libresolv.so.2
/lib/aarch64-linux-gnu/librt.so.1
/lib/aarch64-linux-gnu/libthread_db.so.1
/lib/aarch64-linux-gnu/libutil.so.1

alizj@lima-dev2:~$ dpkg -L libc6-dev
...
/usr/include/aarch64-linux-gnu/a.out.h
/usr/include/aarch64-linux-gnu/bits
/usr/include/aarch64-linux-gnu/bits/a.out.h
/usr/include/aarch64-linux-gnu/bits/argp-ldbl.h
/usr/include/aarch64-linux-gnu/bits/atomic_wide_counter.h
/usr/include/aarch64-linux-gnu/bits/wchar2.h
/usr/include/aarch64-linux-gnu/bits/wctype-wchar.h
/usr/include/aarch64-linux-gnu/bits/wordsize.h
/usr/include/aarch64-linux-gnu/bits/xopen_lim.h
/usr/include/aarch64-linux-gnu/fpu_control.h
/usr/include/aarch64-linux-gnu/gnu
/usr/include/aarch64-linux-gnu/gnu/lib-names-lp64.h
/usr/include/aarch64-linux-gnu/gnu/lib-names.h
/usr/include/aarch64-linux-gnu/gnu/libc-version.h
/usr/include/aarch64-linux-gnu/gnu/stubs-lp64.h
/usr/include/aarch64-linux-gnu/gnu/stubs.h
/usr/include/aarch64-linux-gnu/ieee754.h
/usr/include/aarch64-linux-gnu/sys
/usr/include/aarch64-linux-gnu/sys/acct.h
/usr/include/aarch64-linux-gnu/sys/auxv.h
/usr/include/aarch64-linux-gnu/sys/bitypes.h
/usr/include/aarch64-linux-gnu/sys/cdefs.h
/usr/include/aarch64-linux-gnu/sys/dir.h
#...
/usr/include/aio.h
/usr/include/aliases.h
/usr/include/alloca.h
/usr/include/fcntl.h
/usr/include/features-time64.h
/usr/include/features.h
/usr/include/wchar.h
/usr/include/wctype.h
/usr/include/wordexp.h
...
/usr/lib/aarch64-linux-gnu/Mcrt1.o
/usr/lib/aarch64-linux-gnu/Scrt1.o
/usr/lib/aarch64-linux-gnu/audit
/usr/lib/aarch64-linux-gnu/audit/sotruss-lib.so
/usr/lib/aarch64-linux-gnu/crt1.o
/usr/lib/aarch64-linux-gnu/crti.o
/usr/lib/aarch64-linux-gnu/crtn.o
/usr/lib/aarch64-linux-gnu/gcrt1.o
/usr/lib/aarch64-linux-gnu/grcrt1.o
/usr/lib/aarch64-linux-gnu/libBrokenLocale.a
/usr/lib/aarch64-linux-gnu/libanl.a
/usr/lib/aarch64-linux-gnu/libc.a             # glibc 静态库和动态库
/usr/lib/aarch64-linux-gnu/libc.so
/usr/lib/aarch64-linux-gnu/libc_nonshared.a
/usr/lib/aarch64-linux-gnu/libdl.a
/usr/lib/aarch64-linux-gnu/libg.a
/usr/lib/aarch64-linux-gnu/libm-2.38.a
/usr/lib/aarch64-linux-gnu/libm.a
/usr/lib/aarch64-linux-gnu/libm.so
/usr/lib/aarch64-linux-gnu/libmcheck.a
/usr/lib/aarch64-linux-gnu/libmvec.a
/usr/lib/aarch64-linux-gnu/libpthread.a
/usr/lib/aarch64-linux-gnu/libpthread_nonshared.a
/usr/lib/aarch64-linux-gnu/libresolv.a
/usr/lib/aarch64-linux-gnu/librt.a
/usr/lib/aarch64-linux-gnu/libutil.a
/usr/lib/aarch64-linux-gnu/rcrt1.o
/usr/lib/aarch64-linux-gnu/libBrokenLocale.so
/usr/lib/aarch64-linux-gnu/libanl.so
/usr/lib/aarch64-linux-gnu/libc_malloc_debug.so
/usr/lib/aarch64-linux-gnu/libmvec.so
/usr/lib/aarch64-linux-gnu/libnss_compat.so
/usr/lib/aarch64-linux-gnu/libnss_hesiod.so
/usr/lib/aarch64-linux-gnu/libresolv.so
/usr/lib/aarch64-linux-gnu/libthread_db.so

root@lima-dev2:/home/alizj.linux# dpkg -L libc-bin
/.
/etc
/etc/bindresvport.blacklist
/etc/gai.conf
/etc/ld.so.conf
/etc/ld.so.conf.d
/etc/ld.so.conf.d/libc.conf # libc 动态库加载配置

/sbin
/sbin/ldconfig  # 动态加载配置命令
/sbin/ldconfig.real

/usr
/usr/bin
/usr/bin/getconf
/usr/bin/getent
/usr/bin/iconv
/usr/bin/ldd    # 打印动态库对象的依赖
/usr/bin/locale # 国际化
/usr/bin/localedef
/usr/bin/pldd
/usr/bin/tzselect
/usr/bin/zdump


/usr/lib/locale  # locale 数据库
/usr/lib/locale/C.utf8
/usr/lib/locale/C.utf8/LC_ADDRESS
/usr/lib/locale/C.utf8/LC_COLLATE
/usr/lib/locale/C.utf8/LC_CTYPE

/var/cache/ldconfig  # 动态链接器缓存
/usr/bin/ld.so  # 动态链接器


# linux-libc-dev: glibc 使用的内核头文件
root@lima-dev2:/home/alizj.linux# dpkg -L linux-libc-dev
/.
/usr
/usr/include
/usr/include/aarch64-linux-gnu  # 架构相关的头文件
/usr/include/aarch64-linux-gnu/asm
/usr/include/aarch64-linux-gnu/asm/auxvec.h
/usr/include/aarch64-linux-gnu/asm/bitsperlong.h
/usr/include/aarch64-linux-gnu/asm/bpf_perf_event.h
/usr/include/aarch64-linux-gnu/asm/byteorder.h
/usr/include/aarch64-linux-gnu/asm/errno.h
/usr/include/aarch64-linux-gnu/asm/fcntl.h
/usr/include/aarch64-linux-gnu/asm/hwcap.h
/usr/include/aarch64-linux-gnu/asm/ioctl.h
/usr/include/aarch64-linux-gnu/asm/ioctls.h
/usr/include/aarch64-linux-gnu/asm/ipcbuf.h
#...
/usr/include/aarch64-linux-gnu/asm/unistd.h

/usr/include/asm-generic  # 架构无关(通用)的头文件
/usr/include/asm-generic/auxvec.h
/usr/include/asm-generic/bitsperlong.h
/usr/include/asm-generic/bpf_perf_event.h
#...
/usr/include/asm-generic/unistd.h

/usr/include/drm
/usr/include/drm/amdgpu_drm.h
/usr/include/drm/armada_drm.h
/usr/include/drm/drm.h
/usr/include/linux  # 通用内核头文件
/usr/include/linux/acct.h
/usr/include/linux/xilinx-v4l2-controls.h
/usr/include/linux/zorro.h
/usr/include/linux/zorro_ids.h
#...

libc 库类型
#

libc 库封装了所有 POSIX 系统调用,是用户程序与 Kernel 的接口,在编译 glibc 时,需要提供对应版本的内核头文件。

libc 库有多种实现类型:

  1. glibc:通用;
  2. musl libc:也是通用的 libc,但是更轻量,在轻量化容器镜像中得到广泛应用:https://musl.libc.org/
  3. uClibc/uClibc-ng:嵌入式优化的 libc 库:https://uclibc-ng.org/
  4. newlib:嵌入式优化的 libc 库:https://sourceware.org/newlib/

交叉编译工具链
#

ubuntu aarch64 -> x86_64 交叉静态编译
#

根据经验,ubuntu 对多架构交叉编译的支持比 centos、fedora 更成熟,后者需要 hack gcc 交叉编译工具链的 sysroot 参数。

在 ubuntu aarch64 架构机器上交叉编译出 x86_64 架构静态二进制方案:

# arm64 虚机上,为 CGO 程序交叉编译生成 amd64 程序报错
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o myagent ./cmd/
runtime/cgo
gcc: error: unrecognized command-line option '-m64'

# 这是由于安装的 ubuntu 安装的 gcc 只支持编译生成 arm64 架构的二进制,而不支持交叉编译生成 amd64 架构的二进制。

# 启用多架构
$ sudo dpkg --add-architecture amd64

# 添加 amd64 架构源
$ cat /etc/apt/sources.list
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble main restricted universe multiverse
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-updates main restricted universe multiverse
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports noble-security main restricted universe multiverse
deb [arch=amd64] http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb [arch=amd64] http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
deb [arch=amd64] http://archive.ubuntu.com/ubuntu noble-security main restricted universe multiverse

# 安装 amd64 架构的 libc 库
sudo apt update
sudo apt install libc6:amd64

# 安装可以生成 amd64 架构的 gcc 交叉编译工具链
$ sudo apt install gcc-x86-64-linux-gnu

$ file /usr/bin/x86_64-linux-gnu-gcc
/usr/bin/x86_64-linux-gnu-gcc: symbolic link to x86_64-linux-gnu-gcc-13

$ file /usr/bin/x86_64-linux-gnu-gcc-13
/usr/bin/x86_64-linux-gnu-gcc-13: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=ad41a19a0955b7e6770ad00ff5cd9b97999b2f0e, for GNU/Linux 3.7.0, stripped

# 启用 CGO 的情况下,交叉编译静态链接成功
$ CC=x86_64-linux-gnu-gcc GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags 'osusergo netgo sqlite_omit_load_extension no_dynamic_plugins' -o myagent -ldflags=" -extldflags '-static'" ./cmd/

fedora 40 x86_64 -> aarch64 交叉静态编译
#

类似的,以 fedora40 x86_64 编译环境为例(CentOS、RHEL 类似),如果要编译出 arm64 架构的静态二进制,需要先安装 gcc-aarch64 编译工具链,在 go build 时使用 CC 环境变量来指定使用该工具链。

同时还要安装 sysroot-aarch64-fc40-glibc 包,它为交叉编译提供了 glibc 标准库头文件和静态 glibc 库支持(大坑,卡了很久才解决),通过 CGO_LDFLAGS 环境变量的 –sysroot 参数传递给交叉编译工具链,参考:

yum install -y glibc-devel glibc-static gcc

# 在 x86_64 环境中,可以直接编译出 x86_64 架构二进制
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags 'osusergo netgo sqlite_omit_load_extension no_dynamic_plugins' -o myagent -ldflags=" -extldflags '-static'" ./cmd/

# 交叉编译 arm64 架构的二进制失败,这是由于  x86_64 gcc 不支持汇编 arm64 指令
[root@d8e784ed1d22 bp-agent]# GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -tags 'osusergo netgo sqlite_omit_load_extension no_dynamic_plugins' -buildmode=exe -o bp-agent -ldflags=" -extldflags '-static'" ./cmd/
# runtime/cgo
gcc_arm64.S: Assembler messages:
gcc_arm64.S:30: Error: no such instruction: `stp x29,x30,[sp,'
gcc_arm64.S:34: Error: operand size mismatch for `mov'
gcc_arm64.S:36: Error: no such instruction: `stp x19,x20,[sp,'
gcc_arm64.S:39: Error: no such instruction: `stp x21,x22,[sp,'
gcc_arm64.S:42: Error: no such instruction: `stp x23,x24,[sp,'
gcc_arm64.S:45: Error: no such instruction: `stp x25,x26,[sp,'
gcc_arm64.S:48: Error: no such instruction: `stp x27,x28,[sp,'
gcc_arm64.S:52: Error: operand size mismatch for `mov'
gcc_arm64.S:53: Error: operand size mismatch for `mov'
gcc_arm64.S:54: Error: operand size mismatch for `mov'
gcc_arm64.S:56: Error: no such instruction: `blr x20'
gcc_arm64.S:57: Error: no such instruction: `blr x19'
gcc_arm64.S:59: Error: no such instruction: `ldp x27,x28,[sp,'
gcc_arm64.S:62: Error: no such instruction: `ldp x25,x26,[sp,'
gcc_arm64.S:65: Error: no such instruction: `ldp x23,x24,[sp,'
gcc_arm64.S:68: Error: no such instruction: `ldp x21,x22,[sp,'
gcc_arm64.S:71: Error: no such instruction: `ldp x19,x20,[sp,'
gcc_arm64.S:74: Error: no such instruction: `ldp x29,x30,[sp],'

# 安装支持交叉编译的 arm64 架构的编译工具链
yum install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu gcc-c++-aarch64-linux-gnu;

# 编译失败,提示找不到 stdlib.h 库
[root@d8e784ed1d22 bp-agent]# CC=aarch64-linux-gnu-gcc GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -tags 'osusergo netgo sqlite_omit_load_extension no_dynamic_plugins' -o myagent -ldflags=" -extldflags '-static'" ./cmd/
# runtime/cgo
_cgo_export.c:3:10: fatal error: stdlib.h: No such file or directory
    3 | #include <stdlib.h>
      |          ^~~~~~~~~~
compilation terminated.

# 查看 aarch64-linux-gnu-gcc 编译器配置参数
[root@d8e784ed1d22 bp-agent]# aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/aarch64-linux-gnu/14/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../gcc-14.1.1-20240508/configure --bindir=/usr/bin --build=x86_64-redhat-linux-gnu --datadir=/usr/share --disable-decimal-float --disable-dependency-tracking --disable-gold --disable-libgcj --disable-libgomp --disable-libmpx --disable-libquadmath --disable-libssp --disable-libunwind-exceptions --disable-shared --disable-silent-rules --disable-sjlj-exceptions --disable-threads --with-ld=/usr/bin/aarch64-linux-gnu-ld --enable-__cxa_atexit --enable-checking=release --enable-gnu-unique-object --enable-initfini-array --enable-languages=c,c++ --enable-linker-build-id --enable-lto --enable-nls --enable-obsolete --enable-plugin --enable-targets=all --exec-prefix=/usr --host=x86_64-redhat-linux-gnu --includedir=/usr/include --infodir=/usr/share/info --libexecdir=/usr/libexec --localstatedir=/var --mandir=/usr/share/man --prefix=/usr --program-prefix=aarch64-linux-gnu- --sbindir=/usr/sbin --sharedstatedir=/var/lib --sysconfdir=/etc --target=aarch64-linux-gnu --with-bugurl=http://bugzilla.redhat.com/bugzilla/ --with-gcc-major-version-only --with-isl --with-newlib --with-plugin-ld=/usr/bin/aarch64-linux-gnu-ld --with-sysroot=/usr/aarch64-linux-gnu/sys-root --with-system-libunwind --with-system-zlib --without-headers --enable-gnu-indirect-function --with-linker-hash-style=gnu
Thread model: single
Supported LTO compression algorithms: zlib zstd
gcc version 14.1.1 20240507 (Red Hat Cross 14.1.1-1) (GCC)

# --with-sysroot=/usr/aarch64-linux-gnu/sys-root 目录为空:
[root@d8e784ed1d22 bp-agent]# ls /usr/aarch64-linux-gnu/bin/
ar  as  ld  ld.bfd  nm  objcopy  objdump  ranlib  readelf  strip
[root@d8e784ed1d22 bp-agent]# ls /usr/aarch64-linux-gnu/sys-root/
[root@d8e784ed1d22 bp-agent]#

# 安装 aarch64 对应的 sysroot 包 sysroot-aarch64-fc40-glibc.noarch,它提供了交叉编译所需的 glibc 头文件和静态库
[root@d8e784ed1d22 bp-agent]# yum install sysroot-aarch64-fc40-glibc.noarch
[root@d8e784ed1d22 bp-agent]# ls /usr/aarch64-redhat-linux/sys-root/fc40/usr/
include  lib  lib64

# 使用 CGO_CFLAGS 环境变量为交叉编译 gcc 指定 --sysroot 参数,来使用安装的 aarch64 的 glibc 头文件和静态库,
# 同时使用 CC 环境变量指定使用该工具链来编译 CGO 链接的 C 程序
[root@d8e784ed1d22 bp-agent]# CC=aarch64-linux-gnu-gcc CGO_CFLAGS="-g -O2 --sysroot=/usr/aarch64-redhat-linux/sys-root/fc40" CGO_LDFLAGS="-g -O2 --sysroot=/usr/aarch64-redhat-linux/sys-root/fc40"  GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -x -tags 'osusergo netgo sqlite_omit_load_extension no_dynamic_plugins' -o myagent -ldflags=" -extldflags '-static'" ./cmd/

[root@d8e784ed1d22 bp-agent]# file myagent
myagent: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=90ac14fe0ac828b0defb3ae4e3c328a589948a8c, for GNU/Linux 3.7.0, with debug_info, not stripped

[root@d8e784ed1d22 bp-agent]# ldd myagent
        not a dynamic executable

编译工具链目录分析
#

Host 架构工具链
#

ubuntu host aarch64 架构编译器,库文件搜索路径如下:

  • /usr/libexec/gcc/aarch64-linux-gnu/13/
    • 保存 gcc 内部调用的二进制,如 cc1,collect2 等
  • /usr/lib/gcc/aarch64-linux-gnu/13/
    • 保存 gcc 自身使用的库,引用 /usr/lib/aarch64-linux-gnu 下的动态库,如 libatomic.so/libcc1.so 等
  • /usr/aarch64-linux-gnu/bin/aarch64-linux-gnu/13/,/usr/aarch64-linux-gnu/bin/,/usr/aarch64-linux-gnu/lib/aarch64-linux-gnu/13
    • NO, 目录不存在。
  • /usr/aarch64-linux-gnu/lib
    • NO, 目录不存在。
  • /usr/lib/aarch64-linux-gnu/
    • 系统标准库目录,放到 /usr/lib/ 目录下,而非以前的 /usr/lib 目录。
  • /lib,/usr/lib

/lib, /usr/lib, /usr/libexec 都是 Host 架构库,其它架构的库位于 /usr/ 目录下。

ubuntu 不再提供 /lib64 和 /usr/lib64 目录, /bin, /sbin, /lib 都指向 /usr 下对应目录。

root@lima-dev2:~# ls -l /
total 68
...
lrwxrwxrwx   1 root root     7 Mar  7  2024 bin -> usr/bin
lrwxrwxrwx   1 root root     7 Mar  7  2024 lib -> usr/lib
lrwxrwxrwx   1 root root     8 Mar  7  2024 sbin -> usr/sbin
...

root@lima-dev2:~# ls -l /usr/
total 88
drwxr-xr-x   2 root root 36864 Oct 14 18:09 bin
drwxr-xr-x   2 root root  4096 Oct 10  2023 games
drwxr-xr-x  45 root root  4096 Oct  8 12:27 include
drwxr-xr-x  90 root root  4096 Oct 14 18:09 lib
drwxr-xr-x  12 root root  4096 Oct 14 18:09 libexec
drwxr-xr-x  11 root root  4096 Jun 20 12:28 local
drwxr-xr-x   2 root root 20480 Oct  9 13:37 sbin
drwxr-xr-x 135 root root  4096 Oct 11 15:57 share
drwxr-xr-x   7 root root  4096 Jul 14 06:21 src
drwxr-xr-x   8 root root  4096 Oct 14 18:09 x86_64-linux-gnu # 其它架构(交叉编译工具链)的根目录

# Host 架构的 libc 等标准库不再放到 `/usr/lib` 目录下,而是放到 Host 架构的 `/usr/lib/aarch64-linux-gnu` 目录下:
root@lima-dev2:~# ls -l /usr/lib/libc*
ls: cannot access '/usr/lib/libc*': No such file or directory
root@lima-dev2:~# ls -l /usr/lib/aarch64-linux-gnu/libc.so.6
-rwxr-xr-x 1 root root 1722984 May  1 02:11 /usr/lib/aarch64-linux-gnu/libc.so.6

ubuntu host aarch64 架构编译器,头文件搜索路径如下:

  • /usr/include/aarch64-linux-gnu/ 和 /usr/lib/gcc/aarch64-linux-gnu/13/include : gcc 自身定义和使用的头文件目录
  • /usr/include: 系统标准头文件目录
alizj@ubuntu:~$ ls -l /usr/lib/gcc/aarch64-linux-gnu/13/
total 24024
-rw-r--r-- 1 root root    3280 Sep  4 22:44 crtbegin.o
-rw-r--r-- 1 root root    3656 Sep  4 22:44 crtbeginS.o
-rw-r--r-- 1 root root    3832 Sep  4 22:44 crtbeginT.o
-rw-r--r-- 1 root root    1416 Sep  4 22:44 crtend.o
-rw-r--r-- 1 root root    1416 Sep  4 22:44 crtendS.o
-rw-r--r-- 1 root root    3928 Sep  4 22:44 crtfastmath.o
-rw-r--r-- 1 root root    1416 Sep  4 22:44 crtoffloadbegin.o
-rw-r--r-- 1 root root    1408 Sep  4 22:44 crtoffloadend.o
-rw-r--r-- 1 root root    1648 Sep  4 22:44 crtoffloadtable.o
drwxr-xr-x 1 root root     524 Jan 15 00:42 include
-rw-r--r-- 1 root root 3369448 Sep  4 22:44 libasan.a
-rw-r--r-- 1 root root   14848 Sep  4 22:44 libasan_preinit.o
lrwxrwxrwx 1 root root      39 Sep  4 22:44 libasan.so -> ../../../aarch64-linux-gnu/libasan.so.8
-rw-r--r-- 1 root root  208618 Sep  4 22:44 libatomic.a
lrwxrwxrwx 1 root root      41 Sep  4 22:44 libatomic.so -> ../../../aarch64-linux-gnu/libatomic.so.1
-rw-r--r-- 1 root root  107738 Sep  4 22:44 libbacktrace.a
lrwxrwxrwx 1 root root      38 Sep  4 22:44 libcc1.so -> ../../../aarch64-linux-gnu/libcc1.so.0
-rw-r--r-- 1 root root 3099922 Sep  4 22:44 libgcc.a
-rw-r--r-- 1 root root   53884 Sep  4 22:44 libgcc_eh.a
-rw-r--r-- 1 root root     132 Sep  4 22:44 libgcc_s.so
-rw-r--r-- 1 root root   72562 Sep  4 22:44 libgcov.a
-rw-r--r-- 1 root root  620414 Sep  4 22:44 libgomp.a
lrwxrwxrwx 1 root root      39 Sep  4 22:44 libgomp.so -> ../../../aarch64-linux-gnu/libgomp.so.1
-rw-r--r-- 1 root root     164 Sep  4 22:44 libgomp.spec
-rw-r--r-- 1 root root 1201118 Sep  4 22:44 libhwasan.a
-rw-r--r-- 1 root root    6440 Sep  4 22:44 libhwasan_preinit.o
lrwxrwxrwx 1 root root      41 Sep  4 22:44 libhwasan.so -> ../../../aarch64-linux-gnu/libhwasan.so.0
-rw-r--r-- 1 root root  221010 Sep  4 22:44 libitm.a
lrwxrwxrwx 1 root root      38 Sep  4 22:44 libitm.so -> ../../../aarch64-linux-gnu/libitm.so.1
-rw-r--r-- 1 root root     162 Sep  4 22:44 libitm.spec
-rw-r--r-- 1 root root 1175204 Sep  4 22:44 liblsan.a
-rw-r--r-- 1 root root    6264 Sep  4 22:44 liblsan_preinit.o
lrwxrwxrwx 1 root root      39 Sep  4 22:44 liblsan.so -> ../../../aarch64-linux-gnu/liblsan.so.0
lrwxrwxrwx 1 root root      61 Sep  4 22:44 liblto_plugin.so -> ../../../../libexec/gcc/aarch64-linux-gnu/13/liblto_plugin.so
-rw-r--r-- 1 root root  673462 Sep  4 22:44 libobjc.a
-rw-r--r-- 1 root root  701550 Sep  4 22:44 libobjc_gc.a
lrwxrwxrwx 1 root root      42 Sep  4 22:44 libobjc_gc.so -> ../../../aarch64-linux-gnu/libobjc_gc.so.4
lrwxrwxrwx 1 root root      39 Sep  4 22:44 libobjc.so -> ../../../aarch64-linux-gnu/libobjc.so.4
-rw-r--r-- 1 root root     362 Sep  4 22:44 libsanitizer.spec
-rw-r--r-- 1 root root    1534 Sep  4 22:44 libssp_nonshared.a
-rw-r--r-- 1 root root 6915858 Sep  4 22:44 libstdc++.a
-rw-r--r-- 1 root root  950348 Sep  4 22:44 libstdc++exp.a
-rw-r--r-- 1 root root  748174 Sep  4 22:44 libstdc++fs.a
lrwxrwxrwx 1 root root      14 Sep  4 22:44 libstdc++_libbacktrace.a -> libstdc++exp.a
lrwxrwxrwx 1 root root      41 Sep  4 22:44 libstdc++.so -> ../../../aarch64-linux-gnu/libstdc++.so.6
-rw-r--r-- 1 root root  422436 Sep  4 22:44 libsupc++.a
-rw-r--r-- 1 root root 2801138 Sep  4 22:44 libtsan.a
-rw-r--r-- 1 root root    4912 Sep  4 22:44 libtsan_preinit.o
lrwxrwxrwx 1 root root      39 Sep  4 22:44 libtsan.so -> ../../../aarch64-linux-gnu/libtsan.so.2
-rw-r--r-- 1 root root 1065066 Sep  4 22:44 libubsan.a
lrwxrwxrwx 1 root root      40 Sep  4 22:44 libubsan.so -> ../../../aarch64-linux-gnu/libubsan.so.1

# gcc 提供的头文件 /usr/include/aarch64-linux-gnu/
alizj@ubuntu:~$ ls -l /usr/include/aarch64-linux-gnu/
total 48
-rw-r--r-- 1 root root  4351 Aug  8 22:47 a.out.h
drwxr-xr-x 1 root root   644 Jan 14 23:55 asm
drwxr-xr-x 1 root root  4188 Jan 14 23:55 bits
drwxr-xr-x 1 root root     4 Jan 14 23:55 c++
-rw-r--r-- 1 root root  4251 Dec  2 04:52 expat_config.h
-rw-r--r-- 1 root root 14041 Apr  9  2024 ffi.h
-rw-r--r-- 1 root root  2748 Apr  9  2024 ffitarget.h
-rw-r--r-- 1 root root  3006 Aug  8 22:47 fpu_control.h
drwxr-xr-x 1 root root   120 Jan 14 23:55 gnu
-rw-r--r-- 1 root root  4430 Aug  8 22:47 ieee754.h
drwxr-xr-x 1 root root    56 Jan 14 23:55 openssl
drwxr-xr-x 1 root root    20 Jan 14 23:56 python3.12
drwxr-xr-x 1 root root  1190 Jan 14 23:55 sys

# 系统标准库 /usr/lib/aarch64-linux-gnu/
alizj@ubuntu:~$ ls  -l /usr/lib/aarch64-linux-gnu/lib[cm].so
-rw-r--r-- 1 root root 291 Aug  8 22:47 /usr/lib/aarch64-linux-gnu/libc.so
-rw-r--r-- 1 root root 149 Aug  8 22:47 /usr/lib/aarch64-linux-gnu/libm.so
alizj@ubuntu:~$ ls  -l /usr/lib/aarch64-linux-gnu/lib[cm].a
-rw-r--r-- 1 root root 5247070 Aug  8 22:47 /usr/lib/aarch64-linux-gnu/libc.a
-rw-r--r-- 1 root root     141 Aug  8 22:47 /usr/lib/aarch64-linux-gnu/libm.a
alizj@ubuntu:~$ ls  -ld /usr/lib/aarch64-linux-gnu/ld*
-rwxr-xr-x 1 root root 203968 Aug  8 22:47 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
drwxr-xr-x 1 root root   8490 Jan 14 23:55 /usr/lib/aarch64-linux-gnu/ldscripts

Fedorat 40 Host 架构 x86_64-redhat-linux 的差异:

  • 还提供 /lib64 目录,但是指向 /usr/lib64;
  • 标准库 libc 位于 /usr/lib64 目录下;
  • 其它架构的标准库位于 /usr/aarch64-redhat-linux/sys-root/fc40/usr/lib64/ 目录下
    • 需要单独安装包 sysroot-aarch64-fc40-glibc-2.39-33.fc40.noarch
[root@d8e784ed1d22 ~]# ls -l /{bin,sbin,lib,lib64}
lrwxrwxrwx 1 root root 7 Jan 24  2024 /bin -> usr/bin
lrwxrwxrwx 1 root root 7 Jan 24  2024 /lib -> usr/lib
lrwxrwxrwx 1 root root 9 Jan 24  2024 /lib64 -> usr/lib64
lrwxrwxrwx 1 root root 8 Jan 24  2024 /sbin -> usr/sbin

[root@d8e784ed1d22 ~]# ls -l /usr/lib64/libc.*
-rw-r--r-- 1 root root 6847798 Dec 23 00:00 /usr/lib64/libc.a
-rw-r--r-- 1 root root     253 Dec 23 00:00 /usr/lib64/libc.so
-rwxr-xr-x 1 root root 2449104 Dec 23 00:00 /usr/lib64/libc.so.6

[root@d8e784ed1d22 ~]# ls /usr/aarch64-linux-gnu/bin/
ar  as  ld  ld.bfd  nm  objcopy  objdump  ranlib  readelf  strip
[root@d8e784ed1d22 ~]# ls /usr/aarch64-linux-gnu/sys-root/
[root@d8e784ed1d22 ~]# ls /usr/aarch64-redhat-linux/sys-root/fc40/usr/
include/ lib/     lib64/

[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-redhat-linux/sys-root/fc40/usr/lib64/libc.*
-rw-r--r-- 1 root root 6411932 Dec 23 00:00 /usr/aarch64-redhat-linux/sys-root/fc40/usr/lib64/libc.a
-rw-r--r-- 1 root root     265 Dec 23 00:00 /usr/aarch64-redhat-linux/sys-root/fc40/usr/lib64/libc.so
-rw-r--r-- 1 root root 2364952 Dec 23 00:00 /usr/aarch64-redhat-linux/sys-root/fc40/usr/lib64/libc.so.6

交叉编译架构工具链
#

ubuntu x86_64 交叉编译器,库文件搜索路径:

  • /usr/libexec/gcc-cross/x86_64-linux-gnu/13/
    • 保存 gcc 内部调用的二进制
  • /usr/lib/gcc-cross/x86_64-linux-gnu/13/
    • 保存 gcc 提供的库,引用 /usr/x86_64-linux-gnu/lib 下的中的标准动态库,如 libatomic.so/libcc1.so 等
  • /usr/x86_64-linux-gnu/13/bin/x86_64-linux-gnu/13/
    • NO, 目录不存在
  • /usr/x86_64-linux-gnu/bin
    • 保存交叉编译架构的 binutils 二进制
  • /usr/x86_64-linux-gnu/lib
    • 保存交叉编译架构标准库文件
  • /usr/lib/x86_64-linux-gnu/
    • 保存链接器脚本和标准库的动态版本
  • /lib
  • /usr/lib

ubuntu x86_64 交叉编译器,头文件搜索路径:

  • /usr/lib/gcc/x86_64-linux-gnu/13/include: gcc 自身定义和使用的头文件目录
  • /usr/x86_64-linux-gnu/include:gcc 头文件 + 目标架构标准头文件(含内核)

交叉编译器使用 /usr/<target> 目录,如 /usr/x86_64-linux-gnu,保存交叉编译工具链使用的二进制、头文件、标准库等:

# 交叉编译的第二 /usr 目录层次
alizj@ubuntu:~$ ls /usr/x86_64-linux-gnu/
bin  include  lib  lib64

# 保存交叉编译版本的二进制工具
alizj@ubuntu:~$ ls -l /usr/x86_64-linux-gnu/bin/
total 48
lrwxrwxrwx 1 root root 29 Aug  7 18:15 ar -> ../../bin/x86_64-linux-gnu-ar
lrwxrwxrwx 1 root root 29 Aug  7 18:15 as -> ../../bin/x86_64-linux-gnu-as
lrwxrwxrwx 1 root root 31 Aug  7 18:15 gold -> ../../bin/x86_64-linux-gnu-gold
lrwxrwxrwx 1 root root 29 Aug  7 18:15 ld -> ../../bin/x86_64-linux-gnu-ld
lrwxrwxrwx 1 root root 33 Aug  7 18:15 ld.bfd -> ../../bin/x86_64-linux-gnu-ld.bfd
lrwxrwxrwx 1 root root 34 Aug  7 18:15 ld.gold -> ../../bin/x86_64-linux-gnu-ld.gold
lrwxrwxrwx 1 root root 29 Aug  7 18:15 nm -> ../../bin/x86_64-linux-gnu-nm
lrwxrwxrwx 1 root root 34 Aug  7 18:15 objcopy -> ../../bin/x86_64-linux-gnu-objcopy
lrwxrwxrwx 1 root root 34 Aug  7 18:15 objdump -> ../../bin/x86_64-linux-gnu-objdump
lrwxrwxrwx 1 root root 33 Aug  7 18:15 ranlib -> ../../bin/x86_64-linux-gnu-ranlib
lrwxrwxrwx 1 root root 34 Aug  7 18:15 readelf -> ../../bin/x86_64-linux-gnu-readelf
lrwxrwxrwx 1 root root 32 Aug  7 18:15 strip -> ../../bin/x86_64-linux-gnu-strip

# 保存交叉编译版本的标准库和内核头文件
alizj@ubuntu:~$ ls -l /usr/x86_64-linux-gnu/include/std*.h
-rw-r--r-- 1 root root 26902 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdbit.h
-rw-r--r-- 1 root root  2462 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdc-predef.h
-rw-r--r-- 1 root root  8155 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdint.h
-rw-r--r-- 1 root root  2800 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdio_ext.h
-rw-r--r-- 1 root root 34649 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdio.h
-rw-r--r-- 1 root root 41032 Apr 15  2024 /usr/x86_64-linux-gnu/include/stdlib.h

# 交叉编译版本的标准库(动态库+静态库)
alizj@ubuntu:~$ ls -l /usr/x86_64-linux-gnu/lib/lib[cm].so
-rw-r--r-- 1 root root 308 Apr 15  2024 /usr/x86_64-linux-gnu/lib/libc.so
-rw-r--r-- 1 root root 148 Apr 15  2024 /usr/x86_64-linux-gnu/lib/libm.so
alizj@ubuntu:~$ ls -l /usr/x86_64-linux-gnu/lib/lib[cm].a
-rw-r--r-- 1 root root 6112386 Apr 15  2024 /usr/x86_64-linux-gnu/lib/libc.a
-rw-r--r-- 1 root root     132 Apr 15  2024 /usr/x86_64-linux-gnu/lib/libm.a

# 交叉编译版本的标准库,保存动态链接版本的库,动态链接器和链接脚本
alizj@ubuntu:~$ ls -l /usr/lib/x86_64-linux-gnu/
total 6784
drwxr-xr-x 1 root root      18 Jan 15 20:57 bfd-plugins
drwxr-xr-x 1 root root    5434 Jan 11 22:22 gconv
-rwxr-xr-x 1 root root  236616 Aug  8 22:47 ld-linux-x86-64.so.2
drwxr-xr-x 1 root root    2648 Jan 15 20:57 ldscripts
-rw-r--r-- 1 root root   14408 Aug  8 22:47 libanl.so.1
-rw-r--r-- 1 root root   14624 Aug  8 22:47 libBrokenLocale.so.1
-rw-r--r-- 1 root root   60744 Aug  8 22:47 libc_malloc_debug.so.0
-rwxr-xr-x 1 root root 2125328 Aug  8 22:47 libc.so.6
-rw-r--r-- 1 root root   14408 Aug  8 22:47 libdl.so.2
-rw-r--r-- 1 root root  183024 Sep  9 21:21 libgcc_s.so.1
lrwxrwxrwx 1 root root      16 Apr  9  2024 libidn2.so.0 -> libidn2.so.0.4.0
-rw-r--r-- 1 root root  133192 Apr  9  2024 libidn2.so.0.4.0
-rw-r--r-- 1 root root   18712 Aug  8 22:47 libmemusage.so
-rw-r--r-- 1 root root  952616 Aug  8 22:47 libm.so.6
-rw-r--r-- 1 root root 1018144 Aug  8 22:47 libmvec.so.1
-rw-r--r-- 1 root root  100640 Aug  8 22:47 libnsl.so.1
-rw-r--r-- 1 root root   43736 Aug  8 22:47 libnss_compat.so.2
-rw-r--r-- 1 root root   14336 Aug  8 22:47 libnss_dns.so.2
-rw-r--r-- 1 root root   14336 Aug  8 22:47 libnss_files.so.2
-rw-r--r-- 1 root root   26912 Aug  8 22:47 libnss_hesiod.so.2
-rw-r--r-- 1 root root   14544 Aug  8 22:47 libpcprofile.so
-rw-r--r-- 1 root root   14408 Aug  8 22:47 libpthread.so.0
-rw-r--r-- 1 root root   68104 Aug  8 22:47 libresolv.so.2
-rw-r--r-- 1 root root   14624 Aug  8 22:47 librt.so.1
-rw-r--r-- 1 root root   47912 Aug  8 22:47 libthread_db.so.1
lrwxrwxrwx 1 root root      21 Apr  9  2024 libunistring.so.5 -> libunistring.so.5.0.0
-rw-r--r-- 1 root root 1755312 Apr  9  2024 libunistring.so.5.0.0
-rw-r--r-- 1 root root   14408 Aug  8 22:47 libutil.so.1

alizj@ubuntu:~$ ls -l /usr/x86_64-linux-gnu/lib64/  # 交叉编译版本的链接器
total 4
lrwxrwxrwx 1 root root 27 Apr 15  2024 ld-linux-x86-64.so.2 -> ../lib/ld-linux-x86-64.so.2
alizj@ubuntu:~$ ls /usr/libexec/gcc-cross/x86_64-linux-gnu/13/  # 交叉编译 GCC 自身二进制
cc1  collect2  liblto_plugin.so  lto1  lto-wrapper
alizj@ubuntu:~$ ls -l  /usr/lib/gcc-cross/x86_64-linux-gnu/13  # 交叉编译 GCC 自身使用的库和头文件
total 20884
-rw-r--r-- 1 root root    2448 Sep 15 19:33 crtbegin.o
-rw-r--r-- 1 root root    2752 Sep 15 19:33 crtbeginS.o
-rw-r--r-- 1 root root    2968 Sep 15 19:33 crtbeginT.o
-rw-r--r-- 1 root root    1168 Sep 15 19:33 crtend.o
-rw-r--r-- 1 root root    1168 Sep 15 19:33 crtendS.o
-rw-r--r-- 1 root root    4112 Sep 15 19:33 crtfastmath.o
-rw-r--r-- 1 root root    3768 Sep 15 19:33 crtprec32.o
-rw-r--r-- 1 root root    3776 Sep 15 19:33 crtprec64.o
-rw-r--r-- 1 root root    3768 Sep 15 19:33 crtprec80.o
drwxr-xr-x 1 root root    3530 Jan 15 20:57 include
-rw-r--r-- 1 root root 4984914 Sep 15 19:33 libasan.a
-rw-r--r-- 1 root root    3568 Sep 15 19:33 libasan_preinit.o
lrwxrwxrwx 1 root root      45 Sep 15 19:33 libasan.so -> ../../../../x86_64-linux-gnu/lib/libasan.so.8
-rw-r--r-- 1 root root  158816 Sep 15 19:33 libatomic.a
lrwxrwxrwx 1 root root      47 Sep 15 19:33 libatomic.so -> ../../../../x86_64-linux-gnu/lib/libatomic.so.1
-rw-r--r-- 1 root root  142090 Sep 15 19:33 libbacktrace.a
lrwxrwxrwx 1 root root      38 Sep 15 19:33 libcc1.so -> ../../../aarch64-linux-gnu/libcc1.so.0
-rw-r--r-- 1 root root 3093656 Sep 15 19:33 libgcc.a
-rw-r--r-- 1 root root   66708 Sep 15 19:33 libgcc_eh.a
-rw-r--r-- 1 root root     132 Sep 15 19:33 libgcc_s.so
-rw-r--r-- 1 root root   68002 Sep 15 19:33 libgcov.a
...
drwxr-xr-x 1 root root     212 Jan 15 20:57 plugin

总结:头文件搜索路径
#

总结: 先搜索 GCC 相关头文件目录,再搜索系统标准头文件目录。

对于 host 架构而言,系统标准库和头文件分别是 /usr/lib 和 /usr/include 目录:

  • /usr/include/aarch64-linux-gnu/ 和 /usr/lib/gcc/aarch64-linux-gnu/13/include : gcc 自身定义和使用的头文件目录
  • /usr/include: 系统标准头文件目录

对于交叉编译工具链,不存在 /usr/include/x86_64-linux-gnu/ 目录,gcc 相关和系统标准库头文件都位于:

  • /usr/lib/gcc/x86_64-linux-gnu/13/include: gcc 自身定义和使用的头文件目录
  • /usr/x86_64-linux-gnu/include:gcc 头文件 + 目标架构标准头文件(含内核)

对于 Fedora、CentOS 系列,安装交叉编译工具链后,还要安装 sysroot 包才能提供目标架构的头文件、库文件:

[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-linux-gnu/
total 0
drwxr-xr-x 1 root root 92 Jan 22 07:59 bin
drwxr-xr-x 1 root root  0 May 13  2024 sys-root
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-linux-gnu/bin/
total 20056
-rwxr-xr-x 2 root root 1286616 May 13  2024 ar
-rwxr-xr-x 2 root root 2351968 May 13  2024 as
-rwxr-xr-x 4 root root 3426184 May 13  2024 ld
-rwxr-xr-x 4 root root 3426184 May 13  2024 ld.bfd
-rwxr-xr-x 2 root root 1362072 May 13  2024 nm
-rwxr-xr-x 2 root root 1514504 May 13  2024 objcopy
-rwxr-xr-x 2 root root 3455728 May 13  2024 objdump
-rwxr-xr-x 2 root root 1286616 May 13  2024 ranlib
-rwxr-xr-x 2 root root  890584 May 13  2024 readelf
-rwxr-xr-x 2 root root 1514504 May 13  2024 strip
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-linux-gnu/sys-root/ # 空目录
total 0

[root@d8e784ed1d22 ~]# rpm -qa |grep sysroot
sysroot-aarch64-fc40-glibc-2.39-33.fc40.noarch

# 安装 sysroot 包后,才会有交叉编译架构的头文件、标准库文件等类似于 /usr 的第二目录结构
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-redhat-linux/
total 0
drwxr-xr-x 1 root root 8 Jan 22 08:52 sys-root
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-redhat-linux/sys-root/
total 0
drwxr-xr-x 1 root root 6 Jan 22 08:52 fc40
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-redhat-linux/sys-root/fc40/
total 0
drwxr-xr-x 1 root root 30 Jan 22 08:52 usr
[root@d8e784ed1d22 ~]# ls -l /usr/aarch64-redhat-linux/sys-root/fc40/usr/
total 0
drwxr-xr-x 1 root root 2090 Jan 22 08:52 include
drwxr-xr-x 1 root root   42 Jan 22 08:52 lib
drwxr-xr-x 1 root root 1234 Jan 22 08:52 lib64

# 在编译时需要为链接器传入 --sysroot 参数来指定上面目录
aarch64-linux-gnu-gcc --sysroot=/usr/aarch64-redhat-linux/sys-root/fc40/

可以使用 cpp -v 命令或 echo 'main(){}' | gcc -E -v -gcc -v -xc /dev/null -fsyntax-only 查看搜索路径:

alizj@ubuntu:/Users/alizj/docs/lang/c$ echo 'main(){}' | gcc -E -v -
...
ignoring nonexistent directory "/usr/local/include/aarch64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/include-fixed/aarch64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/aarch64-linux-gnu/13/include
 /usr/local/include
 /usr/include/aarch64-linux-gnu
 /usr/include
End of search list.
...

总结:库文件搜索路径
#

使用 gcc -print-search-dirs 打印库文件默认搜索路径(来源于默认链接脚本):

install: /usr/lib/gcc/aarch64-linux-gnu/13/
programs: =/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/bin/
libraries: =/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../lib/:/lib/aarch64-linux-gnu/13/:/lib/aarch64-linux-gnu/:/lib/../lib/:/usr/lib/aarch64-linux-gnu/13/:/usr/lib/aarch64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../:/lib/:/usr/lib/

使用命令 echo 'main(){}' | gcc -E -v - 或者 gcc -v -xc /dev/null -fsyntax-only 查看编译时生效的头文件和库文件搜索路径:

alizj@ubuntu:/Users/alizj/docs/lang/c$ echo 'main(){}' | gcc -E -v -
...
 /usr/libexec/gcc/aarch64-linux-gnu/13/cc1 -E -quiet -v -imultiarch aarch64-linux-gnu - -mlittle-endian -mabi=lp64 -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -dumpbase -
ignoring nonexistent directory "/usr/local/include/aarch64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/include-fixed/aarch64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/aarch64-linux-gnu/13/include
 /usr/local/include
 /usr/include/aarch64-linux-gnu
 /usr/include
End of search list.
# 0 "<stdin>"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 0 "<command-line>" 2
# 1 "<stdin>"
main(){}
# GCC 内部调用二进制搜索路径
COMPILER_PATH=/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/13/:/usr/libexec/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/
# 库文件搜索路径
LIBRARY_PATH=/usr/lib/gcc/aarch64-linux-gnu/13/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../../lib/:/lib/aarch64-linux-gnu/:/lib/../lib/:/usr/lib/aarch64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/13/../../../:/lib/:/usr/lib/

交叉编译 makefile
#

参考: 20240524-makefile-manual.md

交叉编译 pkg-config
#

pkg-config 是一个管理编译和链接参数的工具,可以简化处理外部依赖库的工作。

pkg-config 是架构相关的,需要安装对应目录架构的 pkg-config 包,后续使用 target triplet prefix 来区分:

  • pkgconf-pkg-config.x86_64
  • pkgconf-pkg-config.aarch64
alizj@lima-dev2:~$ ls -l /usr/bin/pkg-config
lrwxrwxrwx 1 root root 7 Apr 24  2023 /usr/bin/pkg-config -> pkgconf
alizj@lima-dev2:~$ dpkg -S /usr/bin/pkgconf
pkgconf-bin: /usr/bin/pkgconf
alizj@lima-dev2:~$ dpkg -S /usr/bin/aarch64-linux-gnu-pkg-config
pkgconf:arm64: /usr/bin/aarch64-linux-gnu-pkg-config

除了用 -I 和 -L 手动指定路径外,还可以使用一些包提供的 pkg-config 机制和命令来自动查找要链接的库、头文件等编译参数:

  • 它使用库开发者发布的 .pc 格式文件来自动生成 -I、-L 和 -l 参数。
  • 库开发者使用 pkg-config --cflags --libs xxx 生成 gcc 的 -L 或 -l 参数(可以与 gcc、makefile 或 Autotools、CMake 等集成)
  • 主流构构建工具,如 CMake/autotools/meson/bazel, 都支持 pkg-config 来配置和管理动态链接库;

系统默认 .pc 文件路径:

alizj@ubuntu:~$ ls /usr/lib/pkgconfig/
alizj@ubuntu:~$ ls /usr/share/pkgconfig/
iso-codes.pc  personality.d  shared-mime-info.pc  systemd.pc  udev.pc  xkeyboard-config.pc
alizj@ubuntu:~$ ls /usr/local/lib/pkgconfig
ls: cannot access '/usr/local/lib/pkgconfig': No such file or directory
alizj@ubuntu:~$ ls /usr/local/share/pkgconfig
ls: cannot access '/usr/local/share/pkgconfig': No such file or directory

示例:

CFLAGS="`pkg-config --cflags apophenia glib-2.0` -g -Wall -std=gnu11 -O3"
LDLIBS="`pkg-config --libs apophenia glib-2.0`"
# 等效为
CFLAGS="-I/home/b/root/include -g -Wall-std=gnu11 -O3"
LDLIBS="-L/home/b/root/lib -lweirdlib"

# 两者结合使用
gcc `pkg-config --cflags --libs gsl libxml-2.0` -o specific specific.c
# 等效为
gcc -I/usr/include/libxml2 -lgsl -lgslcblas -lm -lxml2 -o specific specific.c

示例: Makefile 中使用 pkg-config,假设依赖 glib 库:

# Compiler and flags
CC = gcc
CFLAGS = -Wall -Iinclude $(shell pkg-config --cflags glib-2.0)  # 生成编译所需的参数,如 -Idir

# Directories
SRC_DIR = src
LIB_DIR = lib
EXT_LIB_DIR = ext_lib

# Source files
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
LIB_FILES = $(wildcard $(LIB_DIR)/*.c)

# Object files
OBJ_FILES = $(SRC_FILES:.c=.o) $(LIB_FILES:.c=.o)

# External libraries
EXT_LIBS = -L$(EXT_LIB_DIR) -lotherlib $(shell pkg-config --libs glib-2.0) # 生成链接所需参数,如 -Ldir -llib

# Output executable
OUTPUT = myprogram

# Default target
all: $(OUTPUT)

# Link object files
$(OUTPUT): $(OBJ_FILES)
	$(CC) -o $@ $^ $(EXT_LIBS)

# Compile source files
%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<

# Clean up
clean:
	rm -f $(SRC_DIR)/*.o $(LIB_DIR)/*.o $(OUTPUT)

.PHONY: all clean

交叉编译配置参数 autoconf
#

对于 autoconf 项目,执行 ./configure 脚本时可以指定交叉编译参数:

  1. –build=build-type:构建机器的架构类型,缺省使用 config.guess 的结果;
  2. –host=host-type:运行 autoconf 的机器架构类型,确实和 –build 一致;
  3. –target=target-type:编译生成的二进制的机器架构类型,缺省和 –host 一致;

示例:

# https://www.linuxfromscratch.org/lfs/view/development/chapter05/binutils-pass1.html
../configure --prefix=$LFS/tools \
             --with-sysroot=$LFS \
             --target=$LFS_TGT   \
             --disable-nls       \
             --enable-gprofng=no \
             --disable-werror    \
             --enable-new-dtags  \
             --enable-default-hash-style=gnu

# --prefix 指定安装路径
./configure --build=i686-pc-linux-gnu --host=m68k-coff --prefix=/path/to/install
make
make install

参考
#

  1. https://www.gnu.org/software/autoconf/manual/autoconf-2.68/html_node/Specifying-Target-Triplets.html
  2. rustc –print target-list
  3. LLVM 定义的 triple:https://llvm.org/doxygen/classllvm_1_1Triple.html
  4. https://www.linuxfromscratch.org/lfs/view/development/partintro/toolchaintechnotes.html
gnu-toolchain - 这篇文章属于一个选集。
§ 4: 本文

相关文章

GCC 编译器 - 个人参考手册
Gnu Gcc Manual
gcc 编译器个人参考手册。
Go CGO 程序静态编译链接
Cgo Go Compile Gcc
本文先介绍 Go CGO 的概念和应用场景,以项目用到的 mattn/go-sqlite3 为例,介绍 CGO 程序的静态链接实现方案,其中涉及到动态链接的问题分析、 ubunut/centos 系统的静态编译环境搭建,CGO 静态编译遇到的问题和解决方案,最终生成最小化系统环境依赖的静态链接二进制。
使用 musl 交叉编译和静态链接
·
Cgo Go Compile Gcc Musl
本文介绍了使用轻量化 libc 库 musl 进行交叉编译生成多架构二进制的方案,最终实现在 x86_64 编译机器上能同时构建出静态链接的 x86_64 和 aarch64 二进制的目标,大大简化了多套构建脚本的开发和维护成本。
C 预处理器-个人参考手册
·
Gnu Cpp Manual
这是我个人的 C 预处理器参考手册文档。