CMake基本命令及作用

命令和作用

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>要查找的库/包名称(如 OpenCVBoost
[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_DIRCMAKE_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. 要链接的库

可以分为以下几种情况

  1. CMake 目标(由 add_library() 创建)

    add_library(math STATIC math.cpp)
    target_link_libraries(my_app PRIVATE math)
    
  2. 系统库(如 pthreaddlm

    target_link_libraries(my_app PRIVATE pthread dl m)
    
  3. 外部库(如 OpenCVBoost

    find_package(OpenCV REQUIRED) target_link_libraries(my_app PRIVATE ${OpenCV_LIBS})
    
  4. 绝对路径或库名

    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 )
注意事项
  1. 使用 OUTPUT 形式时,生成的文件必须被其他目标直接或间接依赖
  2. PRE_BUILD 在某些生成器(如Visual Studio)中可能不起作用
  3. 对于复杂操作,考虑使用 add_custom_target 配合 add_dependencies
  4. 跨平台时注意命令的可移植性

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值