CMake详解

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

✅ 第二阶段:原生构建工具执行(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 的其他 target
  • INTERFACE:仅暴露给使用者(常用于 header-only 库)

四、CMake 如何实现跨平台?

1. 抽象编译器差异

  • 自动处理不同编译器的标志:

    cmake 复制代码
    target_compile_options(app PRIVATE -Wall)  # GCC/Clang
    # CMake 自动转为 MSVC 的 /W3

2. 平台无关的路径与命令

  • 使用 / 作为路径分隔符(CMake 自动转为 Windows 的 \
  • 提供跨平台命令(如 file(COPY ...), execute_process()

3. Find 模块与 Config 模块

  • 自动查找第三方库:

    cmake 复制代码
    find_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+)

  1. 使用 target-based 命令target_include_directories 而非 include_directories

  2. 避免全局设置 (如 set(CMAKE_CXX_FLAGS ...)

  3. 优先使用 IMPORTED target (如 OpenSSL::SSL 而非直接传路径)

  4. 启用策略兼容性

    cmake 复制代码
    cmake_policy(SET CMP0091 NEW)  # 控制 C++ 标准行为
  5. 使用 FetchContent 管理依赖 (CMake 3.11+):

    cmake 复制代码
    include(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,需创建软链接:

bash 复制代码
sudo 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+,省去大量环境配置麻烦。


相关推荐
小龙报2 小时前
【算法通关指南:算法基础篇(四)】二维差分专题:1.【模板】差分 2.地毯
c语言·数据结构·c++·深度学习·神经网络·算法·自然语言处理
CQ_YM2 小时前
Linux文件IO
linux·c语言·文件io
缘三水3 小时前
【C语言】17.字符函数和字符串函数
c语言·开发语言·语法
一枝小雨3 小时前
单例模式简析:C语言实现单例模式
c语言·单例模式·嵌入式
helloworddm3 小时前
NSIS编写C/C++扩展
c语言·开发语言·c++
sinat_602035364 小时前
翁恺 11字符串
c语言
渡我白衣4 小时前
计算机组成原理(4):计算机的层次结构与工作原理
运维·c语言·网络·c++·人工智能·笔记·硬件架构
C语言小火车4 小时前
红黑树(C/C++ 实现版)—— 用 “带配重的书架” 讲透本质
c语言·开发语言·c++·红黑树
猫猫的小茶馆4 小时前
【ARM】VSCode和IAR工程创建
c语言·开发语言·arm开发·ide·vscode·stm32·嵌入式硬件