- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
导读
工具链(Toolchain)是 CMake 构建系统的基石:它决定了编译、链接、归档等全部构建动作由哪一组工具完成。本指南以 CMake 官方手册 cmake-toolchains(7) 为骨架,系统讲解语言启用机制、编译器相关变量与属性、try_compile能力探测,以及面向 Linux、Cray、Clang、QNX、Windows CE/Store/Phone、ADSP、Android、Apple 平台、Emscripten 与 Renesas 等十余类交叉编译场景的 Toolchain File 编写方法。读完本文,你将能够独立编写一份可用的 Toolchain File,理解CMAKE_FIND_ROOT_PATH_MODE_*等搜索规则的底层行为,并能针对具体嵌入式与移动平台完成配置。
引言:什么是 CMake 工具链
CMake 使用一组工具(Toolchain)来完成编译、库链接、归档创建等构建任务。这组工具由启用的语言决定:例如启用了 C 语言,就需要 C 编译器;启用了 Fortran,就需要 Fortran 编译器与对应的归档工具。工具链的获取方式分为两种:
- 本机构建(host build):CMake 通过系统内省(system introspection)与默认值自动探测编译器路径和配套工具,无需人工指定;
- 交叉编译(cross-compiling):通过Toolchain File(工具链文件)显式提供编译器与工具路径等信息。
从 CMake 3.19 起,还可以通过 cmake-presets(7) 指定 Toolchain File(preset 中的toolchainFile字段)。在源码层面,Source/cmake.cxx 中定义了命令行参数--toolchain <file>(见 Source/cmake.cxx#L310),并在 Source/cmake.cxx#L2150-L2153 处将 preset 展开后的ToolchainFile写入CMAKE_TOOLCHAIN_FILE缓存变量;Source/cmake.cxx#L2693-L2696 还支持从环境变量CMAKE_TOOLCHAIN_FILE读取该值。
关键事实:Toolchain File 本身是在配置阶段早期被加载的普通 CMake 脚本(
set(...)赋值即生效),它并非一个被include()的普通模块,而是在检测编译器之前由cmake主流程注入,因此其中的变量赋值会直接作用于后续的编译器探测。
语言启用机制
语言由 project() 命令启用。调用project()时,CMake 会设置该语言相关的内建变量,例如 CMAKE_CXX_COMPILER、CMAKE_CXX_COMPILER_ID 等。若顶层 CMakeLists.txt 中没有project()命令,CMake 会隐式生成一个。默认启用C和CXX两种语言。
只启用 C 语言:
project(C_Only C)不启用任何语言(可用于纯数据/配置项目):
project(MyProject NONE)在project()之后通过 enable_language() 追加启用语言:
enable_language(CXX)启用一种语言时,CMake 会为该语言查找编译器,并探测其供应商(vendor)与版本、目标架构与位宽、配套工具位置等信息。当前已启用的语言集合记录在 ENABLED_LANGUAGES 全局属性中。
从源码实现看,project()触发语言启用后,cmGlobalGenerator::EnableLanguages会加载对应的Modules/CMakeDetermine*Compiler.cmake与Modules/Platform/<Platform>-<Compiler>.cmake,例如Modules/CMakeDetermineCCompiler.cmake、Modules/Platform/Linux-GNU.cmake等,这些文件共同完成编译器 ID、版本和 ABI 探测。
与工具链相关的变量与属性
语言级编译器变量
以下变量与当前启用的语言一一对应,<LANG>可替换为C、CXX、Fortran、ASM、CUDA等:
| 变量 | 含义 |
|---|---|
| CMAKE_ _COMPILER | 用于<LANG>的编译器完整路径 |
| CMAKE_ _COMPILER_ID | CMake 使用的编译器标识(如GNU、Clang、MSVC、AppleClang) |
| CMAKE_ _COMPILER_VERSION | 编译器版本 |
| CMAKE_ _FLAGS | 会附加到该语言所有编译与链接调用的标志(含各配置对应的CMAKE_<LANG>_FLAGS_<CONFIG>,如CMAKE_C_FLAGS_RELEASE) |
| CMAKE_ _LINK_FLAGS | 4.3 新增;仅附加到由该语言驱动链接的调用(同样存在配置化等价变量) |
注意CMAKE_<LANG>_FLAGS同时作用于编译与链接驱动调用,而CMAKE_<LANG>_LINK_FLAGS(4.3 起)只作用于链接驱动,二者在链接阶段的语义差异是排查“链接时标志被吞”的关键。
链接语言的选择
CMake 需要决定用哪个编译器来驱动链接器。规则如下:
- 由目标(target)中各源文件的 LANGUAGE 属性决定;
- 对静态库,还参考其依赖库的
LANGUAGE; - 可通过 LINKER_LANGUAGE 目标属性覆盖默认选择。
典型场景:一个项目同时包含 C 与 Fortran 源文件时,链接通常应交给 Fortran 编译器驱动(以引入其运行时库),此时可显式设置set_target_properties(mylib PROPERTIES LINKER_LANGUAGE Fortran)。
工具链能力探测
CMake 提供 try_compile() 命令与多个模块,用于测试工具链的特定能力与可用性:
- CheckSourceCompiles(以及
CheckCSourceCompiles、CheckCXXSourceCompiles、CheckFortranSourceCompiles等) - CheckCXXSymbolExists
- CheckIncludeFile
这些 API 会以某种方式测试工具链,并将结果缓存(Cache 变量),避免下次运行 CMake 时重复探测。这也是为什么更换工具链后常常需要清理 CMakeCache.txt——缓存中的能力结论可能已失效。
部分工具链特性由 CMake 内建处理,无需编译测试:
- POSITION_INDEPENDENT_CODE:指定目标构建为位置无关代码(
-fPIC等),前提是编译器支持; - _VISIBILITY_PRESET与 VISIBILITY_INLINES_HIDDEN:在编译器支持时添加隐藏可见性标志。
从实现上看,try_compile会生成一个临时项目并在独立目录中执行编译(见 Source/cmTryCompileCommand.cxx)。这也是手册强调“Toolchain File 中不要依赖CMAKE_SOURCE_DIR/CMAKE_BINARY_DIR”的原因:在try_compile的上下文中,这些变量会被重定向到临时项目,取值不可预期;应优先使用始终有确定值的 CMAKE_CURRENT_LIST_DIR 来解析路径。
交叉编译概述:加载 Toolchain File
若以命令行参数--toolchain path/to/file或-DCMAKE_TOOLCHAIN_FILE=path/to/file调用 cmake(1),该文件会在早期被加载以设置编译器相关值。当 CMake 处于交叉编译时,CMAKE_CROSSCOMPILING 变量被置为true。
典型的交叉编译配置流程为:
$ cmake ../src -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake在源码层面,toolchain 文件路径会写入缓存;Source/cmGlobalGenerator.cxx#L717-L739 显示:配置阶段会读取构建目录下的CMakeSystem.cmake,若检测到CMAKE_TOOLCHAIN_FILE与本次输入值不一致,会将该变量标记为需要删除的缓存变更并重新配置,因为“toolchain 文件变化会使内省结果失效”。
Toolchain File 编写注意事项:
- 不要使用
CMAKE_SOURCE_DIR或CMAKE_BINARY_DIR:它们在try_compile等不同上下文中取值不同;应使用 CMAKE_CURRENT_LIST_DIR 定位 Toolchain File 同目录下的工具,它始终具有明确、可预期的值。
通用 Toolchain File 骨架
综合多平台场景,一份通用 Toolchain File 通常包含:
# 目标平台与架构(CMake 标识符) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) # 交叉根文件系统与安装暂存路径(均可选) set(CMAKE_SYSROOT /path/to/rootfs) set(CMAKE_STAGING_PREFIX /path/to/stage) # 编译器(完整路径或可搜索的名字) set(CMAKE_C_COMPILER /path/to/arm-gcc) set(CMAKE_CXX_COMPILER /path/to/arm-g++) set(CMAKE_ASM_COMPILER /path/to/arm-as) # 如启用 ASM # 查找规则:程序只在宿主上找,库/头/包只在目标上找 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)关键变量语义:
| 变量 | 说明 |
|---|---|
| CMAKE_SYSTEM_NAME | 目标平台的 CMake 标识符(Linux、Android、WindowsCE、QNX等),也是触发交叉编译的关键开关 |
| CMAKE_SYSTEM_PROCESSOR | 目标架构的 CMake 标识符(如arm、aarch64) |
| CMAKE_SYSROOT | 可选;sysroot 根目录,find_*命令会在此查找 |
| CMAKE_STAGING_PREFIX | 可选;宿主上用于install的暂存路径。注意 CMAKE_INSTALL_PREFIX始终是运行时安装位置,交叉编译时也不变 |
| CMAKE_ _COMPILER | 可设为完整路径,或设为名字让 CMake 在标准位置搜索 |
| CMAKE_TRY_COMPILE_TARGET_TYPE | 设为STATIC_LIBRARY可让 CMake 在能力检查时不尝试链接可执行文件(适合无法直接链接二进制的工具链) |
CMAKE_TRY_COMPILE_TARGET_TYPE在源码中对应 Source/cmTryCompileCommand.cxx#L57-L63:当其值为STATIC_LIBRARY时,try_compile 生成的目标类型为静态库。Renesas CC-RL 一节中正是用它规避测试可执行文件超出 const section 大小限制的问题。
CMAKE_FIND_ROOT_PATH_MODE_*的查找语义
默认情况下,find_*命令会依次查找 sysroot、CMAKE_FIND_ROOT_PATH 条目,以及宿主系统根前缀。交叉编译时,通常希望:
- 头文件、库、包:只在目标系统前缀中查找(
ONLY); - 必须作为构建一部分在宿主上运行的程序(编译器、链接器、打包工具等):只在宿主上查找(
NEVER)。
这就是CMAKE_FIND_ROOT_PATH_MODE_PROGRAM/LIBRARY/INCLUDE/PACKAGE四个变量的用途,取值均为NEVER、ONLY或BOTH(默认)。实现上,Source/cmFindCommon.cxx#L160 会按查找路径类别动态读取CMAKE_FIND_ROOT_PATH_MODE_<类别>对应的值来约束搜索范围。
面向 Linux 的交叉编译
一份典型的面向 Linux(如树莓派)的交叉编译 Toolchain File:
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_SYSROOT /home/devel/rasp-pi-rootfs) set(CMAKE_STAGING_PREFIX /home/devel/stage) set(tools /home/devel/gcc-4.7-linaro-rpi-gnueabihf) set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc) set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++) 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)说明:CMAKE_SYSTEM_NAME与CMAKE_SYSTEM_PROCESSOR是必填项;CMAKE_SYSROOT与CMAKE_STAGING_PREFIX可选。若工具链无法直接链接可执行文件,可追加set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)。
面向 Cray Linux 环境(CLE)的交叉编译
Cray 登录节点与计算节点交叉编译无需单独的 Toolchain File:在命令行指定-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment即可保证正确的构建设置与搜索路径(对应平台模块为 Modules/Platform/CrayLinuxEnvironment.cmake 与 Modules/Platform/CrayLinuxEnvironment-Initialize.cmake)。平台会从当前环境变量拉取配置,并在存在且已加载时使用 Cray Programming Environment 的PrgEnv-*模块中的编译器包装器。
- CLE 默认仅支持静态库;设置环境变量
CRAYPE_LINK_TYPE=dynamic可启用共享库。 - 不指定
CMAKE_SYSTEM_NAME时,配置阶段按标准 Linux 环境以主机模式运行;此时若未覆盖,PrgEnv-*包装器会被使用——登录节点构建通常不希望这样。 - 例外:直接在 NID 上构建(而非从登录节点交叉编译)时可以使用包装器。
- 若为登录节点构建软件:要么先
unload已加载的PrgEnv-*模块,要么显式让 CMake 使用/usr/bin下的系统编译器。 - 若为计算节点构建:如上所述指定
CMAKE_SYSTEM_NAME=CrayLinuxEnvironment即可。
使用 Clang 交叉编译
Clang 等编译器本身即是交叉编译器。通过CMAKE_ _COMPILER_TARGET向编译器传递目标三元组(triple):
set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) set(triple arm-linux-gnueabihf) set(CMAKE_C_COMPILER clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_CXX_COMPILER clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple})另外,某些编译器不自带链接器等配套工具,但允许指定外部工具链位置供编译器驱动使用。可在 Toolchain File 中设置CMAKE_ _COMPILER_EXTERNAL_TOOLCHAIN来传递该路径。典型场景:用 Clang 驱动 GNU 工具链(--gcc-toolchain),其配套 binutils 来自交叉 GCC 安装目录。
面向 QNX 的交叉编译
QNX 的 QCC 编译器与 Clang 一样是天然的交叉编译器,同样通过CMAKE_<LANG>_COMPILER_TARGET传递目标:
set(CMAKE_SYSTEM_NAME QNX) set(arch gcc_ntoaarch64) set(CMAKE_C_COMPILER qcc) set(CMAKE_C_COMPILER_TARGET ${arch}) set(CMAKE_CXX_COMPILER q++) set(CMAKE_CXX_COMPILER_TARGET ${arch}) set(CMAKE_SYSROOT $ENV{QNX_TARGET})arch的值(如gcc_ntoaarch64)是 QNX 定义的目标变体名,决定 QCC 选择的 CPU 目标;sysroot 直接取环境变量QNX_TARGET。
面向 Windows CE 的交叉编译
面向 Windows CE 交叉编译要求系统安装对应 SDK,通常位于C:/Program Files (x86)/Windows CE Tools/SDKs。配置 Visual Studio 生成器的 Toolchain File 形如:
set(CMAKE_SYSTEM_NAME WindowsCE) set(CMAKE_SYSTEM_VERSION 8.0) set(CMAKE_SYSTEM_PROCESSOR arm) set(CMAKE_GENERATOR_TOOLSET CE800) # 8.0 可省略 set(CMAKE_GENERATOR_PLATFORM SDK_AM335X_SK_WEC2013_V310)- CMAKE_GENERATOR_PLATFORM 告诉生成器使用哪个 SDK;
- CMAKE_SYSTEM_VERSION 告诉生成器使用哪个 Windows CE 版本。目前开箱支持 8.0(Windows Embedded Compact 2013);其他版本可能需要将 CMAKE_GENERATOR_TOOLSET 设置为正确值。
面向 Windows 10 通用应用(UWP)的交叉编译
配置 Visual Studio 生成器构建 Windows 10 通用应用:
set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 10.0)Windows 10 通用应用同时面向 Windows Store 与 Windows Phone。CMAKE_SYSTEM_VERSION需设为10.0或更高。CMake 按 CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION 变量文档所述选择 Windows SDK。
面向 Windows Phone / Windows Store 的交叉编译
Windows Phone:
set(CMAKE_SYSTEM_NAME WindowsPhone) set(CMAKE_SYSTEM_VERSION 8.1)Windows Store:
set(CMAKE_SYSTEM_NAME WindowsStore) set(CMAKE_SYSTEM_VERSION 8.1)二者均用于配置 Visual Studio 生成器。
面向 ADSP SHARC/Blackfin 的交叉编译
面向 ADSP SHARC 或 Blackfin 交叉编译:
- 设置 CMAKE_SYSTEM_NAME 为
ADSP; - 设置 CMAKE_SYSTEM_PROCESSOR 为去掉
ADSP-前缀的“部件号”,例如21594、SC589;该值不区分大小写。
CMake 会自动在默认安装位置搜索 CCES 或 VDSP++ 安装并选择最近版本;两者都装时优先 CCES。自定义安装路径可通过 CMAKE_ADSP_ROOT 变量或 ADSP_ROOT 环境变量设置。编译器(cc21k对应 SHARC,ccblkfn对应 Blackfin)会根据CMAKE_SYSTEM_PROCESSOR自动选择。
面向 Android 的交叉编译
环境选择规则
将 CMAKE_SYSTEM_NAME 设为Android即可启用 Android 交叉编译,其余配置取决于使用的 Android 开发环境:
- Visual Studio 生成器:需要 NVIDIA Nsight Tegra Visual Studio Edition 或 Visual Studio Tools for Android;
- Makefile 生成器 / Ninja:需要 NDK 或 Standalone Toolchain。
CMake 按以下顺序选择环境(任一命中即止):
- 若 CMAKE_ANDROID_NDK 已设置 → 使用指定位置的 NDK;
- 否则若 CMAKE_ANDROID_STANDALONE_TOOLCHAIN 已设置 → 使用 Standalone Toolchain;
- 否则若 CMAKE_SYSROOT 形如
<ndk>/platforms/android-<api>/arch-<arch>→ 提取<ndk>作为 NDK; - 否则若
CMAKE_SYSROOT形如<standalone-toolchain>/sysroot→ 提取<standalone-toolchain>作为 Standalone Toolchain; - 否则若 CMake 变量
ANDROID_NDK已设置 → 用作 NDK; - 否则若 CMake 变量
ANDROID_STANDALONE_TOOLCHAIN已设置 → 用作 Standalone Toolchain; - 否则若环境变量
ANDROID_NDK_ROOT或ANDROID_NDK已设置 → 用作 NDK; - 否则若环境变量
ANDROID_STANDALONE_TOOLCHAIN已设置 → 用作 Standalone Toolchain; - 否则报错:找不到 NDK 或 Standalone Toolchain。
从 3.20 起,若选中 NDK,其版本号会记录在 CMAKE_ANDROID_NDK_VERSION 变量中。
平台模块实现位于 Modules/Platform/Android-Initialize.cmake,其会按需include(${CMAKE_ANDROID_NDK}/build/cmake/hooks/...),将 NDK 自带的钩子(hooks)纳入配置流程。
使用 NDK 交叉编译
可配置 Makefile、Ninja 或 Visual Studio 生成器。相关变量:
| 变量 | 说明 |
|---|---|
| CMAKE_SYSTEM_NAME | 必须为Android |
| CMAKE_SYSTEM_VERSION | Android API level。未指定时:若 CMAKE_ANDROID_API 已设置则用之;否则若CMAKE_SYSROOT已设置则从 NDK 目录结构检测;否则用 NDK 中最新的 API level |
| CMAKE_ANDROID_ARCH_ABI | Android ABI(架构)。未指定时默认取armeabi、armeabi-v7a、arm64-v8a中第一个受支持的;CMAKE_ANDROID_ARCH 会自动由它计算得出。另参见 CMAKE_ANDROID_ARM_MODE 与 CMAKE_ANDROID_ARM_NEON |
| CMAKE_ANDROID_NDK | NDK 根目录的绝对路径;未指定时按上述选择规则取默认 |
| CMAKE_ANDROID_NDK_DEPRECATED_HEADERS | 置真以使用已废弃的按 API level 划分的头文件,而非统一头文件;默认 false(NDK 不提供统一头文件时除外) |
| CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION | NDK r19 及以上必须不设置或设为clang;r18 及以下设为要选用的 NDK 工具链版本,默认最新 GCC 工具链 |
| CMAKE_ANDROID_STL_TYPE | 指定使用的 C++ 标准库;未指定时按变量文档选择默认 |
自动计算并提供以下变量:
- CMAKE_ _ANDROID_TOOLCHAIN_PREFIX:NDK 工具链中 binutils 的绝对路径前缀;
- CMAKE_ _ANDROID_TOOLCHAIN_SUFFIX:NDK 工具链中 binutils 的宿主平台后缀。
Toolchain File 示例:
set(CMAKE_SYSTEM_NAME Android) set(CMAKE_SYSTEM_VERSION 21) # API level set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) set(CMAKE_ANDROID_NDK /path/to/android-ndk) set(CMAKE_ANDROID_STL_TYPE gnustl_static)也可不使用 Toolchain File,直接在命令行指定:
$ cmake ../src \ -DCMAKE_SYSTEM_NAME=Android \ -DCMAKE_SYSTEM_VERSION=21 \ -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \ -DCMAKE_ANDROID_NDK=/path/to/android-ndk \ -DCMAKE_ANDROID_STL_TYPE=gnustl_static使用 Standalone Toolchain 交叉编译
可配置 Makefile 或 Ninja 生成器。相关变量:
| 变量 | 说明 |
|---|---|
| CMAKE_SYSTEM_NAME | 必须为Android |
| CMAKE_ANDROID_STANDALONE_TOOLCHAIN | Standalone Toolchain 根目录的绝对路径;其下必须存在sysroot子目录;未指定时按上述规则取默认 |
| CMAKE_ANDROID_ARM_MODE | 当工具链面向 ARM 时,可选设为ON以面向 32 位 ARM 而非 16 位 Thumb |
| CMAKE_ANDROID_ARM_NEON | 当工具链面向 ARM v7 时,可选设为ON以面向 ARM NEON 设备 |
自动计算并提供:
- CMAKE_SYSTEM_VERSION:从 Standalone Toolchain 检测出的 API level;
- CMAKE_ANDROID_ARCH_ABI:从 Standalone Toolchain 检测出的 ABI;
- CMAKE_ _ANDROID_TOOLCHAIN_PREFIX与CMAKE_ _ANDROID_TOOLCHAIN_SUFFIX:binutils 前缀与宿主后缀。
Toolchain File 示例:
set(CMAKE_SYSTEM_NAME Android) set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN /path/to/android-toolchain)命令行等价写法:
$ cmake ../src \ -DCMAKE_SYSTEM_NAME=Android \ -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=/path/to/android-toolchain使用 NVIDIA Nsight Tegra Visual Studio Edition
配置 Visual Studio 生成器以使用 Nsight Tegra 构建 Android 应用:
set(CMAKE_SYSTEM_NAME Android)CMAKE_GENERATOR_TOOLSET 可用于选择 Nsight Tegra 的 "Toolchain Version" 值。还可参见以下目标属性:ANDROID_API、ANDROID_API_MIN、ANDROID_ARCH、ANDROID_ASSETS_DIRECTORIES、ANDROID_GUI、ANDROID_JAR_DEPENDENCIES、ANDROID_JAR_DIRECTORIES、ANDROID_JAVA_SOURCE_DIR、ANDROID_NATIVE_LIB_DEPENDENCIES、ANDROID_NATIVE_LIB_DIRECTORIES、ANDROID_PROCESS_MAX、ANDROID_PROGUARD、ANDROID_PROGUARD_CONFIG_PATH、ANDROID_SECURE_PROPS_PATH、ANDROID_SKIP_ANT_STEP、ANDROID_STL_TYPE 与 ANDROID_ANT_ADDITIONAL_OPTIONS。
面向 iOS、tvOS、visionOS、watchOS 的交叉编译
向这些 Apple 平台交叉编译时推荐使用 Xcode 生成器;Unix Makefiles 或 Ninja 也可用,但需要项目自行处理目标 CPU 选择与代码签名等更多环节。
将 CMAKE_SYSTEM_NAME 设为下表对应值即可定位对应平台,默认选择最新的 Device SDK;与所有 Apple 平台一致,可通过 CMAKE_OSX_SYSROOT 选择不同 SDK(如模拟器 SDK),但通常无需显式设置(见下文“设备与模拟器切换”)。可用xcodebuild -showsdks列出可用 SDK。
| OS | CMAKE_SYSTEM_NAME | Device SDK(默认) | Simulator SDK | Catalyst SDK |
|---|---|---|---|---|
| iOS | iOS | iphoneos | iphonesimulator | macosx |
| tvOS | tvOS | appletvos | appletvsimulator | N/A |
| visionOS | visionOS | xros | xrsimulator | N/A |
| watchOS | watchOS | watchos | watchsimulator | N/A |
例如,为 iOS 创建 CMake 配置只需:
cmake .. -GXcode -DCMAKE_SYSTEM_NAME=iOSCMAKE_OSX_ARCHITECTURES 可为设备与模拟器同时设置架构;CMAKE_OSX_DEPLOYMENT_TARGET 可设置部署目标。
以下示例在一个通用二进制(universal binary)中安装 5 个架构的 iOS 库,并在需要处自动添加-miphoneos-version-min=9.3或-mios-simulator-version-min=9.3编译标志。注意:示例中的 CMAKE_IOS_INSTALL_COMBINED 已废弃,此做法不再推荐:
$ cmake -S. -B_builds -GXcode \ -DCMAKE_SYSTEM_NAME=iOS \ "-DCMAKE_OSX_ARCHITECTURES=armv7;armv7s;arm64;i386;x86_64" \ -DCMAKE_OSX_DEPLOYMENT_TARGET=9.3 \ -DCMAKE_INSTALL_PREFIX=`pwd`/_install \ -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=NO \ -DCMAKE_IOS_INSTALL_COMBINED=YES配套的 CMakeLists.txt 与验证命令:
# CMakeLists.txt cmake_minimum_required(VERSION 3.14) project(foo) add_library(foo foo.cpp) install(TARGETS foo DESTINATION lib)$ cmake --build _builds --config Release --target install用lipo检查通用二进制:
$ lipo -info _install/lib/libfoo.a Architectures in the fat file: _install/lib/libfoo.a are: i386 armv7 armv7s x86_64 arm64用otool检查最低 iOS 版本:
$ otool -l _install/lib/libfoo.a | grep -A2 LC_VERSION_MIN_IPHONEOS cmd LC_VERSION_MIN_IPHONEOS cmdsize 16 version 9.3代码签名
Apple 嵌入式平台的部分构建产物强制要求代码签名。使用 Xcode 生成器且需要/希望签名时,可通过 CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM 指定开发团队 ID,该 ID 会写入生成的 Xcode 工程。默认情况下,CMake 在内部配置阶段(编译器 ID 探测与特性检测)会避免代码签名需求。
设备与模拟器切换
配置任一嵌入式平台时,可面向真机或模拟器;两者有各自独立的 SDK,而 CMake 在配置阶段只支持指定一个 SDK,因此必须在配置时二选一。使用 Xcode 生成器时这个限制影响较小——Xcode 仍允许在配置只针对其一的情况下,同时为设备或模拟器构建;从 Xcode IDE 构建时按所选 "destination" 平台进行,命令行构建时可直接向底层构建工具(xcodebuild)传-sdk参数:
$ cmake --build ... -- -sdk iphonesimulator注意:配置阶段所做的检查针对配置时的 SDK,未必适用于其他 SDK。find_package()、find_library() 等命令只存储和使用所配置 SDK/平台的信息,跨设备/模拟器切换时可能出问题。让“设备 + 模拟器”配置同时工作的规则:
- 使用显式
-l链接标志,例如target_link_libraries(foo PUBLIC "-lz"); - 使用显式
-framework链接标志,例如target_link_libraries(foo PUBLIC "-framework CoreFoundation"); - 只对通过 CMAKE_IOS_INSTALL_COMBINED 特性安装的库使用
find_package。
面向 Emscripten(WebAssembly)的交叉编译
4.2 新增支持。
将 CMAKE_SYSTEM_NAME 设为Emscripten即可配置面向 Emscripten 的交叉编译。Toolchain File 示例:
set(CMAKE_SYSTEM_NAME Emscripten) set(CMAKE_C_COMPILER /path/to/emcc) set(CMAKE_CXX_COMPILER /path/to/em++)对应的平台模块为 Modules/Platform/Emscripten.cmake,其中将共享库后缀设为.wasm、可执行文件后缀设为.js(见 Modules/Platform/Emscripten.cmake#L18-L19),即链接产物为.wasm模块与.js加载器。另有配套的 Modules/Platform/Emscripten-Clang.cmake、Emscripten-Determine-*.cmake等文件处理编译器探测细节。
面向 Renesas 编译器的交叉编译
Renesas 交叉编译至少需要指定:
| 变量 | 说明 |
|---|---|
| CMAKE_SYSTEM_NAME | 设为Generic,必须指定以启用交叉编译 |
| CMAKE_C_COMPILER | Renesas C 编译器路径,如ccrx、ccrl、ccrh |
| CMAKE_C_FLAGS | 编译器要求的-isa=或-cpu=标志 |
Renesas CC-RX
set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_C_COMPILER "ccrx.exe") set(CMAKE_ASM_COMPILER "ccrx.exe") # 如启用 ASM 语言 set(CMAKE_C_FLAGS "-isa=rxv3") # 指定目标 RX CPU 版本 set(CMAKE_EXE_LINKER_FLAGS "-lnkopt=<your linker option here>")Renesas CC-RL
set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_C_COMPILER "ccrl.exe") set(CMAKE_ASM_COMPILER "ccrl.exe") # 如启用 ASM 语言 set(CMAKE_C_FLAGS "-cpu=S3") # 指定目标 RL CPU 版本 # 避免测试可执行文件超出 const section 大小限制 set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # 通过编译器驱动指定设备文件与段布局链接选项 set(CMAKE_EXE_LINKER_FLAGS "-lnkopt=-device=dr5f10y14.dvf -lnkopt=-auto_section_layout")Renesas CC-RH
set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_C_COMPILER "ccrh.exe") set(CMAKE_ASM_COMPILER "ccrh.exe") # 如启用 ASM 语言 set(CMAKE_C_FLAGS "-Xcommon=rh850") # 指定目标 RH850 CPU 版本 set(CMAKE_EXE_LINKER_FLAGS "-lnkopt=<your linker option here>")实战总结:编写 Toolchain File 的检查清单
- 必填:
CMAKE_SYSTEM_NAME(触发交叉编译模式的开关);目标平台不同,其余必填项不同(如 Android 还需CMAKE_ANDROID_NDK或CMAKE_ANDROID_STANDALONE_TOOLCHAIN); - 架构:
CMAKE_SYSTEM_PROCESSOR(ARM 平台还需CMAKE_ANDROID_ARCH_ABI等); - 编译器:
CMAKE_<LANG>_COMPILER,必要时补CMAKE_<LANG>_COMPILER_TARGET(Clang/QCC)、CMAKE_<LANG>_COMPILER_EXTERNAL_TOOLCHAIN(外部 binutils); - 根文件系统:
CMAKE_SYSROOT(可选); - 安装布局:
CMAKE_STAGING_PREFIX(可选,仅宿主暂存);CMAKE_INSTALL_PREFIX始终是运行时安装位置; - 查找范围:根据产物类型设置
CMAKE_FIND_ROOT_PATH_MODE_{PROGRAM,LIBRARY,INCLUDE,PACKAGE}为NEVER/ONLY/BOTH; - 能力检查:无法链接可执行文件时设
CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY; - 路径安全:Toolchain File 内解析路径用
CMAKE_CURRENT_LIST_DIR,不要依赖CMAKE_SOURCE_DIR/CMAKE_BINARY_DIR; - 与 preset 集成:3.19 起可在 cmake-presets(7) 中通过
toolchainFile字段指定,替代命令行--toolchain; - 缓存失效:更换 Toolchain File 后 CMake 会检测到
CMAKE_TOOLCHAIN_FILE变化并触发重新配置(Source/cmGlobalGenerator.cxx#L724-L739);若能力探测结果异常,清理构建目录的CMakeCache.txt与CMakeFiles/重新配置。
上述所有变量、属性与命令的权威定义均可进一步查阅本仓库 Help/variable(828 个变量文档)、Help/prop_tgt(456 个目标属性文档)与 Help/command(148 个命令文档)目录;对应实现位于 Source 与 Modules(含 Modules/Platform 下 779 个平台相关.cmake文件)。围绕具体平台的落地配置,可结合 Modules/Platform 中对应平台模块(如Linux-GNU.cmake、Android-Initialize.cmake、Emscripten.cmake、CrayLinuxEnvironment.cmake等)进一步核对默认行为。
- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
相关推荐
Academic Research Skills 全景上手:10 阶段流水线、30 秒装好插件,四款技能加三个伙伴讲透
Academic Research Skills 全景上手:10 阶段流水线、30 秒装好插件,四款技能加三个伙伴讲透 写论文最磨人的往往不是动笔那一刻,而是动
AI 技能科研AI 评测人工智能F´ CMake Toolchain 文件完全指南:交叉编译工具链与平台文件配置实战
F´ CMake Toolchain 文件完全指南:交叉编译工具链与平台文件配置实战 导读 本文基于 F´(飞行软件与嵌入式系统框架)官方用户指南中的 CMak
嵌入式系统编程Wireshark CMake工具链交叉编译:终极实战指南
想要在嵌入式设备上运行强大的网络协议分析工具Wireshark吗?🚀 本教程将带你一步步掌握Wireshark的CMake工具链交叉编译技巧,让你的网络分析能
网络通信
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考