Clang交叉编译arm-none-eabi时无法正确识别工具链:找不到ld.lld且头目录识别异常
我之前在搭配Clang和ARM GNU Toolchain交叉编译arm-none-eabi目标时,也踩过几乎一模一样的坑。这俩问题其实都是Clang默认行为和GNU工具链的适配差异导致的,咱们一步步来解决:
一、解决ld.lld不存在的链接器问题
Clang默认会优先尝试调用LLVM自家的ld.lld链接器,但你用的ARM GNU Toolchain只提供了GNU的ld.bfd(也就是工具链里ld软链接指向的二进制)。解决这个问题很简单,只需要明确告诉Clang使用GNU的bfd链接器:
在编译命令中添加参数:-fuse-ld=bfd
这个参数会让Clang自动在sysroot对应的工具链目录中查找ld.bfd并使用它,不用手动指定链接器路径。
二、修复头文件目录识别异常
Clang默认会优先查找LLVM libc的标准库路径(也就是你日志里看到的include/c++/v1),但ARM GNU Toolchain搭载的是GNU libstdc,路径是include/c++/15.2.1(对应你的工具链版本)。要让Clang正确识别这个路径,有两种优雅的方式:
方式1:正确使用--gcc-toolchain参数
你之前用这个参数时被标记为未使用,是因为路径写错了!--gcc-toolchain需要指向工具链的根目录(也就是不带末尾arm-none-eabi的父目录),而不是sysroot的路径。
比如你的工具链根目录是${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi,加上这个参数后,Clang会自动探测GNU工具链的所有头文件、库和链接器配置,不用手动添加include路径。
方式2:手动指定libstdc++的包含目录
如果不想用--gcc-toolchain,可以直接添加两个include参数,覆盖Clang的默认查找路径:
-I${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/arm-none-eabi/include/c++/15.2.1 \ -I${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/arm-none-eabi/include/c++/15.2.1/arm-none-eabi
第二个路径是针对arm-none-eabi目标的平台特定头文件目录,必须加上才能正确识别目标架构的C++标准库。
三、整合后的完整编译命令
把上面的修正点整合起来,最终的编译命令应该是这样的:
clang --verbose \ --target=arm-none-eabi \ --gcc-toolchain=${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi \ --sysroot=${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/arm-none-eabi \ -fuse-ld=bfd \ -o executable \ main.cpp
运行这个命令后,你会在--verbose的输出中看到:
- Clang正确调用了
ld.bfd作为链接器 - 头文件查找列表中会出现GNU libstdc++的
15.2.1相关目录,不再抱怨include/c++/v1不存在
四、顺便解决VS Code clangd的头文件识别问题
clangd的问题根源和命令行完全一致:它没有拿到正确的交叉编译配置。解决方法是给clangd提供正确的编译上下文:
- 生成compile_commands.json:用CMake或者Bear工具(比如
bear -- <你的编译命令>)生成编译数据库,clangd会自动读取这个文件,完美识别所有头文件路径和编译参数。 - 手动配置clangd参数:如果不想用编译数据库,可以在VS Code的
settings.json中添加:
"clangd.arguments": [ "--target=arm-none-eabi", "--gcc-toolchain=${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi", "--sysroot=${HOME}/Desktop/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi/arm-none-eabi", "-fuse-ld=bfd" ]
替换成你自己的工具链路径,重启clangd后就能正确识别头文件了。
其实Clang交叉编译arm-none-eabi时,适配GNU工具链的核心就是让它“放弃”默认的LLVM组件,转而使用GNU的链接器和标准库,调整这几个参数后就顺畅多了~




