cmake中设置编译器需优先指定cmake_c_compiler和cmake_cxx_compiler变量,可通过cmakelists.txt开头硬编码、工具链文件或命令行参数三种方式实现,其中工具链文件最可靠;设置必须在project()之前且首次配置生效,后续修改需清空构建目录。

直接在 CMakeLists.txt 里设 CMAKE_C_COMPILER 和 CMAKE_CXX_COMPILER
只要没运行过 cmake 配置,就能在 CMakeLists.txt 开头(cmake_minimum_required 之后、project 之前)硬编码指定编译器路径:
set(CMAKE_C_COMPILER "/usr/bin/clang")set(CMAKE_CXX_COMPILER "/usr/bin/clang++")
注意:这个设置只对当前 CMakeLists.txt 及其 add_subdirectory 下的子项目生效;如果已在构建目录中执行过 cmake,再改这里不会生效——CMake 会忽略已缓存的变量。
常见错误是把这两行写在 project() 之后,或写在子目录的 CMakeLists.txt 里试图覆盖根目录配置,结果无效。
用 -DCMAKE_TOOLCHAIN_FILE 指定工具链文件(推荐)
工具链文件是更可靠、更可复现的方式,尤其适合多平台或 CI 场景。它不依赖环境变量,也不污染源码树。
新建一个 toolchain.cmake,内容类似:
set(CMAKE_C_COMPILER "/opt/gcc-12.3.0/bin/gcc") set(CMAKE_CXX_COMPILER "/opt/gcc-12.3.0/bin/g++") set(CMAKE_SYSROOT "/opt/sysroot-arm64") set(CMAKE_FIND_ROOT_PATH "/opt/sysroot-arm64") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
然后运行:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake -S . -B build
关键点:CMAKE_TOOLCHAIN_FILE 必须在首次配置时传入;一旦 build 目录生成,后续 cmake --build 不需要再带这个参数,但也不能中途更换工具链文件——必须清空 build 目录重来。
命令行临时指定编译器(仅限调试或单次构建)
适合快速验证某版本编译器是否能通过:
cmake -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 -S . -B build
但要注意:
- 不能混用:比如只设
CMAKE_CXX_COMPILER而不设CMAKE_C_COMPILER,CMake 可能仍用系统默认的gcc编译 C 文件,导致 ABI 或标准不一致 - 路径必须绝对且可执行:
clang这种裸名依赖PATH,CI 中不可靠;应优先用/usr/bin/clang或$(which clang-15) - 该方式无法传递
CMAKE_SYSROOT或交叉编译相关变量,纯主机编译可用,嵌入式场景必须用工具链文件
CMAKE_CXX_STANDARD 和编译器选项不是一回事
很多人误以为设了 set(CMAKE_CXX_STANDARD 17) 就等于选了支持 C++17 的编译器——其实它只是让 CMake 自动加 -std=c++17,前提是当前编译器真支持。如果用的是 GCC 4.8,加了也没用,编译会报错。
真正控制编译器行为的,是前面三类方式选定的可执行文件本身。而 CMAKE_CXX_STANDARD、CMAKE_CXX_FLAGS、target_compile_options 都只是“喂给编译器的参数”。
所以顺序永远是:先确定用哪个编译器(路径),再决定喂它什么参数(标准、警告、优化)。漏掉前者,后者可能毫无意义,甚至掩盖真实问题。











