1、CMake概述
CMake 是一个项目构建工具,并且是跨平台的。关于项目构建我们所熟知的还有Makefile(通过 make 命令进行项目的构建),大多是IDE软件都集成了make,比如:VS 的 nmake、linux 下的 GNU make、Qt 的 qmake等,如果自己动手写 makefile,会发现,makefile 通常依赖于当前的编译平台,而且编写 makefile 的工作量比较大,解决依赖关系时也容易出错。
而 CMake 恰好能解决上述问题, 其允许开发者指定整个工程的编译流程,在根据编译平台,自动生成本地化的Makefile和工程文件,最后用户只需make编译即可,所以可以把CMake看成一款自动生成 Makefile的工具,其编译流程如下图:


介绍完CMake的作用之后,再来总结一下它的优点:
跨平台
能够管理大型项目
简化编译构建过程和编译过程
可扩展:可以为 cmake 编写特定功能的模块,扩充 cmake 功能
2、CMake的使用
CMake支持大写、小写、混合大小写的命令。如果在编写CMakeLists.txt文件时使用的工具有对应的命令提示,那么大小写随缘即可,不要太过在意
2.1、注释
行注释:使用#
块注释 使用#[[ ]]
#cmake 所需要的最小Cmake版本
cmake_minimum_required(VERSION 3.31.0)
#[[ 这是一个 CMakeLists.txt 文件。
这是一个块注释
这是一个 CMakeLists.txt 文件]]
2.2、双引号的使用
- 对命令参数的影响
针对没有空格的命令 加上双引号和没加双引号两者的区别不大,但是针对存在空格的命令参数如 program file 是不同
message("program file") # 输出的program file
message(program file) # 输出的programfile 中间的空格会被忽略掉
- 引用变量的时候
set(MY_LIST Hello World China)
message(${
MY_LIST})
输出:
HelloWorldChina
set(MY_LIST Hello World China)
message("${MY_LIST}")
输出:Hello;World;China
"${MY_LIST}"这种形式的时候,要让 CMake 把这个数组的所有元素当成一个整体,而不是分散的个体。
为了保持数组的含义,又提供一个整体的表达方式,CMake 就会用分号“;” 把这数组的多个元素连接起来
2.3、Cmake常用的命令
2.3.1 定义变量
- 设置简单变量
语法:
set(VARIABLE_NAME value) #这会将 VARIABLE_NAME 设置为指定的 value。如果变量已经存在,则会覆盖其旧值。
eg:
set(MY_VARIABLE "Hello, World!")
- 使用简单变量
${
VARIABLE_NAME}
- 设置多个值 (列表)
#可以将多个值赋给一个变量,形成一个列表:
set(VARIABLE_NAME value1 value2 value3)
eg:
set(SOURCES main.cpp utils.cpp helper.cpp)
注意空格分隔的字符,如果使用带有空格的的字符串,这需要使用引号括起来
set(VARIABLE_NAME "This is a string with spaces")
- 使用 set 追加值
set(VARIABLE_NAME ${
VARIABLE_NAME} new_value)
- 使用 list 命令来追加值,这样可以避免潜在的空格问题
set(SOURCES main.cpp)
list(APPEND SOURCES utils.cpp)
- 设置缓存变量
你可以将变量存储在 CMake 缓存中,这样它们可以在多次构建之间保持不变。缓存变量可以通过命令行进行修改。
set(VARIABLE_NAME value CACHE TYPE "Description")
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build, options are: None Debug Release.")
TYPE 可以是以下几种之一:
- STRING:普通字符串。
- PATH:路径类型,通常用于文件或目录路径。
- FILEPATH:文件路径类型。
- BOOL:布尔类型,值为 ON 或 OFF。
- INTERNAL:内部变量,不会显示在 CMake GUI 中。
设置环境变量
CMake 本身不直接操作环境变量,但你可以通过 set(ENV{VARIABLE_NAME} value) 来设置环境变量。 这种方式只会在 CMake 配置过程中生效,不会影响系统的环境变量。
设置父作用域中的变量
默认情况下,set 命令设置的变量只在当前作用域内可见。如果你想将变量设置为父作用域可见,可以使用 PARENT_SCOPE 选项。
function(my_function)
set(MY_VARIABLE "Hello from function" PARENT_SCOPE)
endfunction()
my_function()
message(STATUS "MY_VARIABLE: ${MY_VARIABLE}") # 输出: MY_VARIABLE: Hello from function
检查变量是否存在
使用 if 语句来检查变量是否存在:
if(DEFINED VARIABLE_NAME)
message(STATUS "VARIABLE_NAME is defined")
else()
message(STATUS "VARIABLE_NAME is not defined")
endif()
- 设置变量为空
变量设置为空字符串或未定义状态:
设置变量为空
set(VARIABLE_NAME "")
- 取消变量设置
unset(VARIABLE_NAME)
- 设置变量的默认值
可以使用 if(NOT DEFINED VARIABLE_NAME) 来检查变量是否已定义,并为其设置默认值:
if(NOT DEFINED MY_VARIABLE)
set(MY_VARIABLE "default_value")
endif()
- 使用 set 进行条件赋值
if(CONDITION)
set(VARIABLE_NAME value1)
else()
set(VARIABLE_NAME value2)
endif()
if(UNIX)
set(OS_SPECIFIC_FLAGS "-Wall -Wextra")
elseif(WIN32)
set(OS_SPECIFIC_FLAGS "/W4")
endif()
- 使用 set 进行数学运算
CMake 提供了 math(EXPR …) 和 math(EXPR …) 命令来进行数学运算,但你也可以使用 set 结合表达式来进行简单的数学运算
set(VARIABLE_NAME ${
VARIABLE_NAME} + 1)
set(COUNT 0)
set(COUNT ${
COUNT} + 1)
message(STATUS "COUNT: ${COUNT}") # 输出: COUNT: 1
- 使用 set 进行字符串拼接
可以使用 ${} 语法进行字符串拼接:
set(VARIABLE_NAME "${PREFIX}_${SUFFIX}")
set(PREFIX "prefix")
set(SUFFIX "suffix")
set(FULL_NAME "${PREFIX}_${SUFFIX}")
message(STATUS "FULL_NAME: ${FULL_NAME}") # 输出: FULL_NAME: prefix_suffix
- 使用 set 进行路径操作
可以使用 set 结合 file 命令进行路径操作,例如获取当前目录、拼接路径等
set(CURRENT_DIR ${
CMAKE_CURRENT_SOURCE_DIR})
set(OUTPUT_DIR "${CURRENT_DIR}/build")
使用 set 进行多平台配置
可以根据不同的平台设置不同的变量值:
if(UNIX)
set(OS_SPECIFIC_FLAGS "-Wall -Wextra")
elseif(WIN32)
set(OS_SPECIFIC_FLAGS "/W4")
endif()
- 使用 set设置 C++标准
#增加-std=c++11
set(CMAKE_CXX_STANDARD 11)
#增加-std=c++14
set(CMAKE_CXX_STANDARD 14)
#增加-std=c++17
set(CMAKE_CXX_STANDARD 17)
2.3.2 搜索文件
find_file 命令用于在指定路径中搜索文件,并将找到的文件路径存储在一个变量中。
基本用法
find_file(VARIABLE_NAME file_name [PATHS path1 path2 ...] [PATH_SUFFIXES suffix1 suffix2 ...])
- VARIABLE_NAME:存储找到的文件路径的变量。
- file_name:要搜索的文件名。
- PATHS:可选参数,指定搜索的路径列表。
- PATH_SUFFIXES:可选参数,指定搜索路径的子目录列表。
示例
假设你要搜索一个名为 config.h 的文件,可以在项目的根目录及其子目录中进行搜索:
find_file(CONFIG_FILE_PATH config.h
PATHS ${
CMAKE_SOURCE_DIR}
PATH_SUFFIXES include)
如果找到了 config.h 文件,CONFIG_FILE_PATH 变量将包含该文件的完整路径;否则,它将为空
也可以通过CMAKE_INCLUDE_PATH 宏定义指定搜索的路径
- 设置 CMAKE_INCLUDE_PATH 变量
set(CMAKE_INCLUDE_PATH ${
PROJECT_SOURCE_DIR}/src)
find_file(CONFIG_FILE_PATH config.h)
使用 file(GLOB …) 搜索多个文件
file(GLOB …) 命令用于根据通配符模式搜索多个文件,并将结果存储在一个列表中。
file(GLOB/GLOB_RECURSE VARIABLE_NAME [RELATIVE path] pattern1 pattern2 ...)
GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中
VARIABLE_NAME:存储找到的文件路径列表的变量。
RELATIVE:可选参数,指定相对于某个路径的相对路径。
pattern1 pattern2 …:通配符模式,用于匹配文件名。
eg
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.h)
获取相对于项目根目录的相对路径,可以使用
RELATIVE 选项
file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_SOURCE_DIR} *.cpp)
- 使用 find_path 搜索路径
find_path 命令用于搜索包含特定文件的目录,并将找到的目录路径存储在一个变量中。
find_path(VARIABLE_NAME file_name [PATHS path1 path2 …] [PATH_SUFFIXES suffix1 suffix2 …])
VARIABLE_NAME:存储找到的目录路径的变量。
file_name:要搜索的文件名。
PATHS:可选参数,指定搜索的路径列表。
PATH_SUFFIXES:可选参数,指定搜索路径的子目录列表。
#[[如果找到了 config.h 文件,
CONFIG_INCLUDE_DIR 变量将包含该文件所在目录的路径;否则,它将为空]]
find_path(CONFIG_INCLUDE_DIR config.h
PATHS /usr/include /opt/include
PATH_SUFFIXES myproject)
- 使用 find_library 搜索库文件
find_library 命令用于搜索库文件(如 .a、.lib 或 .so 文件),并将找到的库文件路径存储在一个变量中
find_library(VARIABLE_NAME library_name [PATHS path1 path2 ...] [PATH_SUFFIXES suffix1 suffix2 ...])
VARIABLE_NAME:存储找到的库文件路径的变量。
library_name:要搜索的库文件名(不带扩展名)。
PATHS:可选参数,指定搜索的路径列表。
PATH_SUFFIXES:可选参数,指定搜索路径的子目录列表。
eg:
find_library(MYLIB_LIBRARY mylib
PATHS /usr/lib /opt/lib
PATH_SUFFIXES myproject)
- 使用 find_package 搜索外部包
find_package 命令用于查找并导入外部包,并设置相关的变量。通常,find_package 会调用相应的
Find.cmake 脚本来执行搜索操作。
find_package(PackageName [version] [REQUIRED] [COMPONENTS component1 component2 ...])
PackageName:要查找的包名称。
version:可选参数,指定所需的最低版本。
REQUIRED:可选参数,表示如果找不到包则终止配置过程。
COMPONENTS:可选参数,指定需要的组件。
查找 Qt5 并导入其 Widgets 组件
find_package(Qt5 COMPONENTS Widgets REQUIRED)
aux_source_directory 命令可以查找某个路径下的所有源文件
aux_source_directory(< dir > < variable >)
dir:要搜索的目录
variable:将从dir目录下搜索到的源文件列表存储到该变量中
- 搜索 src 目录下的源文件
aux_source_directory(${
CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(app ${
SRC_LIST})
2.3.3 包含头文件
使用 include_directories 添加头文件路径
include_directories 是 CMake 中最常用的命令之一,用于添加头文件的搜索路径。它会将指定的路径添加到编译器的
-I 选项中,使得编译器能够在这些路径中查找头文件。
include_directories([AFTER|BEFORE] [SYSTEM] path1 path2 ...)
AFTER 或 BEFORE
选项来指定是添加到列表的前面或者后面。
SYSTEM 选项,会把指定目录当成系统的搜索目录。
path1 path2 ...:要添加的头文件路径列表。
eg:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 添加头文件路径
include_directories(${
CMAKE_SOURCE_DIR}/include)
# 查找源文件
aux_source_directory(src SOURCES)
# 添加可执行文件
add_executable(MyExecutable ${
SOURCES})
注意事项
- include_directories 的作用范围是全局的,即它会影响所有后续定义的目标(如 add_executable 或 add_library)。如果你只想为特定目标添加头文件路径,可以考虑使用 target_include_directories。
- 使用 target_include_directories 为特定目标添加头文件路径
target_include_directories 是一个更现代和推荐的方式,用于为特定目标(如可执行文件或库)添加头文件路径。它提供了更好的控制和灵活性,尤其是当你有多个目标时
target_include_directories(target_name PRIVATE|PUBLIC|INTERFACE path1 path2 ...)
target_name:目标的名称(如 add_executable 或 add_library 定义的目标)。
PRIVATE|PUBLIC|INTERFACE:指定头文件路径的可见性:
PRIVATE:仅对当前目标可见。
PUBLIC:对当前目标及其依赖的目标可见。
INTERFACE:仅对依赖当前目标的目标可见
eg:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 查找源文件
aux_source_directory(src SOURCES)
# 创建可执行文件
add_executable(MyExecutable ${
SOURCES})
# 为 MyExecutable 添加头文件路径
target_include_directories(MyExecutable PRIVATE ${
CMAKE_SOURCE_DIR}/include)</

最低0.47元/天 解锁文章
2055

被折叠的 条评论
为什么被折叠?



