当前位置: 首页 > web >正文

CMake 完全实战指南:从入门到精通

CMake 完全实战指南:从入门到精通

一、CMake 核心概念

1. CMake 是什么?

  • 构建系统生成器:生成各种平台的构建文件(Makefile、VS项目等)
  • 跨平台解决方案:同一份配置适配不同操作系统
  • 现代C/C++标准:推荐用于新项目开发

2. 核心工作流程

CMakeLists.txt
CMake生成器
目标平台
Linux/macOS
生成 Makefile
Windows
生成 VS项目
Ninja
生成 build.ninja
使用 make 构建
使用 MSBuild 构建
使用 ninja 构建

二、快速入门:5分钟上手

1. 基础项目结构

myapp/
├── CMakeLists.txt   # CMake配置文件
├── main.cpp         # 源代码
└── build/           # 构建目录(建议创建)

2. 最小 CMakeLists.txt

# 指定CMake最低版本
cmake_minimum_required(VERSION 3.10)# 设置项目名称
project(MyApp)# 添加可执行文件
add_executable(myapp main.cpp)

3. 构建命令序列

# 创建构建目录
mkdir build && cd build# 生成构建系统(默认生成Makefile)
cmake ..# 编译程序
make# 运行程序
./myapp

三、核心语法详解

1. 项目设置

cmake_minimum_required(VERSION 3.20)  # 最低版本要求
project(MyApp                         # 项目名称VERSION 1.0.0                     # 项目版本DESCRIPTION "My Awesome App"      # 项目描述LANGUAGES CXX                     # 使用语言(CXX=C++)
)

2. 添加可执行文件

# 添加单个源文件
add_executable(app_single main.cpp)# 添加多个源文件
add_executable(app_multi main.cpputils.cppgraphics.cpp
)# 使用变量管理源文件
set(APP_SOURCESsrc/main.cppsrc/utils.cppsrc/graphics.cpp
)
add_executable(myapp ${APP_SOURCES})

3. 添加库文件

# 创建静态库
add_library(math_static STATIC math.cpp)# 创建动态库(共享库)
add_library(math_shared SHARED math.cpp)# 头文件接口库(无源文件)
add_library(math_interface INTERFACE)
target_include_directories(math_interface INTERFACE include)

4. 链接库文件

# 链接库到可执行文件
target_link_libraries(myapp PRIVATE math_static)# 不同链接范围:
# PRIVATE   - 仅当前目标使用
# INTERFACE - 仅依赖者使用
# PUBLIC    - 当前目标和依赖者都使用

5. 包含头文件目录

# 全局包含(旧式)
include_directories(include)# 目标级包含(推荐)
target_include_directories(myappPRIVATE src${CMAKE_CURRENT_SOURCE_DIR}/includePUBLIC$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>$<INSTALL_INTERFACE:include>
)

四、生成 Makefile 实战

1. 基础生成命令

# 生成标准Makefile
cmake -S . -B build -G "Unix Makefiles"# 指定构建类型
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release# 设置安装前缀
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr/local

2. 高级生成选项

# 设置编译器
cmake -S . -B build -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++# 交叉编译配置
cmake -S . -B build \-DCMAKE_SYSTEM_NAME=Linux \-DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc \-DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++# 生成编译数据库(用于工具链)
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

3. 构建与安装

# 使用生成的Makefile构建
cd build
make -j$(nproc)       # 并行编译# 运行测试
make test# 安装程序
sudo make install# 清理构建
make clean

五、项目结构最佳实践

1. 标准项目布局

myproject/
├── CMakeLists.txt            # 根配置文件
├── cmake/                    # CMake模块
│   ├── FindMyLib.cmake
│   └── Config.cmake.in
├── include/                  # 公共头文件
│   └── myproject/
│       └── utils.h
├── src/                      # 源代码
│   ├── CMakeLists.txt
│   ├── main.cpp
│   └── utils.cpp
├── tests/                    # 测试代码
│   ├── CMakeLists.txt
│   └── test_utils.cpp
└── build/                    # 构建目录

2. 模块化配置示例

根 CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(MyProject VERSION 1.0)# 包含子目录
add_subdirectory(src)
add_subdirectory(tests)# 安装配置
include(GNUInstallDirs)
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

src/CMakeLists.txt:

# 添加库
add_library(myproject_lib STATIC utils.cpp)# 包含目录
target_include_directories(myproject_libPUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>$<INSTALL_INTERFACE:include>
)# 添加可执行文件
add_executable(myproject_main main.cpp)
target_link_libraries(myproject_main PRIVATE myproject_lib)# 安装规则
install(TARGETS myproject_lib myproject_mainARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

六、高级技巧

1. 条件编译

option(ENABLE_GPU "Enable GPU acceleration" OFF)if(ENABLE_GPU)find_package(CUDA REQUIRED)target_sources(myapp PRIVATE gpu_kernels.cu)target_link_libraries(myapp PRIVATE CUDA::cudart)
endif()# 命令行启用:cmake -DENABLE_GPU=ON ..

2. 第三方库集成

# 查找系统库
find_package(OpenSSL REQUIRED)# 使用FetchContent下载
include(FetchContent)
FetchContent_Declare(jsonGIT_REPOSITORY https://github.com/nlohmann/jsonGIT_TAG v3.11.2
)
FetchContent_MakeAvailable(json)# 链接库
target_link_libraries(myapp PRIVATE OpenSSL::SSLnlohmann_json::nlohmann_json
)

3. 自定义构建命令

# 生成配置文件
configure_file(config.h.in${CMAKE_CURRENT_BINARY_DIR}/config.h
)# 添加自定义目标
add_custom_target(DocumentationCOMMAND doxygen DoxyfileWORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}COMMENT "Generating API documentation"
)# 文件操作
file(GLOB_RECURSE SOURCES "src/*.cpp")
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/generated)

七、与 Makefile 混用场景

1. 逐步迁移策略

# 在CMake中调用遗留Makefile
add_custom_target(build_legacyCOMMAND make -j4 -C legacy_codeWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}COMMENT "Building legacy components"
)# 主目标依赖
add_executable(myapp main.cpp)
add_dependencies(myapp build_legacy)# 包含生成的头文件
target_include_directories(myapp PRIVATE legacy_code/output)

2. Makefile 调用 CMake

# Makefile 封装 CMake
BUILD_DIR = build
CMAKE = cmake
MAKE = makeall: configure buildconfigure:mkdir -p $(BUILD_DIR)cd $(BUILD_DIR) && $(CMAKE) ..build:cd $(BUILD_DIR) && $(MAKE)clean:rm -rf $(BUILD_DIR).PHONY: all configure build clean

八、最佳实践总结

  1. 源码与构建分离:始终在 build 目录构建

    cmake -S . -B build
    
  2. 目标级别配置:使用 target_* 命令替代全局命令

  3. 现代 CMake 特性

    • 使用 target_link_libraries 传递依赖
    • 使用生成器表达式 $<...>
    • 使用 PUBLIC/PRIVATE/INTERFACE 作用域
  4. 版本管理

    # 在根 CMakeLists.txt 中设置
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
  5. 工具集成

    # 启用测试
    enable_testing()
    add_test(NAME MyTest COMMAND test_executable)
    

九、常见问题解决

问题解决方案
“Could NOT find package”添加 find_package 路径:-DCMAKE_PREFIX_PATH=/path/to/lib
头文件找不到检查 target_include_directories 路径
链接错误确认 target_link_libraries 包含所需库
CMake版本过低升级CMake或调整 cmake_minimum_required
跨平台问题使用平台检测:if(WIN32) ... elseif(UNIX) ...
构建缓慢使用 ccache-DCMAKE_CXX_COMPILER_LAUNCHER=ccache

十、学习资源推荐

  1. 官方文档:https://cmake.org/cmake/help/latest/
  2. 现代CMake教程
    • https://modern-cmake-cn.github.io/ (中文)
    • https://cliutils.gitlab.io/modern-cmake/ (英文)
  3. 实战项目参考
    • https://github.com/ttroy50/cmake-examples
    • https://github.com/onqtam/awesome-cmake
  4. 在线练习:https://cmake.org/cmake/help/latest/guide/tutorial/index.html

掌握CMake是C/C++开发的必备技能。从简单项目开始实践,逐步应用高级特性,你将大大提升项目构建效率!

http://www.xdnf.cn/news/16713.html

相关文章:

  • 使用redis 作为消息队列时, 如何保证消息的可靠性
  • Leetcode 08 java
  • 鸿蒙Harmony-自定义List组件,解决List组件手势滑动点击卡住问题
  • Apache Ignite 的分布式队列(IgniteQueue)和分布式集合(IgniteSet)的介绍
  • 【dropdown组件填坑指南】鼠标从触发元素到下拉框中间间隙时,下拉框消失,怎么解决?
  • 0基礎網站開發技術教學(一) --(前端篇)--
  • 《Java 程序设计》第 9 章 - 内部类、枚举和注解
  • Java07--面向对象
  • 自动调优 vLLM 服务器参数(实战指南)
  • 如何用USRP捕获手机信号波形(下)协议分析
  • 怎么理解使用MQ解决分布式事务 -- 以kafka为例
  • 小白学OpenCV系列1-图像处理基本操作
  • 机器学习-十大算法之一线性回归算法
  • gTest测试框架的安装与配置
  • Qt 并行计算框架与应用
  • 项目优化中对象的隐式共享
  • 从单机架构到分布式:Redis为何成为架构升级的关键一环?
  • 【开源项目】轻量加速利器 HubProxy 自建 Docker、GitHub 下载加速服务
  • Less Less基础
  • Docker学习相关视频笔记(二)
  • 负载均衡、算法/策略
  • ROUGE-WE:词向量化革新的文本生成评估框架
  • Java 9 新特性解析
  • 考古学家 - 华为OD统一考试(JavaScript 题解)
  • 算法第29天|动态规划dp2:不同路径、不同路径Ⅱ、整数拆分、不同的二叉搜索树
  • uipath数据写入excel的坑
  • Python 程序设计讲义(25):循环结构——嵌套循环
  • 《Spring Cloud Gateway 深度剖析:从核心原理到企业级实战》
  • WAIC 2025观察:昇腾助力AI融入多元化生活场景
  • 理解Transformer解码器