CMake快速入门
CMake 官网:CMake
- CMake 是一个 跨平台 的安装编译工具,可以用简单的语句来描述 所有平台 的安装(编译过程)
- CMake 可以说已经成为 大部分C++开源项目的标配
1. 为什么要使用CMake?
比如说有一个开源项目,里面有很多 C++ 的源代码文件和头文件,想在的电脑上编译这个项目并运行它。但是的电脑上安装的编译器和 IDE 可能和项目开发者使用的不一样。这就会导致编译和构建项目的问题,因为的 IDE 或构建系统可能无法识别源代码的文件结构和参数等。如果没有足够的经验和技能手动调整工程文件,那么将无法编译和运行这个开源项目
但是,如果这个开源项目使用了 CMake 作为构建工具,那么就可以使用 CMake 自动生成针对的 IDE 或构建系统的项目文件,并在的电脑上轻松地编译和构建该项目,不必去手动配置项目和解决构建问题
2. 创建第一个 CMake 工程
步骤:
- 在工作目录中创建一个
.cpp
文件
#include <iostream>
int main() {
std::cout << "hello world" << std::endl;
}
- 编写
CMakeLists.txt
文件
# CMakeLists.txt
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
- 使用 CMake 命令,生成 makefile 文件
# 配置项目
cmake -S . -B build
# 构建项目
cmake --build build
- 编译文件
cmake .
3. CMake 指令介绍
- 基本语法格式介绍:指令 (参数1 参数2)
- 参数使用 括号包裹
- 参数之间使用 空格 或 分号 分开
- 变量使用
${}
方式取值,但是在 IF控制语句中是直接使用变量名的
# 在一般的指令中使用变量都需要用 ${}
add_executable(hello main.cpp ${HELLO})
# 但在IF语句中,变量可以直接使用
IF(HELLO)
以上一个文件CMakeLists.txt为例
3.1 cmake_minimum_required 指令
在CMake中,cmake_minimum_required
是一个用于指定最低CMake版本要求的指令,它用于确保构建系统具有所需的最低CMake版本
语法:
cmake_minimum_required(VERSION <major>[.<minor>[.<patch>[.<tweak>]]] [FATAL_ERROR])
参数:
VERSION
:指定所需的最低CMake版本。它由主版本号、次版本号、补丁版本号和调整版本号(可选)组成。这些版本号都是整数,并且必须按照从左到右的顺序指定。例如,3.20.1
表示主版本号为3,次版本号为20,补丁版本号为1FATAL_ERROR
(可选):如果设置了这个参数,当CMake版本低于指定的最低版本时,CMake将会产生一个致命错误并停止配置过程
示例:
cmake_minimum_required(VERSION 3.20.1 FATAL_ERROR)
在上面的示例中,它指定了至少需要CMake版本3.20.1。如果当前的CMake版本低于指定的最低版本,配置过程将会停止并显示一个错误信息
通过使用cmake_minimum_required
指令,可以确保构建系统在配置过程中使用的CMake版本符合要求,以避免由于版本不兼容而导致的问题
3.2 project 指令
在CMake中,project
指令用于定义一个项目,并设置项目的名称、版本号以及可选的语言支持
语法:
project(<project_name> [VERSION <version>] [LANGUAGES <language>...])
参数:
<project_name>
是项目的名称,可以是任意字符串<version>
是可选的项目版本号,可以是任意字符串<language>
是可选的项目所支持的语言,可以是多个语言,用空格分隔
示例:
project(MyProject VERSION 1.0 LANGUAGES CXX)
在这个示例中,项目名称是"MyProject",版本号是"1.0",项目支持的语言是C++
3.3 set 指令
在CMake中,set
指令用于设置变量的值
set(<variable> <value> [CACHE <type> <docstring> [FORCE]])
参数:
<variable>
是变量的名称,可以是任意字符串<value>
是变量的值,可以是字符串、列表或布尔值CACHE
是可选的指令,用于将变量设置为缓存变量,可以在CMake缓存中进行持久化存储<type>
是可选的类型,用于指定变量的类型,比如STRING
、BOOL
、FILEPATH
等<docstring>
是可选的文档字符串,用于描述变量的用途和说明FORCE
是可选的指令,用于强制设置变量的值,即使它已经被设置过
示例:
设置一个字符串变量:
set(my_var "Hello, World!")
设置一个列表变量:
set(my_list_var "apple" "banana" "orange")
设置一个缓存变量:
set(my_cache_var "Hello, CMake!" CACHE STRING "A variable stored in the cache")
设置一个布尔变量:
set(my_bool_var TRUE)
强制设置一个变量的值:
set(my_var "New value" CACHE STRING "A variable with a new value" FORCE)
3.4 message 指令
在CMake中,message指令用于在构建过程中打印消息或调试信息
语法:
message([<mode>] "message to display" ...)
参数:
<mode>
是可选的参数,用于指定消息的类型。常用的消息类型有以下几种:
STATUS
:打印消息作为构建过程的状态信息WARNING
:打印警告消息AUTHOR_WARNING
:打印作者级别的警告消息SEND_ERROR
:打印错误消息,并停止构建过程FATAL_ERROR
:打印致命错误消息,并停止构建过程DEPRECATION
:打印废弃警告消息
在"message to display"
中,可以包含要打印的消息内容,可以是字符串常量、变量或表达式。可以通过使用${}
语法来引用变量或表达式
示例:
message("Hello, World!") # 打印普通消息
set(name "John")
message("Hello, ${name}!") # 打印包含变量的消息
message(STATUS "This is a status message.") # 打印状态消息
message(WARNING "This is a warning message.") # 打印警告消息
message(SEND_ERROR "This is an error message.") # 打印错误消息并停止构建
message(FATAL_ERROR "This is a fatal error message.") # 打印致命错误消息并停止构建
3.5 add_executable 指令
在CMake中,add_executable
指令用于定义一个可执行文件的构建规则
语法:
add_executable(<target> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
参数:
<target>
是要创建的可执行文件的名称。可以自定义名称,但通常与源文件的名称相关联。例如,如果有一个源文件main.cpp
,那么可以将目标名称设置为myapp
可选参数包括:
WIN32
:指定可执行文件在Windows上作为窗口应用程序运行MACOSX_BUNDLE
:指定可执行文件在macOS上作为应用程序捆绑包运行EXCLUDE_FROM_ALL
:指定可执行文件不会被默认构建,除非显式指定
在source1 [source2 ...]
中,指定了用于构建可执行文件的源文件列表。可以指定一个或多个源文件,它们将被编译并链接到可执行文件中
示例:
add_executable(myapp main.cpp utils.cpp) # 创建一个名为myapp的可执行文件,使用main.cpp和utils.cpp作为源文件
在这个示例中,main.cpp
和utils.cpp
是源文件,它们将被编译并链接到名为myapp
的可执行文件中
使用add_executable指令,可以定义一个或多个可执行文件的构建规则,并指定它们所需的源文件。这样,CMake将根据这些规则生成相应的构建系统文件,以编译和链接可执行文件
3.6 add_subdirectory 指令
在CMake中,add_subdirectory指令用于向当前CMakeLists.txt文件中添加子目录
语法:
add_subdirectory(<子目录> [二进制目录])
参数:
<子目录>
是要添加的子目录的路径,可以是相对路径或绝对路径[二进制目录]
是可选参数,用于指定子目录的二进制输出目录
如果不指定二进制目录,CMake会在子目录中创建一个默认的二进制输出目录
当使用add_subdirectory时,CMake会在指定的子目录中查找一个名为CMakeLists.txt的文件,并执行该文件中的指令。这样,可以将一个大型项目分成多个子目录,每个子目录都有自己的CMakeLists.txt文件来管理
在子目录的CMakeLists.txt文件中,可以定义该子目录的构建规则、目标、变量等。子目录可以使用父目录中定义的变量和属性,也可以定义自己的变量和属性
使用add_subdirectory指令可以帮助管理复杂项目的结构,使得项目的构建更加模块化和可维护。通过将不同功能模块或子项目放在不同的子目录中,可以更好地组织代码和资源
需要注意的是,add_subdirectory指令必须在当前CMakeLists.txt文件中的project命令之后使用
3.7 add_library 指令
在CMake中,add_library
指令用于向CMake项目中添加一个库文件
语法:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
参数:
<name>
是库文件的名称source1 source2 ... sourceN
是构建库文件所需的源文件
add_library
指令有几个参数选项:
STATIC
:指定库文件为静态库。静态库在链接时会被完整地复制到可执行文件中SHARED
:指定库文件为共享库(动态库)。共享库在运行时被动态加载,可被多个可执行文件共享MODULE
:指定库文件为模块库。模块库在运行时被动态加载,类似于共享库,但在某些平台上具有不同的加载方式EXCLUDE_FROM_ALL
:指定该库文件不会被默认构建。这在希望将库文件作为可选组件时非常有用
下面是一个示例:
add_library(MyLibrary STATIC source1.cpp source2.cpp)
在这个示例中,CMake将使用
source1.cpp
和source2.cpp
两个源文件构建一个名为MyLibrary
的静态库
3.8 add_compile_options 指令
在CMake中,add_compile_options
指令用于向编译器添加编译选项。它的语法如下:
add_compile_options([target] <options>...)
参数:
target
是可选的,表示要为特定目标添加编译选项。如果没有指定target
,则编译选项将应用于整个项目
options
是要添加的编译选项列表,可以是一个或多个选项。每个选项都是一个字符串,用于指定要传递给编译器的具体选项
下面是一些常见的编译选项示例:
-Wall
:启用所有警告。-Werror
:将警告视为错误。-O2
:启用优化等级2。-std=c++11
:指定使用C++11标准。
示例:
# 添加编译选项到整个项目
add_compile_options(-Wall -Werror)
# 添加编译选项到特定目标
add_executable(myapp main.cpp)
target_compile_options(myapp PRIVATE -O2)
在上述示例中,通过
add_compile_options
将-Wall
和-Werror
选项添加到整个项目中的所有目标。然后,使用target_compile_options
将-O2
选项添加到名为myapp
的特定目标
通过使用add_compile_options
指令,可以轻松地向CMake项目中的目标添加编译选项,以满足特定的编译需求
3.9 include_directories 指令
在CMake中,include_directories
是一个用于指定包含目录的指令。它用于告诉CMake编译器在编译过程中搜索头文件的位置
include_directories
的语法如下:
include_directories([AFTER|BEFORE] [SYSTEM] <directory1> [<directory2> ...])
参数:
AFTER
或BEFORE
(可选):指定包含目录的添加位置相对于已有的包含目录。默认情况下,新的包含目录会添加到已有目录的末尾。如果指定了AFTER
,则新的目录将添加到已有目录的末尾;如果指定了BEFORE
,则新的目录将添加到已有目录的开头SYSTEM
(可选):指定包含的目录是系统级别的目录,这意味着编译器在搜索头文件时会将其视为系统级别的目录,而不是项目级别的目录<directory1> [<directory2> ...]
:指定要添加的包含目录的路径。可以指定一个或多个目录,用空格分隔
使用include_directories
指令的示例:
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(AFTER ${PROJECT_SOURCE_DIR}/third-party/include)
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/system-include)
在上面的示例中,第一行将${PROJECT_SOURCE_DIR}/include
目录添加为项目级别的包含目录。第二行使用AFTER
指令将${PROJECT_SOURCE_DIR}/third-party/include
目录添加到已有目录的末尾。第三行使用SYSTEM
指令将${PROJECT_SOURCE_DIR}/system-include
目录添加为系统级别的包含目录
通过使用include_directories
指令,可以指定项目中需要搜索头文件的目录,以便编译器能够正确找到并包含所需的头文件
3.10 link_directories 指令
当在CMake中构建一个项目时,可能需要链接一些库文件。link_directories
指令用于指定链接库文件的目录
语法:
link_directories(directory1 directory2 ...)
参数:
directory1
,directory2
, … 是链接库文件的目录路径
link_directories
指令告诉CMake在链接阶段搜索库文件时应该查找的目录。这样,就可以在代码中使用库文件而无需指定完整的路径
下面是一个示例:
link_directories(/path/to/lib1 /path/to/lib2)
在这个示例中,CMake将在链接阶段搜索
/path/to/lib1
和/path/to/lib2
目录中的库文件
需要注意的是,使用link_directories
指令并不会自动链接库文件,它只是告诉CMake在链接阶段搜索库文件的位置。要链接库文件,还需要使用target_link_libraries
指令
下面是一个完整的示例:
cmake_minimum_required(VERSION 3.0)
project(MyProject)
# 指定链接库文件的目录
link_directories(/path/to/lib1 /path/to/lib2)
# 添加可执行文件
add_executable(MyExecutable main.cpp)
# 链接库文件
target_link_libraries(MyExecutable lib1 lib2)
在这个示例中,CMake将在链接阶段搜索
/path/to/lib1
和/path/to/lib2
目录中的库文件,并将lib1
和lib2
链接到MyExecutable
可执行文件中
3.11 target_link_libraries 指令
在CMake中,target_link_libraries
指令用于将库文件链接到目标(可执行文件、共享库等)
语法:
target_link_libraries(<target> [item1] [item2] [...])
参数:
target
是要链接库的目标,可以是可执行文件、共享库或静态库item1, item2, ...
是要链接的库文件或目标。可以指定一个或多个库文件或目标
示例:
# 链接共享库
add_executable(myapp main.cpp)
target_link_libraries(myapp mylib)
# 链接多个库文件
target_link_libraries(myapp lib1 lib2 lib3)
# 链接系统库
target_link_libraries(myapp pthread)
在上述示例中,通过target_link_libraries
将名为mylib
的共享库链接到myapp
可执行文件。然后,使用target_link_libraries
链接了多个库文件lib1
、lib2
和lib3
到myapp
。最后,通过target_link_libraries
链接了系统库pthread
到myapp
除了库文件,还可以使用其他目标作为参数。这允许将一个目标链接到另一个目标,以构建更复杂的项目结构
需要注意的是,CMake会自动处理库文件之间的依赖关系,因此无需手动指定依赖关系的顺序
3.12 aux_source_directory 指令
当使用CMake构建项目时,aux_source_directory
指令用于将指定目录下的源文件自动添加到一个变量中
语法:
aux_source_directory(dir variable)
参数:
dir
是要搜索源文件的目录路径variable
是用于存储找到的源文件列表的变量名
aux_source_directory
指令会自动查找指定目录下的所有源文件,并将它们的完整路径添加到variable
变量中。这样,就可以在后续的构建过程中使用这个变量来引用这些源文件
需要注意的是,aux_source_directory
指令只会自动查找指定目录下的源文件,而不会查找子目录中的源文件。如果希望递归地查找源文件,可以使用aux_source_directory
指令的增强版aux_source_directory_recursive
示例:
aux_source_directory(src SOURCES)
add_executable(myapp ${SOURCES})
在上面的示例中,aux_source_directory
指令会查找src
目录下的所有源文件,并将它们的路径存储在SOURCES
变量中。然后,我们可以使用add_executable
指令将这些源文件编译为一个可执行文件
3.13 install 指令
在CMake中,安装是指将构建生成的文件(可执行文件、库文件、头文件等)复制到指定位置,以便用户可以在系统上使用。CMake提供了一系列命令和变量,用于定义安装规则和目标
首先,需要在CMakeLists.txt文件中使用install命令来定义安装规则
基本语法如下:
install(<文件/目录> ... DESTINATION <目标路径>
[PERMISSIONS <权限>]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <组件>]
[OPTIONAL]
)
参数:
<文件/目录>
表示要安装的文件或目录的路径。可以使用相对路径或绝对路径,并可以使用通配符进行模式匹配。可以指定多个文件或目录,以空格分隔DESTINATION
指定了目标路径,即要将文件/目录安装到的位置。可以使用绝对路径或相对路径。相对路径是相对于CMAKE_INSTALL_PREFIX变量定义的路径。可以使用${CMAKE_INSTALL_PREFIX}
变量来引用CMAKE_INSTALL_PREFIXPERMISSIONS
是可选参数,用于设置安装文件的权限。可以使用UNIX风格的权限表示,如OWNER_READ、GROUP_WRITE等CONFIGURATIONS
是可选参数,用于指定只在特定构建配置下安装文件。可以使用Debug、Release等构建配置名称COMPONENT
是可选参数,用于指定安装文件所属的组件。组件可以用于将安装文件分组,方便用户选择安装哪些组件
OPTIONAL
是可选参数,表示安装文件是可选的。如果文件不存在,将不会引发错误
除了install命令,还可以使用其他命令来定义安装规则,如install(DIRECTORY)用于安装目录,install(TARGETS)用于安装目标(可执行文件、库文件等)
在CMakeLists.txt文件中,可以使用CMAKE_INSTALL_PREFIX变量来定义安装的根目录。默认情况下,CMAKE_INSTALL_PREFIX被设置为/usr/local,但可以通过命令行参数或CMake GUI进行修改
安装时,可以使用以下命令来执行构建和安装:
cmake <源码目录>
make
make install
执行make命令会根据CMakeLists.txt文件中定义的构建规则进行构建。执行make install命令会将构建生成的文件安装到指定位置
需要注意的是,安装目录需要有足够的权限才能进行安装。对于系统级的安装,可能需要使用管理员权限进行安装
4. CMake 常用变量
在CMake中,有一些常用的预定义变量,它们提供了关于项目、系统和构建环境的信息
下面是一些常见的CMake变量及其描述:
变量名 | 描述 |
---|---|
CMAKE_SOURCE_DIR | 项目根目录的绝对路径 |
CMAKE_BINARY_DIR | 构建目录的绝对路径 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的源文件目录的绝对路径 |
CMAKE_CURRENT_BINARY_DIR | 当前处理的二进制目录的绝对路径 |
CMAKE_C_COMPILER | C编译器的路径 |
CMAKE_CXX_COMPILER | C++编译器的路径 |
CMAKE_INCLUDE_PATH | 需要搜索的附加头文件路径 |
CMAKE_LIBRARY_PATH | 需要搜索的附加库文件路径 |
CMAKE_INSTALL_PREFIX | 安装目录的前缀路径 |
CMAKE_BUILD_TYPE | 构建类型,例如Debug、Release等 |
CMAKE_C_FLAGS | C编译器的附加编译选项 |
CMAKE_CXX_FLAGS | C++编译器的附加编译选项,一般在后面会追加 std=c++11 |
CMAKE_EXE_LINKER_FLAGS | 可执行文件链接器的附加选项 |
CMAKE_SHARED_LINKER_FLAGS | 共享库链接器的附加选项 |
CMAKE_MODULE_PATH | CMake模块文件的搜索路径 |
CMAKE_FIND_ROOT_PATH | 用于交叉编译时指定依赖库的根目录 |
CMAKE_SYSTEM_NAME | 目标系统的名称,用于交叉编译时指定目标系统 |
CMAKE_SYSTEM_VERSION | 目标系统的版本号,用于交叉编译时指定目标系统版本 |
5. CMake 的语法规则
5.1 语法的规则
-
命令(Command):CMake的语法由一系列命令组成,每个命令都以小写字母开头,并且以括号包围参数。例如,
message("Hello, World!")
是一个命令,它将在构建过程中输出"Hello, World!" -
参数(Arguments):命令的参数可以是字符串、变量或表达式。参数之间使用空格分隔。例如,
message("The answer is ${answer}")
中的${answer}
是一个变量 -
变量(Variables):CMake中的变量用于存储和传递数据。变量的名称由字母、数字和下划线组成,并且区分大小写。变量的值可以是字符串、列表或布尔值。可以使用
set
命令来设置变量的值,例如set(my_variable "Hello")
-
注释(Comments):在CMake中,使用
#
符号来添加注释。注释可以出现在一行的开头或中间,用于解释代码的作用或提供其他相关信息 -
条件语句(Conditionals):CMake支持条件语句,用于根据不同的条件执行不同的代码块。常用的条件语句有
if
、else
和endif
。例如:
if(condition)
# code block
else()
# code block
endif()
- 循环语句(Loops):CMake提供了几种循环语句来重复执行代码块。常用的循环语句有
foreach
和while
。例如:
foreach(item IN LISTS list_variable)
# code block
endforeach()
- 函数(Functions):CMake允许定义和调用函数来组织代码并实现代码的复用。函数可以接受参数,并可以返回值。例如:
function(my_function arg1 arg2)
# code block
endfunction()
5.2 语法注意事项
当使用CMake编写脚本时,有一些语法注意事项需要注意。以下是一些常见的注意事项:
-
大小写敏感:CMake是大小写敏感的,因此变量名、命令和函数名必须与其在脚本中的使用方式完全匹配
-
空格和括号:在CMake中,命令和函数之间需要有空格,并且命令和函数的参数需要用括号括起来,如果源文件名中有空格,那么需要把文件名用双引号括起来
-
注释:CMake使用“#”符号来表示注释。可以使用注释来解释代码的目的或提供其他相关信息
-
变量:在CMake中,变量使用
${}
语法进行引用。变量可以是全局变量,也可以是局部变量。在使用变量之前,通常需要使用set()
命令来定义变量 -
条件语句:CMake支持条件语句,可以使用
if()
、else()
和endif()
来进行条件判断。条件语句可以根据变量的值或其他条件来执行不同的操作 -
循环语句:CMake支持循环语句,可以使用
foreach()
、while()
和endforeach()
等命令来进行循环操作。循环语句可以用于遍历列表或执行一系列重复的操作 -
函数:CMake支持自定义函数,可以使用
function()
和endfunction()
命令来定义函数。函数可以接受参数,并且可以在脚本中多次调用 -
文件包含:CMake允许通过使用
include()
命令来包含其他CMake脚本文件。这可以帮助组织和复用代码 -
路径处理:CMake提供了一些用于处理路径的命令,如
get_filename_component()
和file()
命令。这些命令可以用于获取文件名、目录名或扩展名,以及执行其他与文件和目录相关的操作 -
错误处理:CMake提供了一些命令和变量来处理错误和警告。例如,可以使用
message()
命令输出消息,使用FATAL_ERROR
选项终止脚本的执行
6. 内部构建和外部构建
CMake支持两种主要的构建方式:内部构建(in-source build)和外部构建(out-of-source build)。它们在项目的构建目录和源代码目录之间有所区别
6.1 内部构建(In-Source Build):
- 内部构建是指在源代码目录中直接进行构建,生成的构建文件和中间文件与源代码文件混在一起
- 在内部构建中,CMake生成的构建系统文件(如Makefile或Visual Studio项目文件)将与源代码文件放在同一个目录中
- 这种方式简单方便,适用于小型项目或快速测试,但不推荐在实际项目中使用,因为会导致构建文件和源代码文件混乱,难以清理和管理
6.2 外部构建(Out-of-Source Build):
- 外部构建是指在与源代码目录分离的地方进行构建,生成的构建文件和中间文件与源代码文件分开
- 在外部构建中,需要创建一个单独的构建目录,并在该目录中运行CMake来生成构建系统文件
- 这种方式将构建文件和源代码文件分开,使得项目结构更加清晰,也更容易进行清理和管理
- 外部构建还允许同时使用多个不同的构建目录,用于构建不同的配置(例如Debug和Release)或不同的平台
使用外部构建的步骤如下:
- 创建一个单独的构建目录,例如在项目根目录下创建一个名为"build"的目录
- 进入构建目录,并在该目录中运行CMake命令,指定源代码目录的路径。例如:
cmake /path/to/source_code
- CMake将在构建目录中生成构建系统文件,如Makefile或Visual Studio项目文件
- 使用生成的构建系统文件进行构建,例如使用Make命令或打开Visual Studio进行编译
通过使用外部构建,可以轻松地清理构建文件,同时也可以避免将构建文件与源代码文件混在一起。这种方式更加灵活和可维护,是在实际项目中推荐的构建方式
7. CMake 编译工程
CMake的目录结构通常包含以下几个重要的部分:
- 项目根目录:项目的根目录是CMakeLists.txt文件所在的目录。在这个目录下,你可以定义项目的全局设置和配置选项
- 子目录:项目可以被组织成多个子目录,每个子目录都可以有自己的CMakeLists.txt文件。这种组织方式可以帮助你将项目划分为更小的模块,提高代码的可维护性
- 源代码目录:源代码目录是存放项目源代码的目录,通常包含头文件(.h或.hpp文件)和源文件(.cpp文件)。你可以在CMakeLists.txt文件中使用
add_executable
或add_library
指令来指定源代码目录 - 构建目录:构建目录是用于构建项目的目录,通常是在项目根目录外创建的。在构建目录中,CMake会生成构建系统所需的文件(如Makefile或Visual Studio项目文件),并在这个目录中执行构建操作
下面是一个简单的CMake项目的目录结构示例:
MyProject/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── utils.cpp
│ └── utils.h
└── build/
在这个示例中,MyProject
是项目的根目录,其中包含了CMakeLists.txt文件。src
目录是存放源代码的目录,包含了main.cpp
、utils.cpp
和utils.h
文件。build
目录是构建目录,
用于执行构建操作
7.1 Linux平台下的编译流程
在 Linux 平台下使用 CMake 构建 C/C++ 工程的流程如下:
- 在项目文件夹根目录下创建
CMakeLists.txt
文件 - 编写
CMakeLists.txt
文件- 首先,通过 cmake_minimum_required 指令指定项目最低 CMake 版本
- 使用 project 指令指定工程名 (一般建议大写)
- 首先需要选择是外部构建还是内部构建
- 使用 add_executable 指令指定可执行文件名和相关源文件序列
- 确定是外部构建
- 首先先创建 build 文件夹用来存放 CMake 编译后产生的文件
- 创建好文件夹后,通过
cmake CMakeLists.txt文件路径
指令编译 - 编译完成后,生成
Makefile
文件,使用make Makefile文件所在路径
命令来构建项目生成可执行文件 - 最后在 build 目录中找到可执行文件并执行
注意:如果项目含有头文件,那么你需要在
CMakeLists.txt
中用指令include_directories
指定头文件所在的文件目录 (绝对路径)
实操 CMake 构建工程
步骤:
- 在 CMake 中设置源代码目录和构建后存放二进制文件的目录build
- 点击
Configure
,选择工程的生成器,设置后点击 Finish
- 点击 Configure 后开始构建,之后点击 Generate 生成的工程文件会存放在 build 文件夹中
- 在build文件夹里可以找到helloworld.sln文件,用
Visual Studio 2022
打开,之后点击生成解决方案