命令和作用
1、CMake的最低版本定义
cmake_minimum_required(VERSION 3.0) # 最低需要CMake3.0
2、项目名称
也是最后输出的可执行文件的名称前缀
project(ProjectName) # 最后就会生成Project_Name.exe
3、寻找第三方库
需要保证第三方库存在,REQUIRED表示此库为必须组件,没有就会报错
find_package(lib_info_1, REQUIRED)
find_package(lib_info_2, REQUIRED)
参数列表:
find_package(<PackageName> [version] [EXACT] [QUIET] [REQUIRED]) # 主要参数
参数 | 说明 |
---|---|
<PackageName> | 要查找的库/包名称(如 OpenCV 、Boost ) |
[version] | 可选,指定最低版本(如 1.7.0 ) |
EXACT | 要求版本必须完全匹配(与 version 配合使用) |
QUIET | 禁用未找到时的警告信息 |
REQUIRED | 如果未找到包,则终止 CMake 配置并报错 |
4、库文件获取
file(GLOB SRC_FILES "${PROJECT_SOURCE_DIR}/src/*.h")
参数含义
1. 操作类型
GLOB是file命令的操作类型,表示使用通配符匹配文件
操作类型还有:
GLOB_RECURSE 递归匹配文件
file(GLOB_RECURSE SRC_FILES "${PROJECT_SOURCE_DIR}/src/*.h")
COPY 复制文件或目录
file(COPY files... DESTINATION dir)
REMOVE 删除文件
file(REMOVE files...)
READ 读取文件内容
file(READ filename variable)
WRITE 写入内容到文件
file(WRITE filename "content")
APPEND 追加内容到文件
file(APPEND filename "content")
MAKE_DIRECTORY 创建目录
file(MAKE_DIRECTORY dirs...)
2. 存储结果
SRC_FILES是存储结果的变量名,匹配到的文件列表将被存储在这个变量中
3. 文件列表
在 CMake 中,${PROJECT_SOURCE_DIR}
表示的是 包含最近调用 project()
命令的 CMakeLists.txt 文件所在的目录,而不是当前 CMakeLists.txt 文件所在的目录。
例如根目录里的CMakeLists.txt最先定义了project()
,那么${PROJECT_SOURCE_DIR}
所代表的就是根目录
例如:
project(MyProject) # 假设在 /path/to/project/CMakeLists.txt 中调用
那么此字符串的含义就是:得到/path/to/project/根目录下src/目录中的所有.h
文件
同类型参数还有:
CMAKE_SOURCE_DIR
CMAKE_SOURCE_DIR
是 顶层 CMakeLists.txt 所在的目录(即整个构建树的根目录)。- 如果你的项目是顶级项目(没有用
add_subdirectory()
引入其他项目),那么PROJECT_SOURCE_DIR
和CMAKE_SOURCE_DIR
通常是相同的。 - 但如果你的项目是子项目(例如通过
add_subdirectory()
引入),PROJECT_SOURCE_DIR
会指向子项目的目录,而CMAKE_SOURCE_DIR
仍然指向顶级目录。
CMAKE_CURRENT_SOURCE_DIR
CMAKE_CURRENT_SOURCE_DIR
是 当前正在处理的 CMakeLists.txt 所在的目录(无论是否有project()
命令)。- 如果你在一个子目录的
CMakeLists.txt
里使用它,它会指向那个子目录,而PROJECT_SOURCE_DIR
仍然指向project()
所在的目录。
一次性链接多种文件:
file(GLOB SRC_FILES
"${PROJECT_SOURCE_DIR}/src/*.h"
"${PROJECT_SOURCE_DIR}/src/*.hpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
"${PROJECT_SOURCE_DIR}/src/*.cpp")
5、构建可执行文件
add_executable(${CMAKE_PROJECT_NAME} ${SRC_FILES})
参数
1. 工程文件名
-
${PROJECT_NAME}
:当前项目的名称(由最近的project()
定义) -
${CMAKE_PROJECT_NAME}
:顶级项目的名称(第一个project()
定义的名称) -
或者可以直接使用项目名
add_executable(ProjectName ${SRC_FILES}) # 直接写死名称
-
也可以使用变量名
set(TARGET_NAME "ProjectName") add_executable(${TARGET_NAME} ${SRC_FILES})
2. 源文件列表
-
这是构建可执行文件所需的源文件列表
-
可以包含
.cpp
、.c
、.h
等文件 -
使用file命令生成的文件列表(上文所用的方法)
add_executable(${CMAKE_PROJECT_NAME} ${SRC_FILES})
-
直接列出文件
add_executable(${CMAKE_PROJECT_NAME} main.cpp util.cpp helper.cpp)
-
使用变量组合
set(SRC_MAIN main.cpp) set(SRC_UTIL util.cpp) add_executable(${CMAKE_PROJECT_NAME} ${SRC_MAIN} ${SRC_UTIL})
-
使用 target_sources() 后续添加
add_executable(${CMAKE_PROJECT_NAME} main.cpp) target_sources(${CMAKE_PROJECT_NAME} PRIVATE util.cpp helper.cpp)
-
使用生成器表达式
add_executable(${CMAKE_PROJECT_NAME} $<TARGET_OBJECTS:MyLib> main.cpp)
6、链接第三方库
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE lib_info_1)
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE lib_info_2)
参数
1. 目标
必须是由 add_executable()
或 add_library()
创建的目标。
2. 链接模式
关键字 | 含义 |
---|---|
PRIVATE | 库仅用于当前目标的构建,不传播给依赖它的其他目标。 |
PUBLIC | 库既用于当前目标的构建,也传播给依赖它的目标。 |
INTERFACE | 库不用于当前目标的构建,但会传播给依赖它的目标。 |
示例:
# 假设我们有一个库 `my_lib` 和一个可执行文件 `my_app`
add_library(my_lib STATIC lib.cpp)
add_executable(my_app main.cpp)
# 如果 `my_lib` 需要 `pthread`,但 `my_app` 不需要知道:
target_link_libraries(my_lib PRIVATE pthread)
# 如果 `my_lib` 需要 `zlib`,并且 `my_app` 也需要:
target_link_libraries(my_lib PUBLIC zlib)
# 如果 `my_lib` 本身不需要 `boost`,但 `my_app` 需要:
target_link_libraries(my_lib INTERFACE boost)
# 最后my_app 链接 my_lib
target_link_libraries(my_app PRIVATE my_lib)
实际链接结果
库 | 是否链接到 my_lib | 是否链接到 my_app | 说明 |
---|---|---|---|
pthread | ✅ 是 | ❌ 否 | PRIVATE 不传播 |
zlib | ✅ 是 | ✅ 是 | PUBLIC 自动传播 |
boost | ❌ 否 | ✅ 是 | INTERFACE 仅传播 |
my_lib | — | ✅ 是 | 显式链接 |
3. 要链接的库
可以分为以下几种情况
-
CMake 目标(由
add_library()
创建)add_library(math STATIC math.cpp) target_link_libraries(my_app PRIVATE math)
-
系统库(如
pthread
、dl
、m
)target_link_libraries(my_app PRIVATE pthread dl m)
-
外部库(如
OpenCV
、Boost
)find_package(OpenCV REQUIRED) target_link_libraries(my_app PRIVATE ${OpenCV_LIBS})
-
绝对路径或库名
target_link_libraries(my_app PRIVATE /path/to/libfoo.a)
7、自定义构建规则
1. 为生成文件添加命令 (构建时执行)
add_custom_command(
OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[BYPRODUCTS [files...]]
[IMPLICIT_DEPENDS <lang1> depend1 [<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS])
2. 为构建目标添加后置命令 (构建后执行)
add_custom_command(
TARGET target
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM]
[USES_TERMINAL]
[COMMAND_EXPAND_LISTS])
参数详解
通用参数
- COMMAND: 要执行的命令,可以是可执行程序或脚本
- WORKING_DIRECTORY: 命令执行的工作目录
- COMMENT: 构建时显示的注释信息
- VERBATIM: 确保参数被正确转义
- USES_TERMINAL: 命令需要访问终端
OUTPUT 形式特有参数
- OUTPUT: 指定命令生成的文件
- DEPENDS: 命令依赖的文件或目标
- MAIN_DEPENDENCY: 主要依赖文件
- BYPRODUCTS: 命令可能产生的额外文件
- IMPLICIT_DEPENDS: 指定语言和依赖文件
TARGET 形式特有参数
- TARGET: 关联的目标
- PRE_BUILD: 在目标构建前执行
- PRE_LINK: 在目标链接前执行
- POST_BUILD: 在目标构建后执行
使用示例
示例1:生成源文件
add_custom_command(
OUTPUT generated.cpp
COMMAND generate_tool -o generated.cpp
DEPENDS template.txt
COMMENT "Generating source file" )
add_executable(my_app main.cpp generated.cpp)
示例2:构建后复制文件
add_executable(my_app main.cpp)
add_custom_command(
TARGET my_app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:my_app>
${CMAKE_BINARY_DIR}/bin/
COMMENT "Copying executable to bin directory" )
示例3:自定义处理步骤
add_custom_command(
OUTPUT processed.data
COMMAND preprocessor input.data > processed.data
DEPENDS input.data
COMMENT "Preprocessing data file" )
add_custom_target(
process_data ALL
DEPENDS processed.data )
注意事项
- 使用
OUTPUT
形式时,生成的文件必须被其他目标直接或间接依赖 PRE_BUILD
在某些生成器(如Visual Studio)中可能不起作用- 对于复杂操作,考虑使用
add_custom_target
配合add_dependencies
- 跨平台时注意命令的可移植性
8、C++版本定义
target_complie_features(${CMAKE_PROJECT_NAME} PRIVATE cxx_std_17)
或者
set(CMAKE_CXX_STANDARD 17)
区别
方法 | 作用范围 | 是否可精细控制 | 推荐场景 |
---|---|---|---|
set(CMAKE_CXX_STANDARD 17) | 全局生效 | 否 | 简单项目 |
target_compile_features() | 目标级别 | 是 | 多目标项目,需特性隔离 |
9、示例
cmake_minimum_required(VERSION 3.12)
project(ReactorSystem VERSION 1.0.0 LANGUAGES CXX)
# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# 配置编译选项
if(MSVC)
add_compile_options(/W4 /WX /O2)
else()
add_compile_options(-Wall -Wextra -Werror -O3 -pthread)
endif()
# 查找依赖 (示例:查找Boost库)
find_package(Boost 1.70 REQUIRED COMPONENTS system thread)
# 添加可执行文件
add_executable(reactor_core
src/main.cpp
src/ReactorCore.cpp
src/TemperatureMonitor.cpp
src/CoolantSystem.cpp
src/SafetyControl.cpp
)
# 包含目录
target_include_directories(reactor_core PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${Boost_INCLUDE_DIRS}
)
# 链接库
target_link_libraries(reactor_core PRIVATE
${Boost_LIBRARIES}
# 其他系统库根据需要添加
)
# 安装规则
install(TARGETS reactor_core
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
install(DIRECTORY include/ DESTINATION include)
# 添加自定义构建后检查
add_custom_command(TARGET reactor_core POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Reactor core binary built successfully"
COMMENT "Reactor system build complete"
)
# 添加单元测试 (可选)
enable_testing()
add_subdirectory(tests)
# 打包配置
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)