CMake不直接调用gcc/g++,而是生成Makefile等构建脚本,由make/ninja执行编译;它通过语义化指令(如set、target_compile_options)控制传给GCC/G++的选项,而非拼接shell命令。

gcc 和 g++ 在 CMake 构建中实际不直接调用
CMake 本身不执行 gcc 或 g++,它只生成构建脚本(如 Makefile),真正调用编译器的是 make 或 ninja。所以“GCC 配合 CMake”本质是:CMake 控制哪些选项传给底层 GCC/G++,而不是你在 CMakeLists.txt 里写 gcc -o ...。
常见误解是以为 CMake 像 shell 脚本一样拼接 gcc 命令——它不是。CMake 把编译器选择、标准、宏定义、头文件路径、链接库等拆成语义化指令,由生成器转为对应平台的原生命令。
-
CMAKE_C_COMPILER和CMAKE_CXX_COMPILER可显式指定路径,例如:cmake -DCMAKE_CXX_COMPILER=/usr/bin/clang++ .. - 不设时,默认用系统
PATH中第一个gcc或g++;g++会自动链接 STL,gcc编译 .cpp 文件必须加-lstdc++,但 CMake 内部已处理这点,无需手动干预 - 交叉编译时,必须通过 toolchain 文件设置
CMAKE_C_COMPILER等,不能靠环境变量临时覆盖
影响 GCC 行为的关键 CMake 变量和命令
这些配置最终会变成 g++ -std=c++17 -O2 -Wall -I/path/to/include ... 这类命令的一部分:
-
set(CMAKE_CXX_STANDARD 17)→ 控制-std=gnu++17或-std=c++17(取决于CMAKE_CXX_EXTENSIONS) -
set(CMAKE_CXX_STANDARD_REQUIRED ON)→ 若编译器不支持 C++17,CMake 直接报错,不降级 -
add_compile_options(-Wall -Wextra)→ 全局生效,对所有 target 生效;但更推荐用target_compile_options(my_target PRIVATE ...),避免污染依赖项 -
set(CMAKE_CXX_FLAGS "-g -O0")是老写法,易被覆盖;现代项目应优先用target_compile_options+target_compile_features -
target_compile_features(my_target PRIVATE cxx_auto_type cxx_range_for)→ 比单纯设标准更精确,CMake 会自动补全必要 flag(如-std=c++11)并检查编译器能力
链接阶段对应 GCC 的 -L/-l 参数怎么写
CMake 不用 -L/path -lfoo 这种裸写法,而是分三步:找库、声明路径、链接目标:
-
find_library(FOO_LIB foo PATHS /opt/foo/lib)→ 类似gcc -L/opt/foo/lib -lfoo中的定位动作 -
link_directories(/opt/foo/lib)已过时,应改用target_link_libraries(my_target PRIVATE ${FOO_LIB})或target_link_libraries(my_target PRIVATE foo)(后者要求foo已注册为 imported target) - 真正生效的是
target_link_libraries(my_target PRIVATE Art_DAQ_64)—— 这会触发 CMake 在链接时插入-lArt_DAQ_64,并自动查找-L路径(来自find_package或link_directories,但后者不推荐) - 注意:如果
Art_DAQ_64是你自己的库,应先用add_library(Art_DAQ_64 SHARED ...)定义,再target_link_libraries,否则 CMake 找不到符号
调试和优化选项如何映射到 GCC
CMake 默认不加调试或优化标志,必须显式启用:
-
-g对应set(CMAKE_BUILD_TYPE Debug)(需在cmake命令中传入:cmake -DCMAKE_BUILD_TYPE=Debug ..);RelWithDebInfo会同时加-O2 -g -
-O2来自CMAKE_BUILD_TYPE=Release;-O0来自Debug;-O3需手动加:target_compile_options(my_target PRIVATE $:-O3>) -
-rdynamic(用于 backtrace 符号)不能直接写进CMAKE_CXX_FLAGS,正确方式是:target_link_options(my_target PRIVATE $:-rdynamic>) -
-Werror这类严格检查,建议按 target 设置:target_compile_options(my_target INTERFACE -Werror),避免影响第三方依赖
最易被忽略的是构建类型(CMAKE_BUILD_TYPE)必须在首次运行 cmake 时指定,后续修改需删掉 build 目录重来;另外,target_link_libraries 的 PRIVATE/INTERFACE/PUBLIC 作用域不只影响链接,还决定头文件路径和编译选项是否透传——这点一旦配错,下游 target 就会编译失败。











