文档首页> 云计算> Linux Cmake如何进行交叉编译

Linux Cmake如何进行交叉编译

发布时间:2025-09-07 00:19       

下面给出一套可直接复用的 CMake 交叉编译方法论与示例,覆盖工具链文件、sysroot、依赖发现、try_compile/try_run、pkg-config 与打包安装等关键点。🛠️

一、核心思路(一句话)

在主机上用目标架构的编译器和头库(sysroot)进行配置阶段的“假执行+真编译”,禁止在配置期跑目标程序,并把依赖搜索限定到目标 sysroot。✅


二、准备清单

  • 交叉编译器:如 aarch64-linux-gnu-gcc/g++ 或 arm-linux-gnueabihf-gcc/g++
  • 目标 rootfs/sysroot:/opt/sysroots/aarch64(含 include/ 与 lib/
  • CMake ≥ 3.16(建议 3.22+,Preset 更好用)
  • 可选:qemu-<arch>(仅在需要运行目标程序做测试时)

三、最小可用 Toolchain 文件(推荐保存为 toolchain-aarch64.cmake

# 目标系统与架构
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

# 指定交叉编译器(全路径或通过 PATH)
set(CMAKE_C_COMPILER   aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)

# 指定 sysroot(头文件与库的根)
set(CMAKE_SYSROOT /opt/sysroots/aarch64)

# 依赖搜索只在 sysroot 内进行
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)   # 程序走主机 PATH
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)    # 库只在 sysroot
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)    # 头文件只在 sysroot
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)    # 包只在 sysroot

# 配置期不运行目标二进制,避免“可执行文件格式错误”
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# pkg-config 指向目标库(如有)
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
set(ENV{PKG_CONFIG_LIBDIR}      ${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig)

要点解释:

  • CMAKE_SYSTEM_NAME/PROCESSOR 告诉 CMake “这是交叉编译”。
  • CMAKE_SYSROOT + CMAKE_FIND_ROOT_PATH_MODE_* 将库/头查找限定到目标环境。
  • CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY 禁掉配置期执行。🚫

四、标准命令行

cmake -S . -B build-aarch64 \
  -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64.cmake \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr \
  -DCMAKE_STAGING_PREFIX=/tmp/stage-aarch64
  • -S/-B:源码与构建目录分离。
  • CMAKE_INSTALL_PREFIX:目标系统内的安装前缀(如 /usr)。
  • CMAKE_STAGING_PREFIX:将安装产物“假装”安装到打包目录,便于后续打包或拷入 rootfs。📦

随后编译与“打包安装”:

cmake --build build-aarch64 -j
cmake --install build-aarch64

五、依赖与 pkg-config 的正确打开方式

  • 目标库(如 OpenSSL、zlib、protobuf)需在目标架构下预装到 ${CMAKE_SYSROOT}
  • 若用 find_package(OpenSSL REQUIRED),确保对应的 *.cmake 或 pkgconfig 位于 sysroot。
  • 通过上面的 PKG_CONFIG_* 环境变量,find_package(PkgConfig) + pkg_check_modules() 才会命中目标版本。🔍

六、Clang/多目标的补充(可选)

若用 Clang + LLVM:

set(CMAKE_C_COMPILER   clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_C_COMPILER_TARGET   aarch64-linux-gnu)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)

这样可不依赖特定前缀编译器,只要有对应目标的运行时与 sysroot 即可。🚀


七、try_run 与单元测试

  • CMake/部分包在配置期会 try_run。交叉场景中应避免,或配置 CMAKE_CROSSCOMPILING_EMULATOR=qemu-aarch64 以在主机上模拟运行:
    set(CMAKE_CROSSCOMPILING_EMULATOR qemu-aarch64)
    
  • 更稳妥:在 CI 的目标机/容器里跑测试,构建阶段仅编译与安装。⚠️

八、常见问题速解

  • 链接不到目标库:检查 CMAKE_SYSROOT 是否正确;确认 lib 目录是否是 aarch64 版本;file libxxx.so 核对架构。
  • 找不到包:为 sysroot 补齐 xxx-config.cmake 或 pkgconfig/*.pc;必要时用 -D<Package>_ROOT=${CMAKE_SYSROOT}/usr
  • 混入主机库:务必使用 ONLY 策略;不要把主机 /usr/lib 加入额外搜索路径。
  • C++ ABI 不匹配:目标和交叉工具链的 libstdc++ 版本需匹配;尽量同源(如同套件版本的 GCC)。

九、进阶:CMakePresets.json(团队复用更优雅)

{
  "version": 5,
  "configurePresets": [
    {
      "name": "aarch64-release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build-aarch64",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "toolchain-aarch64.cmake",
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_INSTALL_PREFIX": "/usr",
        "CMAKE_STAGING_PREFIX": "/tmp/stage-aarch64"
      }
    }
  ]
}

团队只需 cmake --preset aarch64-release 即可复现同配置。🙌


十、简明清单(拿去就能跑)

  1. 准备交叉编译器与 sysroot
  2. 写好 toolchain.cmake(含 SYSROOTONLY 策略、TRY_COMPILE 静态)
  3. cmake -S -B -D CMAKE_TOOLCHAIN_FILE=... 配置
  4. --build 编译,--install 安装到 staging
  5. 用 file/readelf 核对产物架构;将 /tmp/stage-<arch> 同步到镜像或打包

以上流程覆盖了当下主流 CMake 版本的最佳实践,能稳定落地于 ARM/aarch64/RISC-V 等多架构交叉编译场景。✅✨