compiler-rt

compiler-rt 提供了一个中间层,用来不支持某些语言特征的机器上执行软件模拟运算。例如 compiler-rt 的 __muldi3 函数能够在不支持 64 位整数的计算机上执行 64 位乘法。

对于 GNU 而言,这个库是 libgcc

大多数 C 编辑器会带有这个库。比如在 Ununtu 上, build_essential 包,你就可以在 /lib/x86_64-linux-gnu/libgcc_s.so.1 发现它。

如果你下载了 clang+llvm,你会发现随包附带的并没有这个库,这是因为 clang 依赖于系统提供的 libgcc,其中一个原因是这个库是系统强相关的。

和 clang 的策略不同。zig 参考 llvm 自己实现了一套 compiler-rt 库。并将其附带在二进制包中,然后依赖于缓存系统而无需每次都从源码构建。

libc

libc 是一个 C 语言库,它提供了 C 语言的标准库。对于 FreeBSD 和 macOS 而言。libc 是一个系统库,提供了系统调用接口。而对于 Linux 和 Windows 而言,libc 是可选的,并存在多个可相互替代的 libc 实现。

zig 的 libc 参考了 musl 的实现,和 compiler-rt 的策略相同,通过附带源码的形式解决了交叉编译问题。

glibc

zig 通过预处理工具将 glibc 和 linux 的源码进行分类成平台相关代码和平台无关代码,然后生成了三个文件:

  • vers.txt 包含了 glic 的所有版本。

  • fns.txt 包含了 glibc 提供的所有符号。

  • abi.txt 对于每个 target、每个函数他们的 glibc 版本。

如果用户程序没有要求 glibc 版本,则 zig 首先通过查看自己的二进制文件来查找系统的 glibc,如果找不到就通过 /usr/bin/env 的 shebang 查找。最后连接到系统的 glibc 版本。

如果用户请求特定的 glibc 版本,那么 zig 会链接到一个 dummy 库上,然后在目标系统上动态查找符号。

最后还有 “C 运行时启动文件”:

  • Scrt1.o

  • crti.o

  • crtn.o

由于它们的 ABI 相当稳定,所以直接静态编译。

这样 zig 就不再与任何系统绑定了。

musl

zig 对 musl 的处理和 glibc 类似。但是由于 musl 支持静态链接,因此 zig 附带了 musl 的大部分源码。

交叉编译

和普通编译相同,交叉编译也涉及到了三个阶段:

  • 预处理阶段

  • 编译阶段

  • 链接阶段

clang 预处理阶段天然支持交叉编译,第二个阶段用来将代码编译成汇编,通过 llvm-mc(LLVM 集成汇编处理器)进行支持。第三个阶段通过 lld(通用 linker)进行支持。

更准确来讲,lld 分为四个不同的 linker:

  • ld.lld (Unix)

  • ld64.lld (macOS)

  • lld-link (Windows)

  • wasm-ld (WebAssembly)

不论如何,这四个 linker 本身就是跨平台软件。

除非代码本身不依赖任何其它库(包括 libc),否则链接阶段还需要指定依赖的库所在的路径。这一过程通过 sysroot 受支持。sysroot 结构同 /usr 路径结构相同。包括了目标平台的头文件和库文件。

获取 sysroot 最简单的办法就是直接从目标平台上将相关文件夹拷贝过来:

mkdir ~/farm_tree
ssh FARM64 'tar cf - /lib /usr/include /usr/lib /usr/local/lib /usr/local/include' | bsdtar xvf - -C $HOME/farm_tree/

clang 通过 target triple 来指明交叉编译的目标平台。

例如,将代码编译到 aarch64-pc-freebsd 上的命令为:

clang++ --target=aarch64-pc-freebsd --sysroot=$HOME/bsd_sysroot -fuse-ld=lld -stdlib=libc++ -o zpipe zpipe.cc -lz

对于 CMake + clang 的交叉编译。参阅 [1]

Last moify: 2025-05-06 09:04:45
Build time:2025-07-18 09:41:42
Powered By asphinx