使用 Modern CMake 构建现代 C++ 项目:target从入门到实践

CMake 是 C++ 项目中最主流的构建系统之一,而随着 CMake 3.x ,4.x的发展,Modern CMake(现代 CMake)已成为推荐的最佳实践。

本篇文章将用通俗易懂的方式,带你从头理解并实践 Modern CMake 的核心理念,包括 target_* 系列命令、文件组织、安装与打包、测试下游项目、以及 CMakePresets 的使用。


一、Modern CMake 的核心思想

传统 CMake 中常用的 include_directories()add_definitions()file(GLOB ...) 等方式,容易带来依赖混乱。

Modern CMake 提倡:一切都通过 target 管理

核心原则是:

  • 每个库/程序用一个 add_library()add_executable() 创建 target
  • 使用 target_sources()target_include_directories()target_link_libraries() 配置 target 的行为
  • 避免全局变量,改用 target 作用域

二、目录结构设计

一个清晰的目录结构是 Modern CMake 的第一步:

foo_project/
├── CMakeLists.txt
├── include/
│   └── foo/
│       └── foo.h
├── src/
│   └── foo.cpp
├── test_app/
│   ├── main.cpp
│   └── CMakeLists.txt
├── CMakePresets.json
└── fooConfig.cmake.in
  • include/foo/foo.h:公共头文件
  • src/foo.cpp:实现文件
  • test_app/:测试程序

三、使用 target_sources 管理源码

Modern CMake 中推荐使用 target_sources() 明确地将头文件和源文件加入库:

add_library(foo)  # 创建目标 foo

target_sources(foo
  PUBLIC
    FILE_SET foo_headers TYPE HEADERS         # 定义一个文件集用于安装头文件
    BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
    FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/foo/foo.h
  PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/src/foo.cpp   # 私有源文件不被安装
)

这不仅清晰地标明了头文件和源文件的作用域,还能与 install() 一起自动安装。


四、安装与导出库

使用 install() 命令,可以将构建好的库、头文件和 CMake 配置文件安装到系统或本地目录中。

install(TARGETS foo
  EXPORT fooTargets                           # 导出 target 定义供下游使用
  FILE_SET foo_headers DESTINATION include    # 安装头文件到 include/
  LIBRARY DESTINATION lib                     # 安装 .so 动态库
  ARCHIVE DESTINATION lib                     # 安装 .a 静态库
)

install(EXPORT fooTargets                     # 安装导出文件
  FILE fooTargets.cmake
  NAMESPACE foo::                             # 添加命名空间,使用 foo::foo
  DESTINATION lib/cmake/foo
)

configure_package_config_file(
  fooConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake
  INSTALL_DESTINATION lib/cmake/foo
)

install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/fooConfig.cmake
  DESTINATION lib/cmake/foo
)

这样,其他项目就可以使用 find_package(foo) 来链接你的库了。


五、CMakePresets.json 的使用

CMakePresets.json 是 CMake 3.19+ 引入的新功能,可以统一预设构建参数:

{
  "version": 3,
  "configurePresets": [
    {
      "name": "release",
      "generator": "Unix Makefiles",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_INSTALL_PREFIX": "${sourceDir}/install"
      }
    }
  ],
  "buildPresets": [
    { "name": "release", "configurePreset": "release" }
  ]
}

使用方式非常简单:

cmake --preset=release                # 配置构建目录
cmake --build --preset=release       # 构建项目
cmake --install build                # 安装到 install/ 目录

实际终端输出如下所示:

$ cmake --preset=release
-- The CXX compiler identification is GNU 10.2.1
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../foo_project/build

$ cmake --build --preset=release
[ 50%] Building CXX object CMakeFiles/foo.dir/src/foo.cpp.o
[100%] Linking CXX static library libfoo.a
[100%] Built target foo

$ cmake --install build
-- Install configuration: "Release"
-- Installing: /.../foo_project/install/lib/libfoo.a
-- Installing: /.../foo_project/install/include/foo/foo.h
-- Installing: /.../foo_project/install/lib/cmake/foo/fooTargets.cmake
-- Installing: /.../foo_project/install/lib/cmake/foo/fooTargets-release.cmake
-- Installing: /.../foo_project/install/lib/cmake/foo/fooConfig.cmake

六、测试下游项目

在项目根目录下我们还设置了一个 test_app/ 目录,用于模拟一个使用 foo 库的下游项目。

// test_app/main.cpp
#include <foo/foo.h>

int main() {
    foo::say_hello();
    return 0;
}
# test_app/CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(test_app)

find_package(foo REQUIRED PATHS ../install/lib/cmake/foo)  # 查找安装后的包

add_executable(test_app main.cpp)
target_link_libraries(test_app PRIVATE foo::foo)  # 链接目标

构建和运行:

$ cmake -B build -DCMAKE_PREFIX_PATH=../install
-- The CXX compiler identification is GNU 10.2.1
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /.../test_app/build

$ cmake --build build
[ 50%] Building CXX object CMakeFiles/test_app.dir/main.cpp.o
[100%] Linking CXX executable test_app
[100%] Built target test_app

$ ./build/test_app
Hello from foo!

说明 foo 库已经成功安装并被下游项目引用。


七、安装生成的配置文件说明

安装完成后你会得到:

install/lib/cmake/foo/
├── fooConfig.cmake
├── fooTargets.cmake
└── fooTargets-release.cmake

这些文件让其他项目通过 find_package(foo REQUIRED PATHS ./install/lib/cmake/foo) 使用 foo::foo 目标,无需写死路径。

它们的作用分别是:

文件作用
fooConfig.cmake包配置入口文件,供 find_package() 加载
fooTargets.cmake定义导出的目标及其依赖
fooTargets-release.cmake定义 release 模式下库文件路径

八、总结

功能Modern CMake 命令说明
添加源码add_library() + target_sources()创建目标并声明源文件和头文件
设置包含路径target_include_directories()设置头文件查找路径
链接库target_link_libraries()连接依赖库
安装头文件install(FILE_SET ...)安装头文件并保持目录结构
导出配置install(EXPORT ...)安装 target 定义供 find_package() 使用
包配置文件configure_package_config_file()生成并安装 Config.cmake 供下游使用
使用 preset 构建cmake --preset=...快速构建统一配置
测试下游项目find_package() + target_link验证库是否被成功引用

通过 Modern CMake,构建脚本更可维护、更易复用、更标准化。

下一步,你可以尝试将自己的项目改造成 Modern CMake 风格,或基于本文的结构构建可复用的 C++ SDK。


📌 如需完整示例项目打包文件、测试程序或跨平台支持配置,欢迎留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值