不是编译失败,而是没真正完成交叉编译——clang 默认仍按宿主机目标生成二进制,必须显式指定 --target、--sysroot 和(必要时)--gcc-toolchain,否则生成的文件在目标机上必然报 exec format error。

直接结论:不是编译失败,而是没真正完成交叉编译——Clang 默认仍按宿主机目标生成二进制,必须显式指定 --target、--sysroot 和(必要时)--gcc-toolchain,否则生成的文件在目标机上必然报 exec format error。
为什么加了 -target 还报 exec format error
常见错误是 --target 写错或不完整。Clang 对三元组格式极其敏感,比如:
-
armv7-linux-gnueabihf❌:Clang 不识别,报error: unable to create target -
arm-linux-gnueabihf❌:不是标准三元组,头文件路径失效,stdio.h找不到 -
armv7a-unknown-linux-gnueabihf✅:32 位 ARM Linux 正确写法 -
aarch64-unknown-linux-gnu✅:ARM64 Linux 标准写法
漏掉 -mcpu=generic 或写太具体的 CPU(如 -mcpu=cortex-a72)也可能触发隐式 target 冲突,导致链接器选错 ABI。
sysroot 没配对就等于没交叉编译
--sysroot 不是可选参数,而是硬性依赖。Clang 自带的 minimal headers 完全无法支撑 Linux 用户态程序编译:
- 不能用宿主机的
/usr/include替代——结构体定义、__kernel_size_t等宏全错 - 路径下必须含
lib/ld-linux-aarch64.so.1(ARM64)或lib/ld-linux-armhf.so.3(ARM32),否则动态链接失败 - 即使加了
-static,也得有libc.a,否则报cannot find -lc
典型命令示例(ARM64):clang --target=aarch64-unknown-linux-gnu --sysroot=/opt/sysroots/aarch64-linux --gcc-toolchain=/opt/gcc-arm64 --stdlib=libc++ hello.c -o hello-arm64
CMake Presets 下容易漏掉的三个致命点
用 CMakePresets.json 管理交叉编译时,以下三项缺一不可,漏掉任一都会静默回归宿主机编译:
-
CMAKE_SYSTEM_NAME必须设为"Linux"(不能是空或"Generic") -
CMAKE_SYSTEM_PROCESSOR必须与--target中的 CPU 部分一致,如"aarch64"或"armv7" -
CMAKE_TOOLCHAIN_FILE中必须包含set(CMAKE_C_COMPILER "clang")和完整--target=...参数,不能只靠环境变量传
工具链文件里还要加:set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
否则 find_package() 会混用宿主机库。
file 命令是第一道诊断线
别猜,先跑 file 看输出:
-
ELF 64-bit LSB pie executable, x86-64, ...→ 实际还是编译成了 x86_64 -
ELF 64-bit LSB shared object, ARM aarch64, ...→ 架构正确,再查readelf -d看NEEDED库是否指向 sysroot 内路径 -
data或cannot open→ 文件损坏或权限问题(但概率极低)
如果 file 输出里没出现目标架构关键词,说明前面所有配置都白做了——Clang 根本没按你预期的目标生成代码。











