CMake学习篇三:常用指令速查
- 笔记
- 8小时前
- 12热度
- 0评论
💡 学习前提
1. CMake 命令行选项
基本用法:
cmake [选项] <源代码目录>
1.1 常用选项速查
# 构建类型
cmake .. -DCMAKE_BUILD_TYPE=Debug # 调试模式
cmake .. -DCMAKE_BUILD_TYPE=Release # 发布模式
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo # 优化+调试信息
cmake .. -DCMAKE_BUILD_TYPE=MinSizeRel # 最小体积
# 指定编译器
cmake .. -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
# 安装路径
cmake .. -DCMAKE_INSTALL_PREFIX=/opt/myapp
# 调试选项
cmake .. -DCMAKE_VERBOSE_MAKEFILE=ON # 持久详细输出
cmake --build . --verbose # 临时详细输出
cmake .. --debug-output # CMake 调试信息
# 生成器
cmake .. -G Ninja # 使用 Ninja(更快)
cmake .. -G "Unix Makefiles" # 使用 Make
cmake .. -G "Visual Studio 16 2019" # VS 2019
# 自定义变量
cmake .. -DBUILD_TESTS=ON -DENABLE_LOGGING=OFF
# 一行命令
cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build
⚠️ 选项类型
- 配置选项(-D):配置阶段生效,写入 Makefile
- 构建选项(--build 后):编译阶段生效,传递给底层工具
```bash
cmake .. -DCMAKE_BUILD_TYPE=Release # 配置选项
cmake --build . --verbose -j 8 # 构建选项
```
2. 常用指令详解
2.1 基础指令(快速参考)
# 版本要求
cmake_minimum_required(VERSION 3.10)
# 项目定义
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
# 创建可执行文件
add_executable(app main.cpp utils.cpp)
# 创建库
add_library(mylib STATIC lib.cpp) # 静态库
add_library(mylib SHARED lib.cpp) # 动态库
add_library(mylib INTERFACE) # 接口库(仅头文件)
# 链接库
target_link_libraries(app PRIVATE mylib)
# 头文件路径
target_include_directories(mylib
PUBLIC include/ # 对外接口
PRIVATE src/ # 内部实现
)
⚠️ 现代 CMake 原则
- 使用 target_xxx 命令(精确控制每个目标)
- 避免全局命令 include_directories/link_directories(影响所有目标)
- 合理使用 PRIVATE/PUBLIC/INTERFACE(控制依赖传递)
2.2 target_xxx 系列(现代方式)
| 命令 | 对应参数 | 作用 |
|---|---|---|
target_include_directories |
-I |
头文件搜索路径 |
target_compile_definitions |
-D |
宏定义 |
target_compile_options |
-Wall -O2 |
编译选项 |
target_link_libraries |
-l |
链接库 |
target_link_directories |
-L |
库搜索路径 |
示例:
add_library(mylib lib.cpp)
target_include_directories(mylib PUBLIC include/)
target_compile_definitions(mylib PRIVATE DEBUG_MODE)
target_compile_options(mylib PRIVATE -Wall -Wextra)
target_link_libraries(mylib PUBLIC other_lib)
2.3 其他常用指令
target_compile_definitions
# 添加宏定义(对应 -D 参数)
target_compile_definitions(my_app
PRIVATE DEBUG_MODE
PUBLIC VERSION=1.0
PRIVATE $<$<CONFIG:Debug>:DEBUG_BUILD> # 仅 Debug 模式
)
target_compile_options
# 添加编译选项
target_compile_options(my_app
PRIVATE -Wall -Wextra
PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/W4> # MSVC 特定
PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wpedantic> # GCC 特定
)
add_subdirectory
# 添加子目录(子目录必须包含 CMakeLists.txt)
add_subdirectory(src)
add_subdirectory(libs/mylib)
# 指定构建输出路径
add_subdirectory(../shared_lib ${CMAKE_BINARY_DIR}/shared)
include
# 包含 CMake 模块或文件
include(CMakePrintHelpers)
include(CheckCXXCompilerFlag)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/MyFunctions.cmake)
# 可选包含(文件不存在不报错)
include(OptionalFile OPTIONAL)
find_package
# 查找并加载外部库
find_package(OpenCV REQUIRED)
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
# 可选包
find_package(CUDA)
if(CUDA_FOUND)
message("CUDA found: ${CUDA_VERSION}")
endif()
message
# 输出消息
message(STATUS "This is a status message")
message(WARNING "This is a warning")
message(FATAL_ERROR "This stops configuration")
message("Variable value: ${MY_VAR}")
option
# 定义布尔选项(可在命令行修改)
option(BUILD_TESTS "Build test programs" ON)
option(ENABLE_LOGGING "Enable logging" OFF)
if(BUILD_TESTS)
add_subdirectory(tests)
endif()
# 命令行设置:cmake .. -DBUILD_TESTS=OFF
configure_file
# 配置文件生成(变量替换)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h
)
config.h.in 模板:
#define PROJECT_VERSION "@PROJECT_VERSION@"
#define PROJECT_NAME "@PROJECT_NAME@"
#cmakedefine ENABLE_FEATURE
#cmakedefine01 USE_OPENMP
生成的 config.h:
#define PROJECT_VERSION "1.2.3"
#define PROJECT_NAME "MyProject"
#define ENABLE_FEATURE // 如果 ENABLE_FEATURE 为 ON
/* #undef ENABLE_FEATURE */ // 如果为 OFF
#define USE_OPENMP 1 // 如果 USE_OPENMP 为 ON
3. 跨平台知识
3.1 库文件扩展名
| 平台 | 静态库 | 动态库 | 可执行文件 |
|---|---|---|---|
| Linux | .a |
.so |
无扩展名 |
| macOS | .a |
.dylib |
无扩展名 |
| Windows | .lib |
.dll + .lib(导入库) |
.exe |
命名规则:
Linux/macOS: lib + 库名 + 扩展名
libmath.a, libmath.so, libmath.dylib
Windows: 库名 + 扩展名
math.lib, math.dll
💡 CMake 自动处理跨平台差异
```cmake
add_library(mymath STATIC add.c)
# Linux/macOS: libmymath.a
# Windows: mymath.lib
add_library(mymath SHARED add.c)
# Linux: libmymath.so
# macOS: libmymath.dylib
# Windows: mymath.dll + mymath.lib
# 链接时不需要写扩展名
target_link_libraries(main PRIVATE mymath) # 自动找到正确的库
```
4. 进阶内容
4.1 find_package 深入
查找系统库:
# Threads
find_package(Threads REQUIRED)
target_link_libraries(my_app PRIVATE Threads::Threads)
# OpenMP
find_package(OpenMP REQUIRED)
target_link_libraries(my_app PRIVATE OpenMP::OpenMP_CXX)
# Boost
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
target_link_libraries(my_app PRIVATE Boost::filesystem Boost::system)
自定义 Find 模块(cmake/FindMyLib.cmake):
find_path(MYLIB_INCLUDE_DIR mylib.h
PATHS /usr/include /usr/local/include
)
find_library(MYLIB_LIBRARY
NAMES mylib
PATHS /usr/lib /usr/local/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib
REQUIRED_VARS MYLIB_LIBRARY MYLIB_INCLUDE_DIR
)
if(MyLib_FOUND AND NOT TARGET MyLib::MyLib)
add_library(MyLib::MyLib UNKNOWN IMPORTED)
set_target_properties(MyLib::MyLib PROPERTIES
IMPORTED_LOCATION "${MYLIB_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${MYLIB_INCLUDE_DIR}"
)
endif()
使用自定义模块:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
find_package(MyLib REQUIRED)
target_link_libraries(my_app PRIVATE MyLib::MyLib)
4.2 FetchContent(现代依赖管理)
include(FetchContent)
# 声明依赖
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
# 使依赖可用
FetchContent_MakeAvailable(googletest)
# 使用依赖
add_executable(my_test test.cpp)
target_link_libraries(my_test PRIVATE gtest_main)
多个依赖:
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.2
)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 9.1.0
)
FetchContent_MakeAvailable(json fmt)
target_link_libraries(my_app PRIVATE nlohmann_json::nlohmann_json fmt::fmt)
4.3 安装和导出
# 安装目标
install(TARGETS mylib my_app
EXPORT MyProjectTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
# 安装头文件
install(DIRECTORY include/ DESTINATION include)
# 导出目标
install(EXPORT MyProjectTargets
FILE MyProjectTargets.cmake
NAMESPACE MyProject::
DESTINATION lib/cmake/MyProject
)
# 生成配置文件
include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfig.cmake
INSTALL_DESTINATION lib/cmake/MyProject
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfig.cmake
DESTINATION lib/cmake/MyProject
)
5. 实战示例
5.1 第三方库集成
使用 find_package:
cmake_minimum_required(VERSION 3.15)
project(ThirdPartyDemo)
set(CMAKE_CXX_STANDARD 17)
# 查找库
find_package(OpenCV REQUIRED)
find_package(Boost 1.70 REQUIRED COMPONENTS filesystem system)
find_package(Threads REQUIRED)
add_executable(demo main.cpp)
target_link_libraries(demo
PRIVATE ${OpenCV_LIBS}
PRIVATE Boost::filesystem Boost::system
PRIVATE Threads::Threads
)
使用 FetchContent:
cmake_minimum_required(VERSION 3.15)
project(FetchContentDemo)
set(CMAKE_CXX_STANDARD 17)
include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.2
)
FetchContent_Declare(spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.11.0
)
FetchContent_MakeAvailable(json spdlog)
add_executable(demo main.cpp)
target_link_libraries(demo
PRIVATE nlohmann_json::nlohmann_json
PRIVATE spdlog::spdlog
)
5.2 跨平台配置
cmake_minimum_required(VERSION 3.15)
project(CrossPlatform)
set(CMAKE_CXX_STANDARD 17)
add_executable(app main.cpp)
# 平台特定的源文件
if(WIN32)
target_sources(app PRIVATE src/windows_impl.cpp)
elseif(UNIX AND NOT APPLE)
target_sources(app PRIVATE src/linux_impl.cpp)
elseif(APPLE)
target_sources(app PRIVATE src/macos_impl.cpp)
endif()
# 平台特定的库
if(WIN32)
target_link_libraries(app PRIVATE ws2_32)
elseif(UNIX)
target_link_libraries(app PRIVATE pthread dl)
endif()
# 平台特定的编译定义
if(WIN32)
target_compile_definitions(app PRIVATE PLATFORM_WINDOWS)
elseif(UNIX)
target_compile_definitions(app PRIVATE PLATFORM_UNIX)
endif()
6. 最佳实践
6.1 现代 CMake 原则
使用 target_xxx 命令:
# ✅ 现代方式
target_include_directories(my_target PRIVATE include/)
target_compile_definitions(my_target PRIVATE DEBUG)
target_link_libraries(my_target PRIVATE mylib)
# ❌ 旧方式(避免使用)
include_directories(include/)
add_definitions(-DDEBUG)
link_libraries(mylib)
6.2 目录结构规范
project/
├── CMakeLists.txt # 根配置
├── cmake/ # CMake 模块和脚本
│ ├── FindXXX.cmake
│ └── CompilerWarnings.cmake
├── include/ # 公共头文件
│ └── project/
│ └── api.h
├── src/ # 源文件
│ └── api.cpp
├── apps/ # 应用程序
│ └── main.cpp
├── tests/ # 测试
│ └── test_api.cpp
├── docs/ # 文档
├── external/ # 第三方库
└── build/ # 构建目录(不提交到版本控制)
6.3 构建类型管理
# 设置默认构建类型
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
6.4 编译器警告配置
# cmake/CompilerWarnings.cmake
function(set_project_warnings target)
set(MSVC_WARNINGS /W4 /WX)
set(GCC_CLANG_WARNINGS
-Wall -Wextra -Wpedantic -Wshadow
-Wnon-virtual-dtor -Wold-style-cast
)
if(MSVC)
set(PROJECT_WARNINGS ${MSVC_WARNINGS})
else()
set(PROJECT_WARNINGS ${GCC_CLANG_WARNINGS})
endif()
target_compile_options(${target} PRIVATE ${PROJECT_WARNINGS})
endfunction()
# 使用
include(cmake/CompilerWarnings.cmake)
set_project_warnings(my_target)
6.5 选项和缓存变量
# 布尔选项
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(BUILD_TESTS "Build test programs" ON)
# 字符串选项
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo"
)
# 使用选项
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
6.6 版本管理
# 从文件读取版本
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" VERSION_STRING)
string(STRIP "${VERSION_STRING}" VERSION_STRING)
project(MyProject VERSION ${VERSION_STRING})
# 生成版本头文件
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/include/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/version.h
)
version.h.in:
#pragma once
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define PROJECT_VERSION "@PROJECT_VERSION@"
6.7 测试集成
# 启用测试
enable_testing()
# 添加测试
add_executable(test_math tests/test_math.cpp)
target_link_libraries(test_math PRIVATE math_lib)
add_test(NAME MathTests COMMAND test_math)
# 使用 Google Test
find_package(GTest REQUIRED)
add_executable(gtest_example tests/gtest_example.cpp)
target_link_libraries(gtest_example PRIVATE GTest::GTest GTest::Main)
gtest_discover_tests(gtest_example)
运行测试:
cd build
ctest # 运行所有测试
ctest -V # 详细输出
ctest -R Math # 运行匹配 "Math" 的测试
ctest --output-on-failure # 失败时显示输出
6.8 安装规则
# 安装目标
install(TARGETS mylib myapp
EXPORT MyProjectTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
# 安装头文件
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING PATTERN "*.h"
)
# 导出目标
install(EXPORT MyProjectTargets
FILE MyProjectTargets.cmake
NAMESPACE MyProject::
DESTINATION lib/cmake/MyProject
)
安装命令:
cmake --build build
cmake --install build --prefix /usr/local
6.9 常用命令速查
# 配置
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake -B build -G Ninja
# 构建
cmake --build build
cmake --build build -j 8
cmake --build build --target my_app
# 安装
cmake --install build --prefix ~/myapp
# 测试
cd build && ctest
# 查看缓存
cmake -B build -L
cmake -B build -LAH
6.10 调试技巧
# 打印变量
message(STATUS "Variable: ${MY_VAR}")
# 使用 CMakePrintHelpers
include(CMakePrintHelpers)
cmake_print_variables(CMAKE_CXX_COMPILER CMAKE_BUILD_TYPE)
cmake_print_properties(TARGETS my_target PROPERTIES COMPILE_OPTIONS)
详细输出:
# 查看详细编译命令
cmake --build build --verbose
# 生成编译数据库
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
7. 常见问题
Q1: 如何指定 C++ 标准?
# 方法 1:全局设置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# 方法 2:目标级别
target_compile_features(my_target PUBLIC cxx_std_17)
Q2: 如何处理头文件依赖?
target_include_directories(my_target
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include # 公共接口
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src # 内部实现
)
Q3: 如何添加编译宏?
# 目标级别宏
target_compile_definitions(my_target
PRIVATE DEBUG_MODE
PUBLIC API_VERSION=2
)
Q4: 如何链接系统库?
# Linux 系统库
target_link_libraries(my_app PRIVATE pthread m dl)
# Windows 系统库
target_link_libraries(my_app PRIVATE ws2_32 advapi32)
# 使用 find_package
find_package(Threads REQUIRED)
target_link_libraries(my_app PRIVATE Threads::Threads)
Q5: 如何处理不同平台的差异?
if(WIN32)
target_compile_definitions(my_app PRIVATE PLATFORM_WINDOWS)
elseif(APPLE)
target_compile_definitions(my_app PRIVATE PLATFORM_MACOS)
elseif(UNIX)
target_compile_definitions(my_app PRIVATE PLATFORM_LINUX)
endif()
Q6: 如何生成静态库和动态库?
# 静态库
add_library(mylib_static STATIC src/lib.cpp)
# 动态库
add_library(mylib_shared SHARED src/lib.cpp)
# 自动选择(根据 BUILD_SHARED_LIBS)
add_library(mylib src/lib.cpp)
Q7: 如何使用预编译头?
# CMake 3.16+
target_precompile_headers(my_target
PRIVATE
<iostream>
<vector>
<string>
"my_common_header.h"
)
Q8: 如何处理大型项目的编译时间?
# 1. 使用 Ninja 生成器
cmake -B build -G Ninja
# 2. 启用并行编译
cmake --build build -j $(nproc)
# 3. 使用 ccache
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
endif()
# 4. 使用 Unity Build
set(CMAKE_UNITY_BUILD ON)
8. 学习资源
9. 总结
✅ 本篇核心要点
1. 命令行选项
- 构建类型:-DCMAKE_BUILD_TYPE=Debug/Release
- 编译器:-DCMAKE_CXX_COMPILER=g++
- 调试:-DCMAKE_VERBOSE_MAKEFILE=ON 或 --verbose
2. 常用指令
- 基础:cmake_minimum_required, project, add_executable, add_library
- 现代:target_include_directories, target_link_libraries, target_compile_options
- 进阶:find_package, FetchContent, configure_file
3. 跨平台
- CMake 自动处理库文件扩展名差异
- 使用条件判断处理平台特定代码
4. 最佳实践
- 使用 target_xxx 命令(现代 CMake)
- 合理使用 PRIVATE/PUBLIC/INTERFACE
- 保持项目结构清晰
- 善用 find_package 和 FetchContent
学习路径:
✅ 引入篇:理解为什么需要 CMake
✅ 篇一:快速入门,创建基本项目
✅ 篇二:理解核心概念(Target、变量、作用域)
✅ 篇三:掌握常用指令和最佳实践(当前)
系列文章:
下一步:
- 在真实项目中应用这些知识
- 深入学习特定领域(测试、打包、安装等)
- 阅读优秀开源项目的 CMakeLists.txt
最后更新:2026-05-28