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()