CMake(Cross-platform Make)是一个开源的、跨平台的构建系统生成器(build system generator) ,其核心目标是:用统一的方式描述项目结构和构建逻辑,然后为不同平台(如 Linux、Windows、macOS)和不同编译工具链(如 GCC、Clang、MSVC、Ninja 等)自动生成对应的原生构建文件。
一、CMake 的核心原理:两阶段构建
CMake 采用 "配置(Configure) + 生成(Generate)" → "构建(Build)" 的两阶段模型:
源代码 + CMakeLists.txt
↓
[ CMake ]
↓
平台原生构建系统
(Makefile / Ninja / VS .sln / Xcode project)
↓
[ make / ninja / msbuild ]
↓
可执行文件 / 库
✅ 第一阶段:CMake 配置与生成(cmake 命令)
- 解析
CMakeLists.txt文件(项目的构建脚本) - 检测系统环境(编译器、库、头文件、特性支持等)
- 根据用户指定的 生成器(Generator) 生成对应平台的构建文件
- Linux 默认:
Unix Makefiles→ 生成Makefile - Windows + Visual Studio:生成
.sln和.vcxproj - 跨平台快速构建:
Ninja→ 生成build.ninja
- Linux 默认:
✅ 第二阶段:原生构建工具执行(make / ninja 等)
- 调用系统原生工具(如
make)读取 CMake 生成的构建文件 - 实际编译、链接源代码,生成目标文件
🌟 关键思想 :CMake 不直接编译代码,它只是"翻译官",把高级构建描述转换成具体平台能理解的指令。
二、CMake 的核心组件
1. CMakeLists.txt
- 项目的构建脚本,使用 CMake 语言(DSL) 编写
- 支持变量、函数、条件判断、循环、宏等
- 从项目根目录开始,可嵌套子目录(每个子目录可有自己的
CMakeLists.txt)
cmake
cmake_minimum_required(VERSION 3.10)
project(MyApp)
add_executable(myapp main.cpp utils.cpp)
target_link_libraries(myapp ssl crypto)
2. 缓存机制(CMakeCache.txt)
- 在构建目录(build directory)中生成
- 存储配置阶段的检测结果(如编译器路径、库位置、用户选项等)
- 下次运行
cmake时会复用,避免重复检测 - 可通过
-DVAR=value覆盖缓存值
3. 生成器(Generator)
决定输出哪种构建系统:
bash
cmake -G "Unix Makefiles" .. # 默认(Linux)
cmake -G "Ninja" .. # 更快的构建
cmake -G "Visual Studio 17 2022" .. # Windows
4. 工具链文件(Toolchain File)
用于交叉编译,指定目标平台、编译器前缀等(如你之前问的 AArch64 工具链):
bash
cmake -DCMAKE_TOOLCHAIN_FILE=arm-toolchain.cmake ..
三、CMake 的关键概念
🔹 Target(目标)
CMake 的核心抽象单位,代表一个可构建实体:
add_executable(name ...)→ 可执行文件add_library(name ...)→ 静态库(STATIC)、动态库(SHARED)或接口库(INTERFACE)
✅ 现代 CMake 推荐基于 target 的设计(而非全局设置)。
🔹 属性(Properties)
每个 target 有属性,如:
INCLUDE_DIRECTORIES→ 头文件路径COMPILE_OPTIONS→ 编译选项LINK_LIBRARIES→ 链接的库
通过 target_* 命令设置(作用域隔离,避免污染):
cmake
target_include_directories(mylib PUBLIC include/)
target_compile_features(myapp PRIVATE cxx_std_17)
target_link_libraries(myapp PRIVATE OpenSSL::SSL)
🔹 PUBLIC / PRIVATE / INTERFACE
控制依赖传递性:
PRIVATE:仅自身使用,不暴露给使用者PUBLIC:自身使用 + 暴露给链接此 target 的其他 targetINTERFACE:仅暴露给使用者(常用于 header-only 库)
四、CMake 如何实现跨平台?
1. 抽象编译器差异
-
自动处理不同编译器的标志:
cmaketarget_compile_options(app PRIVATE -Wall) # GCC/Clang # CMake 自动转为 MSVC 的 /W3
2. 平台无关的路径与命令
- 使用
/作为路径分隔符(CMake 自动转为 Windows 的\) - 提供跨平台命令(如
file(COPY ...),execute_process())
3. Find 模块与 Config 模块
-
自动查找第三方库:
cmakefind_package(OpenSSL REQUIRED) # 使用 FindOpenSSL.cmake # 或 find_package(fmt CONFIG REQUIRED) # 使用 fmt 提供的 fmt-config.cmake
4. 生成器表达式(Generator Expressions)
在构建时动态计算值(支持条件、平台判断):
cmake
target_compile_definitions(app PRIVATE
$<$<CONFIG:Debug>:DEBUG_MODE>
$<$<PLATFORM_ID:Linux>:LINUX_BUILD>
)
五、CMake 的优势 vs 传统 Makefile
| 特性 | CMake | 手写 Makefile |
|---|---|---|
| 跨平台 | ✅ 原生支持 | ❌ 需手动适配 |
| 依赖管理 | ✅ 自动扫描头文件依赖 | ⚠️ 需手写或用 gcc -M |
| 第三方库集成 | ✅ find_package / FetchContent |
❌ 手动写路径和链接 |
| 构建类型切换 | ✅ CMAKE_BUILD_TYPE=Debug/Release |
❌ 需多套 Makefile |
| 可维护性 | ✅ 高层抽象,逻辑清晰 | ❌ 易出错,难维护 |
六、典型工作流程(Out-of-Source Build)
bash
myproject/
├── CMakeLists.txt
├── src/
│ └── main.cpp
└── build/ ← 推荐:单独构建目录
bash
cd myproject/build
cmake .. # 配置 + 生成 Makefile
cmake --build . # 等价于 make(跨平台)
# 或
make # Linux
ninja # 如果用 Ninja 生成器
✅ 永远不要在源码目录直接运行 cmake! 使用 out-of-source 构建保持干净。
七、现代 CMake 最佳实践(v3.0+)
-
使用 target-based 命令 (
target_include_directories而非include_directories) -
避免全局设置 (如
set(CMAKE_CXX_FLAGS ...)) -
优先使用 IMPORTED target (如
OpenSSL::SSL而非直接传路径) -
启用策略兼容性 :
cmakecmake_policy(SET CMP0091 NEW) # 控制 C++ 标准行为 -
使用
FetchContent管理依赖 (CMake 3.11+):cmakeinclude(FetchContent) FetchContent_Declare(googletest GIT_REPOSITORY https://github.com/google/googletest) FetchContent_MakeAvailable(googletest)
总结:CMake 的本质
CMake 是一个"元构建系统"------它不构建软件,而是构建"构建软件的系统"。
通过高层次的、平台无关的描述,CMake 将开发者从繁琐的平台适配和构建脚本维护中解放出来,专注于代码本身。
如果你正在开发 C/C++ 项目,尤其是需要跨平台或集成多个第三方库,CMake 几乎是行业标准选择(被 LLVM、KDE、ROS、TensorFlow 等广泛采用)。
CentOS7 cmake升级
📌 CentOS 7 官方仓库中的 CMake 版本非常老旧(2.8.x),无法满足现代 C++ 项目(尤其是使用 C++11/14/17、OpenSSL 3.x、target-based CMake 等特性)的需求。
✅ 解决方案:升级 CMake 到 3.10+(推荐 3.20+)
方法一:【推荐】使用官方二进制包安装(简单、安全、不依赖 EPEL)
bash
# 1. 下载新版 CMake(以 3.28.3 为例,可替换为其他版本)
cd /tmp
wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.tar.gz
# 2. 解压
tar -zxvf cmake-3.28.3-linux-x86_64.tar.gz
# 3. 复制到系统目录(或加入 PATH)
sudo cp -r cmake-3.28.3-linux-x86_64/* /usr/local/
# 4. 验证版本
/usr/local/bin/cmake --version
# 应显示 cmake version 3.28.3
# 5. (可选)替换旧版 cmake(谨慎操作)
sudo ln -sf /usr/local/bin/cmake /usr/bin/cmake
# 或临时用 PATH 优先
export PATH=/usr/local/bin:$PATH
✅ 优点:无需编译,开箱即用,不破坏系统原有包。
方法二:启用 EPEL 源并安装较新 CMake(但可能仍不够新)
CentOS 7 的 EPEL 仓库提供 cmake3 包(通常是 3.17 左右):
bash
# 1. 安装 EPEL
sudo yum install -y epel-release
# 2. 安装 cmake3
sudo yum install -y cmake3
# 3. 使用 cmake3 命令(注意不是 cmake)
cmake3 --version # 应为 3.17.x
# 4. 在构建时用 cmake3 代替 cmake
cmake3 -G "Unix Makefiles" .. -DCMAKE_BUILD_TYPE=Release ...
⚠️ 注意:此时命令是
cmake3,不是cmake。如果你的脚本写死cmake,需创建软链接:
bashsudo ln -s /usr/bin/cmake3 /usr/local/bin/cmake
方法三:从源码编译 CMake(不推荐,除非必须定制)
bash
sudo yum install -y gcc gcc-c++ make openssl-devel
wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3.tar.gz
tar -zxvf cmake-3.28.3.tar.gz
cd cmake-3.28.3
./bootstrap --prefix=/usr/local
make -j$(nproc)
sudo make install
🔍 验证修复
升级后运行:
bash
cmake --version
应输出类似:
cmake version 3.28.3
CMake suite maintained and supported by Kitware (kitware.com/cmake).
然后再执行你的构建命令:
bash
cd build
cmake -G "Unix Makefiles" .. \
-DCMAKE_BUILD_TYPE=Release \
-Dwith_openssl=/home/yys/SAF_QC_SDK-mixin-2.2.0/compents/openssl \
-Dwith_curl=/home/yys/SAF_QC_SDK-mixin-2.2.0/compents/curl \
-Dwith_ccl=/home/yys/SAF_QC_SDK-mixin-2.2.0/compents/ccl \
-Dwith_co_sign=/home/yys/SAF_QC_SDK-mixin-2.2.0/compents/coll_sign
⚠️ 重要提醒:CentOS 7 已停止维护!
如前所述,CentOS 7 已于 2024 年 6 月 30 日终止支持(EOL) ,不再接收任何安全更新。
即使你升级了 CMake,系统本身仍存在严重安全隐患。
🔄 建议:
- 短期:按上述方法升级 CMake 继续开发。
- 长期 :尽快迁移到受支持的系统,例如:
- Rocky Linux 8/9(RHEL 兼容,免费)
- AlmaLinux 8/9
- Ubuntu 22.04 LTS
这些新系统默认就包含 CMake 3.18+,省去大量环境配置麻烦。