cmake命令

cmake 命令 #

cmake是一个跨平台的构建系统生成器,用于管理软件项目的构建过程。它使用名为CMakeLists.txt的配置文件来描述构建过程,并可以生成各种本地构建系统(如 Makefile、Visual Studio 项目、Ninja 等)的文件。

语法 #

cmake [选项] <源目录>
cmake [选项] <现有构建目录>
cmake [选项] -S <源目录> -B <构建目录>

常用选项 #

选项 描述
-S <源目录> 指定源代码目录
-B <构建目录> 指定构建目录
-G <生成器> 指定要使用的生成器
-D <var>=<value> 创建或更新 CMake 缓存条目
--build <构建目录> 构建已生成的项目
--install <构建目录> 安装已构建的项目
-C <初始缓存> 预加载缓存文件
-U <全局属性> 从 CMake 缓存中移除匹配的条目
-E <命令> 执行 CMake 命令行工具
--version 显示版本信息
--help 显示帮助信息
--help-full 显示完整帮助信息
--system-information 显示系统信息
--log-level=<级别> 设置日志级别
--trace 启用跟踪输出
--trace-expand 启用展开变量的跟踪输出
--warn-uninitialized 警告未初始化的变量
--warn-unused-vars 警告未使用的变量
--no-warn-unused-cli 不警告未使用的命令行选项

基本用法 #

1. 生成构建系统 #

# 在源目录中生成构建系统
cd source_directory
mkdir build
cd build
cmake ..

# 或者使用-S和-B选项
cmake -S source_directory -B build_directory

2. 构建项目 #

# 在构建目录中构建
cd build_directory
cmake --build .

# 或者直接指定构建目录
cmake --build build_directory

3. 安装项目 #

# 在构建目录中安装
cd build_directory
cmake --install .

# 或者直接指定构建目录
cmake --install build_directory

4. 指定构建类型 #

cmake -S source_directory -B build_directory -DCMAKE_BUILD_TYPE=Release

5. 指定安装前缀 #

cmake -S source_directory -B build_directory -DCMAKE_INSTALL_PREFIX=/usr/local

6. 指定生成器 #

# 使用Ninja生成器
cmake -G Ninja -S source_directory -B build_directory

# 使用Unix Makefiles生成器
cmake -G "Unix Makefiles" -S source_directory -B build_directory

CMakeLists.txt 基本结构 #

CMakeLists.txt 是 CMake 项目的主要配置文件,包含了构建项目所需的指令。以下是一个基本的 CMakeLists.txt 文件结构:

# 指定CMake最低版本
cmake_minimum_required(VERSION 3.10)

# 设置项目名称和版本
project(MyProject VERSION 1.0)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加可执行文件
add_executable(myapp main.cpp utils.cpp)

# 添加头文件目录
target_include_directories(myapp PUBLIC include)

# 添加库依赖
target_link_libraries(myapp PRIVATE mylib)

# 安装规则
install(TARGETS myapp DESTINATION bin)

常用 CMake 命令 #

1. 项目配置 #

# 设置项目名称和版本
project(MyProject VERSION 1.0 LANGUAGES CXX)

# 设置变量
set(MY_VARIABLE "value")

# 添加编译选项
add_compile_options(-Wall -Wextra)

# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

2. 目标管理 #

# 添加可执行文件
add_executable(myapp main.cpp)

# 添加库
add_library(mylib STATIC lib.cpp)
add_library(mysharedlib SHARED lib.cpp)

# 设置目标属性
set_target_properties(myapp PROPERTIES OUTPUT_NAME "application")

# 添加头文件目录
target_include_directories(myapp PRIVATE include)

# 添加库依赖
target_link_libraries(myapp PRIVATE mylib)

# 添加编译定义
target_compile_definitions(myapp PRIVATE DEBUG=1)

3. 条件语句 #

# if-else条件
if(UNIX)
    message(STATUS "Running on Unix")
elseif(WIN32)
    message(STATUS "Running on Windows")
else()
    message(STATUS "Running on unknown platform")
endif()

# 检查选项
option(USE_FEATURE "Enable feature" OFF)
if(USE_FEATURE)
    add_definitions(-DUSE_FEATURE)
endif()

4. 查找包和库 #

# 查找包
find_package(Boost REQUIRED COMPONENTS system filesystem)
if(Boost_FOUND)
    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(myapp PRIVATE ${Boost_LIBRARIES})
endif()

# 查找库
find_library(MATH_LIBRARY m)
if(MATH_LIBRARY)
    target_link_libraries(myapp PRIVATE ${MATH_LIBRARY})
endif()

5. 安装规则 #

# 安装可执行文件
install(TARGETS myapp DESTINATION bin)

# 安装库
install(TARGETS mylib DESTINATION lib)

# 安装头文件
install(FILES include/mylib.h DESTINATION include)

# 安装目录
install(DIRECTORY docs/ DESTINATION share/doc/myproject)

6. 测试 #

# 启用测试
enable_testing()

# 添加测试
add_test(NAME mytest COMMAND myapp --test)

# 设置测试属性
set_tests_properties(mytest PROPERTIES TIMEOUT 30)

高级用法 #

1. 创建配置头文件 #

# 配置头文件
configure_file(config.h.in ${CMAKE_BINARY_DIR}/config.h)

config.h.in 文件内容:

#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VERSION "@PROJECT_VERSION@"
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@

2. 添加自定义命令 #

# 添加自定义命令
add_custom_command(
    OUTPUT generated.cpp
    COMMAND generator -o ${CMAKE_CURRENT_BINARY_DIR}/generated.cpp
    DEPENDS generator input.txt
    COMMENT "Generating source file"
)

# 添加自定义目标
add_custom_target(
    generate_files
    DEPENDS generated.cpp
)

3. 使用子目录 #

# 添加子目录
add_subdirectory(src)
add_subdirectory(tests)

4. 创建和使用库 #

# 创建库
add_library(mylib STATIC src1.cpp src2.cpp)

# 设置库的包含目录
target_include_directories(mylib
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)

# 导出库
install(TARGETS mylib
    EXPORT mylibTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

# 安装导出目标
install(EXPORT mylibTargets
    FILE mylibTargets.cmake
    NAMESPACE mylib::
    DESTINATION lib/cmake/mylib
)

5. 创建包配置文件 #

# 生成版本文件
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/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
)

常用生成器 #

生成器 描述 平台
“Unix Makefiles” 生成标准 Unix Makefile Linux, macOS
“Ninja” 生成 Ninja 构建文件 跨平台
“Visual Studio 16 2019” 生成 Visual Studio 2019 项目文件 Windows
“Xcode” 生成 Xcode 项目 macOS
“MinGW Makefiles” 生成适用于 MinGW 的 Makefile Windows
“MSYS Makefiles” 生成适用于 MSYS 的 Makefile Windows
“CodeBlocks - Unix Makefiles” 生成 CodeBlocks 项目文件 跨平台
“Eclipse CDT4 - Unix Makefiles” 生成 Eclipse 项目文件 跨平台

实用示例 #

1. 简单的可执行文件项目 #

cmake_minimum_required(VERSION 3.10)
project(HelloWorld VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(hello main.cpp)

2. 带有库的项目 #

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 创建库
add_library(mylib STATIC src/lib.cpp)
target_include_directories(mylib PUBLIC include)

# 创建可执行文件
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE mylib)

# 安装规则
install(TARGETS myapp DESTINATION bin)
install(TARGETS mylib DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)

3. 使用外部库 #

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找Boost库
find_package(Boost REQUIRED COMPONENTS system filesystem)

# 创建可执行文件
add_executable(myapp src/main.cpp)
target_include_directories(myapp PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${Boost_LIBRARIES})

4. 添加测试 #

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 创建库
add_library(mylib STATIC src/lib.cpp)
target_include_directories(mylib PUBLIC include)

# 创建可执行文件
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE mylib)

# 启用测试
enable_testing()

# 创建测试可执行文件
add_executable(test_mylib tests/test_lib.cpp)
target_link_libraries(test_mylib PRIVATE mylib)

# 添加测试
add_test(NAME lib_test COMMAND test_mylib)

5. 跨平台配置 #

cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 平台特定配置
if(WIN32)
    add_definitions(-DWINDOWS)
    set(PLATFORM_SOURCES src/windows_impl.cpp)
elseif(APPLE)
    add_definitions(-DMACOS)
    set(PLATFORM_SOURCES src/macos_impl.cpp)
elseif(UNIX)
    add_definitions(-DLINUX)
    set(PLATFORM_SOURCES src/linux_impl.cpp)
endif()

# 创建可执行文件
add_executable(myapp src/main.cpp ${PLATFORM_SOURCES})

常见问题排查 #

1. 找不到包或库 #

# 设置额外的搜索路径
set(CMAKE_PREFIX_PATH "/path/to/libraries")

# 或者手动指定库路径
set(LIBRARY_DIR "/path/to/library")
include_directories(${LIBRARY_DIR}/include)
link_directories(${LIBRARY_DIR}/lib)

2. 构建类型问题 #

# 确保设置了构建类型
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
endif()

# 显示可用的构建类型
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
    "Debug" "Release" "MinSizeRel" "RelWithDebInfo")

3. 编译器选择问题 #

# 在调用project()之前设置编译器
set(CMAKE_C_COMPILER "/path/to/gcc")
set(CMAKE_CXX_COMPILER "/path/to/g++")

4. 版本兼容性问题 #

# 检查CMake版本
if(CMAKE_VERSION VERSION_LESS "3.10")
    message(FATAL_ERROR "CMake >= 3.10 required")
endif()

# 检查编译器版本
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.0")
        message(FATAL_ERROR "GCC >= 7.0 required")
    endif()
endif()

与其他构建系统的比较 #

构建系统 优点 缺点 适用场景
CMake 跨平台、灵活、广泛支持 语法有时复杂 中大型跨平台项目
Make 简单、广泛可用 跨平台性差、手动依赖管理 小型项目、Unix 环境
Ninja 非常快速、简单 不适合直接编写 大型项目、作为 CMake 后端
Meson 现代语法、快速 相对较新、支持不如 CMake 广泛 新项目、注重构建速度
Bazel 可扩展、支持大型项目 学习曲线陡峭 大型单仓库项目

提示和技巧 #

1. 使用现代 CMake 风格 #

# 现代CMake推荐使用target_*命令
add_library(mylib STATIC src/lib.cpp)
target_include_directories(mylib PUBLIC include)
target_compile_definitions(mylib PRIVATE DEBUG=1)
target_compile_options(mylib PRIVATE -Wall)
target_link_libraries(mylib PRIVATE otherlib)

2. 使用生成器表达式 #

# 根据构建类型设置不同的编译选项
target_compile_options(myapp PRIVATE
    $<$<CONFIG:Debug>:-g -O0>
    $<$<CONFIG:Release>:-O3>
)

# 区分构建接口和安装接口
target_include_directories(mylib
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
)

3. 使用预设 #

CMake 3.19+支持预设文件(CMakePresets.json):

{
  "version": 3,
  "configurePresets": [
    {
      "name": "debug",
      "displayName": "Debug Build",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "release",
      "displayName": "Release Build",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ]
}

使用预设:

cmake --preset=debug
cmake --build --preset=debug

4. 使用 FetchContent 获取依赖 #

include(FetchContent)

FetchContent_Declare(
    fmt
    GIT_REPOSITORY https://github.com/fmtlib/fmt.git
    GIT_TAG 8.0.1
)

FetchContent_MakeAvailable(fmt)

target_link_libraries(myapp PRIVATE fmt::fmt)

5. 使用 CPack 创建安装包 #

include(CPack)

set(CPACK_PACKAGE_NAME "MyProject")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_VENDOR "My Organization")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My awesome project")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")

# 根据平台设置生成器
if(WIN32)
    set(CPACK_GENERATOR "NSIS")
elseif(APPLE)
    set(CPACK_GENERATOR "DragNDrop")
else()
    set(CPACK_GENERATOR "DEB")
endif()

扩展阅读 #