clang交叉编译不能直接用libgcc,因其为gcc专用运行时,clang默认不识别;需改用llvm官方compiler-rt提供内建函数、sanitizer及abi支持,且须显式指定-rtlib=compiler-rt并确保sysroot或resource-dir路径正确。

交叉编译时为什么不能直接用 libgcc
libgcc 是 GCC 工具链专用的运行时支持库,由 GCC 自带的 gcc 驱动在链接阶段自动注入。LLVM/Clang 默认不识别 libgcc,也不会在 -target 切换架构后自动找它——即使你硬把 GCC 的 libgcc.a 拖进链接命令,也极大概率遇到符号缺失(如 __aeabi_memmove)、ABI 不兼容(ARM EABI vs AAPCS64)、或与 libc++abi 冲突。
compiler-rt 是什么,它替代了哪些东西
compiler-rt 是 LLVM 官方维护的轻量级运行时库,专为 Clang 设计,覆盖三类关键功能:
- 内建函数(
__muloti4、__udivmodti4等 128 位算术) - sanitizer 运行时(ASan/UBSan/TSan 的桩代码)
- 目标平台适配的低层 ABI 支持(如 ARM 的
__aeabi_*系列、RISC-V 的__riscv_*)
它不是“标准库”,也不提供 malloc 或 fopen;它只做 Clang 编译器生成代码所必须依赖的底层 glue code。启用方式很简单:-rtlib=compiler-rt 即可让 Clang 主动链接 compiler-rt 对应目标的静态库。
什么时候必须显式指定 -rtlib=compiler-rt
以下场景不加就可能链接失败或运行崩溃:
- 交叉编译到裸机(bare-metal)或微控制器(如 Cortex-M),没 libc 可用时
- 使用
-ffreestanding或-nostdlib,且代码含 64/128 位运算、除法、浮点转整等隐式调用内建函数的操作 - 目标 triple 明确不含 GNU(例如
aarch64-unknown-elf、riscv64-unknown-elf),Clang 默认不会拉libgcc - 启用 sanitizer(如
-fsanitize=address)时,compiler-rt是唯一支持源
示例命令:
clang --target=armv7a-unknown-eabihf -mfloat-abi=hard -rtlib=compiler-rt \ -ffreestanding -nostdlib -o firmware.o -c firmware.c
常见坑:compiler-rt 没编译、路径不对、或和 libc 冲突
如果你从源码构建 llvm-project,compiler-rt 默认不参与构建,除非你在 cmake 里显式开启:
- 构建时漏掉
-DLLVM_ENABLE_PROJECTS="clang;compiler-rt"→ 编译完没有lib/clang/*/lib/linux/libclang_rt.*.a - 交叉编译时没指定
--sysroot或-resource-dir→ Clang 找不到对应 target 的compiler-rt归档文件 - 同时链接
libc(如 newlib/picolibc)和compiler-rt中的同名符号(如__memcpy)→ 链接器报multiple definition
解决方法:用 clang -print-resource-dir 确认资源路径,再检查 $RESOURCE_DIR/lib/<target>/libclang_rt.*.a</target> 是否存在;若用自定义 C library,建议禁用其内建函数实现(如 newlib 的 --disable-newlib-supplied-syscalls),交由 compiler-rt 统一提供。
真正容易被忽略的是:compiler-rt 的 ABI 支持粒度很细,比如 armv7a-unknown-eabihf 和 armv7a-unknown-linux-gnueabihf 虽然都用 ARMv7,但前者走 compiler-rt 的 eabi 实现,后者可能 fallback 到 libgcc —— 差一个 vendor 字段,底层 runtime 就可能完全不同。











