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_COMPILER | C编译器路径 |
CMAKE_CXX_COMPILER | C++编译器路径 |
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 最佳实践
-
使用目标(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
:当前目标和依赖者都使用
-
-
导出和导入目标:
-
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 是一个功能强大但复杂的工具,掌握其基本语法和现代用法可以大大提高项目的可维护性和跨平台能力。