CMake 高级特性

CMake 高级特性:掌握专业级项目管理

掌握基础后,CMake 的高级特性能让你处理大型、复杂、跨平台的真实项目。本篇聚焦最实用、最常用的高级特性,并附带完整示例。

1. 选项与配置(Options & Configurations)

option():让用户通过命令行控制构建行为。

option(BUILD_TESTS "Build unit tests" ON)
option(USE_OPENMP "Enable OpenMP support" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries instead of static" ON)

使用:

cmake .. -DBUILD_TESTS=OFF -DUSE_OPENMP=ON

示例:在 CMakeLists.txt 中应用

if(USE_OPENMP)
    find_package(OpenMP REQUIRED)
    target_link_libraries(myapp PRIVATE OpenMP::OpenMP_CXX)
endif()

if(BUILD_TESTS)
    add_subdirectory(tests)
endif()

2. 查找外部依赖(find_package)

用于查找并配置第三方库(系统安装或自带 Find 模块)。

常见示例:

find_package(Threads REQUIRED)              # pthread
find_package(OpenGL REQUIRED)
find_package(fmt CONFIG REQUIRED)           # 现代包(如 vcpkg/Conan 安装的)

target_link_libraries(myapp PRIVATE Threads::Threads)
target_link_libraries(myapp PRIVATE fmt::fmt)

find_package 的模式

  • MODULE:传统 FindXXX.cmake(旧方式)
  • CONFIG:优先现代 XXXConfig.cmake(推荐,vcpkg/Conan 默认提供)

3. 导入外部项目(FetchContent / ExternalProject)

无需用户预先安装依赖,直接在构建时下载并编译。

推荐:FetchContent(CMake 3.11+,简单同步)

include(FetchContent)

FetchContent_Declare(
    spdlog
    GIT_REPOSITORY https://github.com/gabime/spdlog.git
    GIT_TAG        v1.14.1
)

FetchContent_MakeAvailable(spdlog)

target_link_libraries(myapp PRIVATE spdlog::spdlog)

ExternalProject(更强大,支持复杂构建)
适合需要自定义构建步骤的库。

4. 生成导出头与安装规则(install + export)

让你的项目可以被其他 CMake 项目通过 find_package() 使用。

# 安装目标
install(TARGETS mylib myapp
    EXPORT MyLibTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

# 安装头文件
install(DIRECTORY include/ DESTINATION include)

# 导出配置
install(EXPORT MyLibTargets
    FILE MyLibTargets.cmake
    NAMESPACE MyLib::
    DESTINATION lib/cmake/MyLib
)

# 生成 Config 文件(让 find_package(MyLib CONFIG) 工作)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    MyLibConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY SameMajorVersion
)

configure_package_config_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/MyLibConfig.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake
    INSTALL_DESTINATION lib/cmake/MyLib
)

install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/MyLibConfigVersion.cmake
    DESTINATION lib/cmake/MyLib
)

使用你项目的其他项目:

find_package(MyLib REQUIRED)
target_link_libraries(other_app PRIVATE MyLib::mylib)

5. 自定义函数与宏(Functions & Macros)

封装重复逻辑,提高可维护性。

function(add_my_executable name)
    add_executable(${name} ${ARGN})
    target_include_directories(${name} PRIVATE include)
    target_compile_features(${name} PRIVATE cxx_std_20)
    target_link_libraries(${name} PRIVATE mylib)
endfunction()

# 使用
add_my_executable(app1 main1.cpp)
add_my_executable(app2 main2.cpp)

6. 编译器警告与优化控制

target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic>
    $<$<CXX_COMPILER_ID:MSVC>:/W4 /permissive->
)

target_compile_definitions(myapp PRIVATE
    $<$<CONFIG:Debug>:DEBUG_BUILD>
    MY_VERSION="1.0"
)

7. 交叉编译支持

工具链文件示例(toolchain-arm.cmake)

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH /path/to/sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

使用:

cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain-arm.cmake

8. 测试与覆盖率(CTest + Coverage)

enable_testing()

add_executable(my_test tests/test_main.cpp)
target_link_libraries(my_test PRIVATE mylib GTest::gtest_main)

add_test(NAME UnitTests COMMAND my_test)

# 覆盖率(GCC/Clang)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    target_compile_options(my_test PRIVATE --coverage)
    target_link_options(my_test PRIVATE --coverage)
endif()

运行:ctestctest -V

9. CPack 打包(生成 deb/rpm/zip 安装包)

set(CPACK_PACKAGE_NAME "MyAwesomeApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "DEB;RPM;ZIP")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "you@example.com")

include(CPack)

构建后运行:

cpack -G DEB   # 生成 .deb 包

10. 完整高级项目模板(推荐结构)

myproject/
├── CMakeLists.txt
├── cmake/
│   └── MyLibConfig.cmake.in
├── src/
├── include/
├── app/
├── tests/
├── third_party/        # FetchContent 下载的内容
└── tools/

小结:高级特性使用建议

特性何时使用推荐程度
option()需要用户控制功能开关★★★★★
find_package(CONFIG)使用 vcpkg/Conan 管理的库★★★★★
FetchContent项目依赖小第三方库★★★★★
install + export开发可被他人使用的库★★★★★
CPack需要分发安装包★★★★
自定义函数项目规模大、重复配置多★★★★

这些高级特性让 CMake 从“能用”变成“专业级构建系统”。大型开源项目(如 LLVM、OpenCV、Qt)都深度使用这些功能。

如果你想深入某个特性(如完整可安装库示例、集成 vcpkg/Conan、Android/iOS 交叉编译、Unity Build 优化等),告诉我,我可以提供完整可运行的项目模板!

文章已创建 3511

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部