CMake 基本语法指南

CMake 是一个跨平台的构建系统生成工具,它使用 CMakeLists.txt 文件来描述项目的构建过程。以下是 CMake 的基本语法和常用命令。

1. 基本结构

最简单的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)  # 指定CMake最低版本
project(MyProject)                    # 定义项目名称
add_executable(my_app main.cpp)       # 添加可执行文件

2. 变量与注释

变量定义与使用

# 设置变量
set(MY_VARIABLE "Hello CMake")

# 使用变量
message(STATUS "The value is: ${MY_VARIABLE}")

注释

# 这是单行注释

#[[
这是多行注释
可以跨越多行
]]

3. 常用命令

项目配置

cmake_minimum_required(VERSION 3.10)  # 最低CMake版本要求
project(MyProject 
    VERSION 1.0.0      # 项目版本
    LANGUAGES CXX      # 使用C++
    DESCRIPTION "A sample project"
)

构建目标

# 添加可执行文件
add_executable(my_app main.cpp src1.cpp src2.cpp)

# 添加静态库
add_library(my_lib STATIC lib1.cpp lib2.cpp)

# 添加动态库
add_library(my_shared_lib SHARED lib1.cpp lib2.cpp)

包含目录

include_directories(${PROJECT_SOURCE_DIR}/include)
# 或更现代的写法
target_include_directories(my_app PUBLIC include)

链接库

# 链接内部库
target_link_libraries(my_app PRIVATE my_lib)

# 链接系统库
find_package(Threads REQUIRED)
target_link_libraries(my_app PRIVATE Threads::Threads)

4. 流程控制

条件语句

if(WIN32)
    message(STATUS "This is Windows")
elseif(APPLE)
    message(STATUS "This is macOS")
elseif(UNIX)
    message(STATUS "This is Linux")
else()
    message(STATUS "Unknown system")
endif()

循环语句

# foreach循环
foreach(i RANGE 1 5)
    message(STATUS "Current value: ${i}")
endforeach()

# while循环
set(counter 0)
while(counter LESS 5)
    message(STATUS "Counter: ${counter}")
    math(EXPR counter "${counter} + 1")
endwhile()

5. 文件操作

文件查找

# 查找源文件
file(GLOB SOURCES "src/*.cpp")

# 递归查找
file(GLOB_RECURSE HEADERS "include/*.h")

# 更推荐显式列出文件
set(SOURCES
    src/main.cpp
    src/util.cpp
)

文件操作

# 读取文件
file(READ "file.txt" CONTENT)

# 写入文件
file(WRITE "output.txt" "Some content")

# 复制文件
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/data" 
     DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")

6. 函数与宏

定义函数

function(print_hello name)
    message(STATUS "Hello, ${name}!")
endfunction()

# 调用函数
print_hello("World")

定义宏

macro(setup_target target_name)
    add_executable(${target_name} ${ARGN})
    target_include_directories(${target_name} PRIVATE include)
endmacro()

# 使用宏
setup_target(my_target main.cpp util.cpp)

7. 查找包与依赖

查找系统库

find_package(OpenSSL REQUIRED)
if(OpenSSL_FOUND)
    target_include_directories(my_app PRIVATE ${OpenSSL_INCLUDE_DIRS})
    target_link_libraries(my_app PRIVATE ${OpenSSL_LIBRARIES})
endif()

自定义查找模块

find_path(MYLIB_INCLUDE_DIR mylib.h
    PATHS /usr/local/include /usr/include
)

find_library(MYLIB_LIBRARY
    NAMES mylib
    PATHS /usr/local/lib /usr/lib
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib DEFAULT_MSG
    MYLIB_LIBRARY MYLIB_INCLUDE_DIR
)

8. 生成器表达式

CMake 提供强大的生成器表达式,用于条件化构建系统生成:

target_compile_definitions(my_app
    PRIVATE $<$<CONFIG:Debug>:DEBUG_MODE=1>
)

target_link_libraries(my_app
    PRIVATE $<$<PLATFORM_ID:Windows>:win32_lib>
            $<$<PLATFORM_ID:Linux>:pthread>
)

9. 安装规则

# 安装可执行文件
install(TARGETS my_app
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

# 安装头文件
install(DIRECTORY include/ DESTINATION include)

# 安装文档
install(FILES README.md LICENSE DESTINATION share/doc/my_app)

10. 常用变量

变量名描述
CMAKE_SOURCE_DIR顶级源代码目录
CMAKE_BINARY_DIR顶级构建目录
CMAKE_CURRENT_SOURCE_DIR当前处理的CMakeLists.txt所在目录
CMAKE_CURRENT_BINARY_DIR当前构建目录
CMAKE_C_COMPILERC编译器路径
CMAKE_CXX_COMPILERC++编译器路径
CMAKE_BUILD_TYPE构建类型 (Debug/Release等)
CMAKE_INSTALL_PREFIX安装前缀 (/usr/local)
PROJECT_NAME当前项目名称
PROJECT_SOURCE_DIR项目源代码目录
PROJECT_BINARY_DIR项目构建目录

11. 构建类型与编译选项

# 设置构建类型
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

# 设置编译选项
if(MSVC)
    target_compile_options(my_app PRIVATE /W4 /WX)
else()
    target_compile_options(my_app PRIVATE -Wall -Wextra -pedantic)
endif()

# 针对不同构建类型设置不同选项
target_compile_definitions(my_app
    PRIVATE $<$<CONFIG:Debug>:DEBUG=1>
            $<$<CONFIG:Release>:NDEBUG=1>
)

12. 现代 CMake 最佳实践

  1. 使用目标(target)为中心的方法

  • target_include_directories()
    target_compile_options()
    target_link_libraries()
  • 避免使用全局命令

    • 避免 include_directories(),改用 target_include_directories()

    • 避免 link_libraries(),改用 target_link_libraries()

  • 正确使用 PUBLIC/PRIVATE/INTERFACE

    • PRIVATE:仅当前目标使用

    • INTERFACE:仅依赖者使用

    • PUBLIC:当前目标和依赖者都使用

  • 导出和导入目标

  1. install(TARGETS my_lib EXPORT my_lib-targets
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
        INCLUDES DESTINATION include
    )
    
    install(EXPORT my_lib-targets
        FILE my_lib-config.cmake
        DESTINATION lib/cmake/my_lib
    )

CMake 是一个功能强大但复杂的工具,掌握其基本语法和现代用法可以大大提高项目的可维护性和跨平台能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值