版块:开发工具

从"能编过"到"CI 里稳定出包",CMake 交叉编译要过的坎就那么几个,但几乎人人要踩一遍。整理一份清单给你对号。

一、工具链描述文件:别再用命令行硬塞

很多人还在 cmake -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc ... 一把梭——问题:编译器测不了 sysroot、链接选项对不齐时,CMake 的 try_compile 会混进 host 库。

正确做法:toolchain.cmake + -DCMAKE_TOOLCHAIN_FILE=:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER /opt/poky/5.0/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-gcc)
set(CMAKE_SYSROOT /opt/poky/5.0/sysroots/aarch64-poky-linux)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

FIND_ROOT_PATH 三件套是灵魂:只让 find_library/find_path 钻到 sysroot 里(否则你会得到 x86 的 zlib.a 在 ARM 链接时报一堆 ELF 架构错误)。

二、交叉依赖包:find_package 为何找不到

- 第三方 ARM 包装进了一个前缀(如 /opt/target-deps):加 CMAKE_PREFIX_PATH,同时确认 FIND_ROOT_PATH_MODE_PACKAGE=ONLY;
- find_package(CONFIG) 模式下,被依赖包的 *-config.cmake 里硬编码了它构建时的绝对路径——换 sysroot 就失效,打补丁修该包或改走 find_path + include_directories 手工流;
- pkg-config 交叉场景必须设 PKG_CONFIG_SYSROOT_DIR 和 PKG_CONFIG_LIBDIR,CMake 查不到而 pkg-config 能查到的"玄学"多半在此。

三、编译/链接选项对齐的三个细节

1. 目标 ABI 与库的 ABI:-mcpu/-march/-mfpu/-mfloat-abi 与 sysroot 里预编译库不一致时链接静默选错 multilib 目录;工具链带 --print-multi-directory 自检;
2. rpath 别把 host 目录编进去:构建后 file(READLIB) 或 rpath-link 指定 target 库搜索路径;CI 产物用 readelf -d 扫 RPATH 检查;
3. strip 时机:调试包分离用符号表 + install(TARGETS ... / COMPONENT),比最后 cp -r 可靠。

四、混合语言/生成代码的坑

- protobuf/grpc 交叉编译:protoc 必须先 host build,toolchain 模式下设 protobuf_PROTOBUF_GENERATE… 类的 host tool 变量——记住原则:"工具在 host,库在 target";
- 用 FetchContent 拉依赖时它不带 toolchain 传播,子项目 CMakeLists 里显式传 CMAKE_TOOLCHAIN_FILE;
- ccache 交叉模式下按 compiler hash,换 toolchain 记得清缓存再信报错。

五、CI 最小闭环建议

cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-poky.cmake -G Ninja
cmake --build build
ctest --test-dir build --output-on-failure --timeout 120
# QEMU user-mode: qemu-aarch64 -L <sysroot> ./build/app

真机测试阶段用 QEMU 跑单测,能筛掉 80% 的架构错误再上板。

你们公司 CMake 交叉配置里还有什么血泪条规?回帖补进这份清单,我按周合并更新版本。