一、速查手册
1. 常用命令
命令 | 作用 |
---|---|
cmake … | 使用默认参数执行构建 |
cmake -D CMAKE_BUILD_TYPE=Debug … | 构建带调试信息的程序或库 |
cmake -G Ninja … | 指定生成器为Ninja |
cmake --build . | 根据默认构建系统生成程序 |
cmake -version | 查看cmake版本 |
-B
用于指定构建目录-D
用于定义Cmake变量-E
调用Cmake内置命令的参数-G
用于指定生成器-S
用于指定源代码目录,此目录包含了CMakeLists.txt
文件
2. 常用变量
变量名 | 含义 |
---|---|
CMAKE_SOURCE_DIR | 最顶层CmakeLists.txt所在目录,CHAN |
CMAKE_CURRENT_SOURCE_DIR | 当前CMakeLists.txt 所在路径 |
PROJECT_SOURCE_DIR | 工程的根目录 |
CMAKE_ARCHIVE_OUTPUT_DIRECTORY | 静态库的输出目录 |
CMAKE_LIBRARY_OUTPUT_DIRECTORY | 动态库的输出目录 |
CMAKE_RUNTIME_OUTPUT_DIRECTORY | 可执行文件的输出路径 |
3. 基本模板
cmake_minimum_required (VERSION 3.5)
project (Test)
# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)
# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)
# 添加可执行文件
add_executable(helloworld hello.cpp)
# 链接库
target_link_libraries(helloworld ${CMAKE_SOURCE_DIR}/add.a)
cmake_minimum_required (VERSION 3.5)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
project (Test)
# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)
# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)
# 添加可执行文件
add_executable(helloworld hello.cpp)
# 链接库
target_link_libraries(helloworld ${CMAKE_SOURCE_DIR}/add.a)
二、基本用法
1. 单个源文件
1.1 目录结构
.
├── build
├── CMakeLists.txt
└── hello.cpp
1.2 CmakeLists.txt
cmake_minimum_required (VERSION 3.5)
project (LearnCmake)
add_executable(helloworld hello.cpp)
1.3 编译步骤
cd build
cmake ..
make
2. 多个源文件
2.1 目录结构
Project
├── build
├── add.cpp
├── add.hpp
├── CMakeLists.txt
└── hello.cpp
2.2 CmakeLists.txt
cmake_minimum_required (VERSION 3.5)
project (LearnCmake)
add_executable(helloworld hello.cpp add.cpp)
2.3 编译步骤
cd build
cmake ..
make
3. 编译动态库
3.1 目录结构
├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp
3.2 CmakeLists.txt
cmake_minimum_required (VERSION 3.5)
project (LearnCmake)
# 创建共享库目标
add_library(hello SHARED hello.hpp hello.cpp)
# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ./lib)
3.3 编译步骤
cd build
cmake ..
make
4. 编译静态库
4.1 目录结构
Project
├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp
4.2 CmakeLists.txt
cmake_minimum_required (VERSION 3.5)
project (LearnCmake)
# 创建共享库目标
add_library(hello STATIC hello.hpp hello.cpp)
# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ./lib)
4.3 编译步骤
cd build
cmake ..
make
5. 综合案例
5.1 目录结构
Project
├── build
├── CMakeLists.txt
├── hello.cpp
├── hello.hpp
└── main.cpp
5.2 CmakeLists.txt
# 设置最低版本
cmake_minimum_required (VERSION 3.5)
# 设置项目名称
project (LearnCmake)
# 设置头文件目录
include_directories(${PROJECT_SOURCE_DIR}/inc INC_DIR)
# 设置源文件目录
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_DIR)
# 创建共享库目标
add_library(hello_shared SHARED ${SRC_DIR})
# 创建静态库目标
add_library(hello_static STATIC ${SRC_DIR})
# 设置库的最终生成路径
set(LIBRARY_OUTPUT_PATH ../lib)
# 创建可执行文件
add_executable(main main.cpp)
# 链接库文件
target_link_libraries(main hello_static)
5.3 编译步骤
mkdir -p build
cd build
cmake ..
cmake --build .
三、进阶用法
1. 编译选项
有时因为一些特殊需要,为了实现自定义的编译,我们需要指定编译选项,这时我们可使用 add_compile_options
来添加编译选项,如下:
add_compile_options(-std=c++11 -Wall)
2. 控制选项
有时希望在编译代码时只编译一些指定的源码,可以使用cmake的option命令,主要遇到的情况分为2种:
- 本来要生成多个bin或库文件,现在只想生成部分指定的bin或库文件
- 对于同一个bin文件,只想编译其中部分代码(使用宏来控制)
3. 设置目录
aux_source_directory(dir var)
可把dir目录中的所有源文件都储存在var变量中include_directories ( dir )
,其作用类似gcc中的 gcc -I dir
设置指定头文件及源文件目录的示例CMakeLists.txt
文件如下:
# 设置最低版本
cmake_minimum_required (VERSION 3.5)
# 设置项目名称
project (LearnCmake)
# 设置头文件目录
include_directories(./include1 ./include2)
# 设置源文件目录
aux_source_directory(src1 SRC1_DIR)
aux_source_directory(src2 SRC2_DIR)
aux_source_directory(main MAIN_DIR)
# 生成可执行文件
add_executable(helloworld ${SRC1_DIR} ${SRC2_DI} ${MAIN_DIR})
4. 编译类型
1. Debug: `-O0 -g`
2. Release: `-O3 -DNDEBUG`
3. MinSizeRel: `-Os -DNDEBUG`
4. RelWithDebInfo: `-O2 -g -DNDEBUG`
4.1 C编译标志相关变量
CMAKE_C_FLAGS
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
4.2 C++编译标志相关变量
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]或 CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO] 则指定特定构建类型的编译标志,这些编译标志将被加入到 CMAKE_C_FLAGS 或 CMAKE_CXX_FLAGS 中去,例如,如果构建类型为 DEBUG,那么 CMAKE_CXX_FLAGS_DEBUG 将被加入到 CMAKE_CXX_FLAGS中去
4.3 链接标志相关变量
CMAKE_EXE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_MODULE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_SHARED_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
它们类似于编译标志相关变量
debug版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而release版的不需要调试信息但需要优化。这些特性在gcc/g++中是通过编译时的参数决定的,如果将优化程度调到最高需要设置-O3,最低-O0即不做优化;添加调试信息的参数是-g -ggdb,如果不添加这个参数,调试信息就不会被包含在生成的二进制文件中。
CMake中有一个变量CMAKE_BUILD_TYPE,可以的取值是Debug、Release、RelWithDebInfo和MinSizeRel。当这个变量值为Debug的时候,CMake会使用变量CMAKE_CXX_FLAGS_DEBUG和 CMAKE_C_FLAGS_DEBUG中的字符串作为编译选项生成Makefile ,当这个变量值为 Release 的时候,工程会使用变量 CMAKE_CXX_FLAGS_RELEASE 和CMAKE_C_FLAGS_RELEASE 选项生成 Makefile。
project(main)
cmake_minimum_required(version 2.6)
set(CMAKE_SOURCE_DIR .)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") # 设置debug编译选项
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") # 设置release编译选项
ADD_EXECUTABLE(main ${DIR_SRCS})
AUX_SOURCE_DIRECTORY(. DIR_SRCS)
四、语法规则
Cmake的指令是大小写无关的,但建议全部使用大写指令。
1. 注释
单行注释
# 注释内容
多行注释
# [[
注释内容
]]
2. 变量
Cmake中所有的变量都是string
类型
set(变量名 变量值) # 声明一个变量
unset(变量) # 移除一个变量
${变量名} # 引用变量
message("变量名=${变量名}") # 打印一个变量值
3. 列表
列表也是字符串,可以把列表看作是一个特殊的变量,这个变量包含多个值,其语法格式如下:
set(列表名 值1 值2 值3 ...) # 方式一
set(列表名 "值1;值2;值3;...") # 方式二
引用列表和打印列表与变量的使用方式相同
${列表名} # 引用列表
message("列表名=${列表名}") # 打印列表
4. 作用域
全局层
:cache变量,在整个项目范围可见。一般在set定义变量时,需要指定CACHE
参数才能定义为cache变量目录层
:在当前目录的CMakeList.txt中定义,以及在该文件包含的其他CMake源文件中定义的变量函数层
:在命令函数中定义的变量,属于函数作用域内的变量
5. 判断语句
在 CMake 中,可以使用 if 语句来进行条件判断。CMake 提供了多种条件判断操作符和函数,用于比较字符串、数值、文件属性等。
5.1 比较操作符
CMake的比较操作符如下:
EQUAL
:检查是否相等LESS
:检查是否小于GREATER
:检查是否大于LESS_EQUAL
:检查是否小于或等于GREATER_EQUAL
:检查是否大于或等于STREQUAL
:检查字符串是否相等STRLESS
:检查字符串是否小于(按字典顺序)STRGREATER
:检查字符串是否大于(按字典顺序)EXISTS
:检查文件或目录是否存在IS_DIRECTORY
:检查是否是目录IS_SYMLINK
:检查是否是符号链接IS_ABSOLUTE
:检查路径是否是绝对路径
5.2 逻辑操作符
AND
:逻辑与OR
:逻辑或NOT
:逻辑非
5.3 使用示例
以下是 CMake 中条件判断语句的详细介绍和示例。
if(condition)
# Commands to execute if the condition is true
elseif(another_condition)
# Commands to execute if the another condition is true
else()
# Commands to execute if none of the above conditions are true
endif()
示例代码如下:
# 字符串比较
if(variable STREQUAL "value")
message(STATUS "Variable equals 'value'")
endif()
# 数值比较
if(variable EQUAL 10)
message(STATUS "Variable equals 10")
elseif(variable GREATER 10)
message(STATUS "Variable is greater than 10")
else()
message(STATUS "Variable is less than 10")
endif()
# 文件目录检查
if(EXISTS "path/to/file_or_directory")
message(STATUS "File or directory exists")
endif()
if(IS_DIRECTORY "path/to/directory")
message(STATUS "It is a directory")
endif()
if(IS_SYMLINK "path/to/symlink")
message(STATUS "It is a symbolic link")
endif()
# 逻辑操作
if(variable AND another_variable)
message(STATUS "Both variables are true")
endif()
if(variable OR another_variable)
message(STATUS "At least one of the variables is true")
endif()
if(NOT variable)
message(STATUS "Variable is false")
endif()
更加复杂的示例如下:
操作系统检测
cmake_minimum_required(VERSION 3.0)
project(OSDetection)
if(WIN32)
message(STATUS "This is Windows")
elseif(UNIX)
message(STATUS "This is Unix or Unix-like (including Linux and macOS)")
if(APPLE)
message(STATUS "This is macOS")
else()
message(STATUS "This is Linux or another Unix-like system")
endif()
else()
message(STATUS "Unknown operating system")
endif()
C++标准支持
cmake_minimum_required(VERSION 3.0)
project(CppStandardCheck)
set(CMAKE_CXX_STANDARD 11)
if(CMAKE_CXX_STANDARD EQUAL 11)
message(STATUS "Using C++11")
elseif(CMAKE_CXX_STANDARD EQUAL 14)
message(STATUS "Using C++14")
elseif(CMAKE_CXX_STANDARD EQUAL 17)
message(STATUS "Using C++17")
else()
message(STATUS "Using an unknown or unsupported C++ standard")
endif()
配置选项和条件编译
cmake_minimum_required(VERSION 3.0)
project(ConfigOptions)
option(USE_FEATURE_X "Enable feature X" OFF)
option(USE_FEATURE_Y "Enable feature Y" ON)
if(USE_FEATURE_X)
add_definitions(-DUSE_FEATURE_X)
message(STATUS "Feature X enabled")
endif()
if(USE_FEATURE_Y)
add_definitions(-DUSE_FEATURE_Y)
message(STATUS "Feature Y enabled")
endif()
6. 循环语句
6.1 foreach
用于遍历列表中的每个元素或特定范围的值。
# 遍历一组数值
foreach(v arg1 arg2 ...)
# Commands to execute for each element
endforeach()
# 遍历列表变量
foreach(v IN LISTS list_var)
# Commands to execute for each element in list_var
endforeach()
示例如下
cmake_minimum_required(VERSION 3.0)
project(ForeachExample)
foreach(i 1 2 3 4 5)
message(STATUS "Number: ${i}")
endforeach()
set(my_list a b c d e)
foreach(item IN LISTS my_list)
message(STATUS "Item: ${item}")
endforeach()
6.2 while
用于在给定条件为真时重复执行命令。它的基本用法如下:
while(condition)
# Commands to execute while condition is true
endwhile()
示例如下:
cmake_minimum_required(VERSION 3.0)
project(WhileExample)
set(i 0)
while(i LESS 5)
message(STATUS "Number: ${i}")
math(EXPR i "${i} + 1")
endwhile()
7. 定义函数
在 CMake 中,可以使用 function 关键字来定义函数。函数允许你封装一段逻辑,以便在多个地方重复使用。定义函数的基本语法如下:
function(FunctionName arg1 arg2 ...)
# Commands that the function executes
endfunction()
示例如下:
cmake_minimum_required(VERSION 3.0)
project(FunctionExample)
# 定义普通函数
function(PrintMessage msg)
message(STATUS "Message: ${msg}")
endfunction()
# 调用函数
PrintMessage("Hello, World!")
PrintMessage("This is a custom function in CMake.")
# 定义带有默认值的函数
function(PrintWithPrefix msg prefix)
if(NOT prefix)
set(prefix "DefaultPrefix")
endif()
message(STATUS "${prefix}: ${msg}")
endfunction()
# 调用函数
PrintWithPrefix("Hello, World!" "Greeting")
PrintWithPrefix("This is a message without a prefix")
# 定义函数并设置返回值
function(AddNumbers a b result)
math(EXPR sum "${a} + ${b}")
set(${result} ${sum} PARENT_SCOPE)
endfunction()
# 调用函数并获取返回值
AddNumbers(3 4 result)
message(STATUS "The sum is: ${result}")
# 定义处理列表的函数
function(PrintList mylist)
foreach(item IN LISTS mylist)
message(STATUS "Item: ${item}")
endforeach()
endfunction()
# 调用函数
set(mylist a b c d e)
PrintList(mylist)
8. 定义宏
9. 预设变量
变量 | 作用 |
---|---|
CMAKE_MAJOR_VERSION | cmake 主版本号 |
CMAKE_MINOR_VERSION | cmake 次版本号 |
CMAKE_C_FLAGS | 设置 C 编译选项 |
CMAKE_CXX_FLAGS | 设置 C++ 编译选项 |
PROJECT_SOURCE_DIR | 工程的根目录 |
PROJECT_BINARY_DIR | 运行 cmake 命令的目录 |
CMAKE_CURRENT_SOURCE_DIR | 当前CMakeLists.txt 所在路径 |
CMAKE_CURRENT_BINARY_DIR | 目标文件编译目录 |
EXECUTABLE_OUTPUT_PATH | 重新定义目标二进制可执行文件的存放位置 |
LIBRARY_OUTPUT_PATH | 重新定义目标链接库文件的存放位置 |
UNIX | 如果为真,表示为UNIX-like的系统,包括AppleOSX和CygWin |
WIN32 | 如果为真,表示为 Windows 系统,包括 CygWin |
APPLE | 如果为真,表示为 Apple 系统 |
CMAKE_SIZEOF_VOID_P | 表示void*的大小(例如为4或者8),可以使用其来判断当前构建为32位还是64位 |
CMAKE_CURRENT_LIST_DIR | 表示正在处理的CMakeLists.txt文件所在目录的绝对路径 |
CMAKE_ARCHIVE_OUTPUT_DIRECTORY | 用于设置ARCHIVE目标的输出路径 |
CMAKE_LIBRARY_OUTPUT_DIRECTORY | 用于设置LIBRARY目标的输出路径 |
CMAKE_RUNTIME_OUTPUT_DIRECTORY | 用于设置RUNTIME目标的输出路径 |