文章目录
- 1 :peach:什么是CMake:peach:
- 2 :peach:CMake的使用:peach:
1 🍑什么是CMake🍑
官方回答是:CMake 是一个开源的、跨平台的自动化建构系统,它使用一个名为 CMakeLists.txt
的文件来描述构建过程,包括源代码编译规则、链接库、生成文件等。CMake 不直接构建项目,而是生成标准的构建文件(如 Unix 的 Makefile 或 Windows 的 Visual Studio 项目文件),这些文件由原生构建环境使用。使用 CMake 可以简化复杂项目的构建和维护过程,使开发者能够更专注于代码编写和调试。
通俗来说,CMake可以理解为一个高级编译配置工具,当多个人使用不同的语言或者编译器开发一个项目时,最终要输出一个可执行文件或者共享库,所有的操作都是通过编译CMakeLists.txt
文件来完成的,学习CMake是为了将来处理大型的C++/JAVA项目做准备。
介绍完CMake的作用之后,再来总结一下它的优点:
- 跨平台
- 能够管理大型项目
- 简化编译构建过程和编译过程
- 可扩展:可以为 cmake 编写特定功能的模块,扩充 cmake 功能
2 🍑CMake的使用🍑
CMake支持大写、小写、混合大小写的命令。如果在编写CMakeLists.txt
文件时使用的工具有对应的命令提示,那么大小写随缘即可,不要太过在意。
2.1 🍎注释🍎
CMake进行注释的时候通常有两种方式:一种是是使用#
注释一行,另外一种是使用#[[ ]]
注释一种代码块。
比如:
#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
cmake_minimum_required(VERSION 3.0.0)
2.2 🍎简单示例🍎
比如在下面这种场景下:
其中里面的add.h/sub.h存放的时候函数声明,而add.cpp/sub.cpp存放的是函数的定义。
然后我们再编写一个CMakeLists.txt
文件,注意该文件名区分大小写,不要写错了。
文件内容如下:
cmake_minimum_required(VERSION 3.20.2)
project(CALC)
add_executable(calculator add.c main.c sub.c)
接下来依次介绍一下在 CMakeLists.txt
文件中添加的三个命令:
cmake_minimum_required
:指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。project
:定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project
指令的语法是:
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
add_executable
:定义工程会生成一个可执行程序
add_executable(可执行程序名 源文件名称)
这里的可执行程序名和project中的项目名没有任何关系。源文件名可以是一个也可以是多个,如有多个可用空格
或 ;
间隔。
# 样式1
add_executable(calculator add.cpp main.cpp sub.cpp)
# 样式2
add_executable(calculator add.cpp;main.cpp;sub.cpp)
万事俱备只欠东风,将 CMakeLists.txt
文件编辑好之后,就可以执行 cmake命令了。
# cmake 命令原型
$ cmake CMakeLists.txt文件所在路径
我们使用cmake
后再使用tree
命令来查看当前生成的目录结构:
其他的我们可以先不管,然后我们再执行make
,就会生成可执行文件,执行可执行文件就可以得到正确的结果:
但是通过上面这种方式我们不难发现一个问题,那就是源文件与生成的一些文件混合在一起容易混淆视听,所以通常情况下我们会将生成的文件放在一个build
目录下,名字可以随便起没有强制要求。
我们进入到创建的build
目录中,让后执行cmake ..
命令,再make
:
此时程序的结构就会清晰许多。
2.3 🍎私人订制🍎
2.3.1 🍋定义变量🍋
在上面的例子中一共提供了3个源文件,假设这3个源文件需要反复被使用,每次都直接将它们的名字写出来确实是很麻烦,此时我们就需要定义一个变量,将文件名对应的字符串存储起来,在cmake里定义变量需要使用set
。
# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
VAR
:变量名VALUE
:变量值
示例:
# 方式1: 各个源文件之间使用空格间隔
set(SRC_LIST add.c main.c sub.c)
# 方式2: 各个源文件之间使用分号 ; 间隔
set(SRC_LIST add.c;main.c;sub.c)
add_executable(app ${SRC_LIST})
2.3.2 🍋指定使用的C++标准🍋
set
除了用来指定变量外还可以指定使用的C++标准,在编写C++程序的时候,可能会用到C++11、C++14、C++17、C++20等新特性,那么就需要在编译的时候在编译命令中制定出要使用哪个标准,通常有两种方式。
- 方法1:在
CMakeLists.txt
中通过set
命令指定:
#增加-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:在执行
cmake
命令的时候指定出这个宏的值:
#增加-std=c++11
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
#增加-std=c++14
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14
#增加-std=c++17
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
在上面例子中 cmake 后的路径需要根据实际情况酌情修改。
2.3.3 🍋指定输出的路径🍋
在CMake中指定可执行程序输出的路径,也对应一个宏,叫做EXECUTABLE_OUTPUT_PATH
,它的值还是通过set
命令进行设置:
set(HOME /home/robin/Linux/Sort)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
- 第一行:定义一个变量用于存储一个绝对路径
- 第二行:将拼接好的路径值设置给
EXECUTABLE_OUTPUT_PATH
宏
如果这个路径中的子目录不存在,会自动生成,无需自己手动创建。
由于可执行程序是基于 cmake
命令生成的 makefile
文件然后再执行 make
命令得到的,所以如果此处指定可执行程序生成路径的时候使用的是相对路径 ./xxx/xxx
,那么这个路径中的 ./
对应的就是 makefile
文件所在的那个目录。
2.4 🍎搜索文件🍎
如果一个项目里边的源文件很多,在编写CMakeLists.txt
文件的时候不可能将项目目录的各个文件一一罗列出来,这样太麻烦也不现实。所以,在CMake中为我们提供了搜索文件的命令,可以使用aux_source_directory
命令或者file
命令。
2.4.1 🍋aux_source_directory🍋
在 CMake 中使用aux_source_directory
命令可以查找某个路径下的所有源文件,命令格式为:
aux_source_directory(< dir > < variable >)
dir
:要搜索的目录variable
:将从dir目录下搜索到的源文件列表存储到该变量中
示例:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
# 搜索 src 目录下的源文件
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(app ${SRC_LIST})
2.4.2 🍋file🍋
如果一个项目里边的源文件很多,在编写CMakeLists.txt
文件的时候不可能将项目目录的各个文件一一罗列出来,这样太麻烦了。所以,在CMake中为我们提供了搜索文件的命令,他就是file
(当然,除了搜索以外通过 file
还可以做其他事情)。
file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
GLOB
: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。GLOB_RECURSE
:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。
搜索当前目录的src
目录下所有的源文件,并存储到变量中:
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
CMAKE_CURRENT_SOURCE_DIR
宏表示当前访问的CMakeLists.txt
文件所在的路径。
关于要搜索的文件路径和类型可加双引号,也可不加:
file(GLOB MAIN_HEAD "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
2.5 🍎包含头文件🍎
在编译项目源文件的时候,很多时候都需要将源文件对应的头文件路径指定出来,这样才能保证在编译过程中编译器能够找到这些头文件,并顺利通过编译。在CMake中设置要包含的目录也很简单,通过一个命令就可以搞定了,他就是include_directories
:
include_directories(headpath)
举例说明,有源文件若干,其目录结构如下:
├── build
├── CMakeLists.txt
├── include
│ └── head.h
└── src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
3 directories, 7 files
CMakeLists.txt文件内容如下:
cmake_minimum_required(VERSION 3.0)
project(CALC)
set(CMAKE_CXX_STANDARD 11)
set(HOME /home/robin/Linux/calc)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin/)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(app ${SRC_LIST})
其中,第六行指定就是头文件的路径,PROJECT_SOURCE_DIR
宏对应的值就是我们在使用cmake
命令时,后面紧跟的目录,一般是工程的根目录。
2.6 🍎制作动态库或静态库🍎
有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些静态库或动态库提供给第三方使用,下面来讲解在cmake中生成这两类库文件的方法。
忘记动态库/静态库的小伙伴可以看看博主之前讲解的文章:
2.6.1 🍋静态库🍋
在cmake中,如果要制作静态库,需要使用的命令如下:
add_library(库名称 STATIC 源文件1 [源文件2] ...)
在Linux中,静态库名字分为三部分:lib+库名字+.a
,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。在Windows中虽然库名和Linux格式不同,但也只需指定出名字即可。
下面有一个目录:
需要将src目录中的源文件编译成静态库,然后再使用,CMakeLists.txt文件内容如下:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
然后我们再cmake和make:
此时就生成了静态库。
2.6.2 🍋动态库🍋
在cmake中,如果要制作动态库,需要使用的命令如下:
add_library(库名称 SHARED 源文件1 [源文件2] ...)
在Linux中,动态库名字分为三部分:lib+库名字+.so
,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。在Windows中虽然库名和Linux格式不同,但也只需指定出名字即可。
根据上面的目录结构,可以这样编写CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc SHARED ${SRC_LIST})
然后我们再cmake和make:
此时就生成了动态库。
2.6.3 🍋指定输出的路径🍋
方式1 - 适用于动态库
对于生成的库文件来说和可执行程序一样都可以指定输出路径。由于在Linux下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式去指定它生成的目录:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(calc SHARED ${SRC_LIST})
对于这种方式来说,其实就是通过set
命令给EXECUTABLE_OUTPUT_PATH
宏设置了一个路径,这个路径就是可执行文件生成的路径。(注意如果设置的路径不存在的话会先创建)
方式2 - 静态库/动态库都适用
由于在Linux下生成的静态库默认不具有可执行权限,所以在指定静态库生成的路径的时候就不能使用EXECUTABLE_OUTPUT_PATH
宏了,而应该使用LIBRARY_OUTPUT_PATH
,这个宏对应静态库文件和动态库文件都适用。
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库/静态库生成路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 生成动态库
#add_library(calc SHARED ${SRC_LIST})
# 生成静态库
add_library(calc STATIC ${SRC_LIST})
2.7 🍎包含库文件🍎
在编写程序的过程中,可能会用到一些系统提供的动态库或者自己制作出的动态库或者静态库文件,cmake
中也为我们提供了相关的加载动态库的命令。
2.7.1 🍋链接静态库🍋
在cmake中,链接静态库的命令如下:
link_libraries(<static lib> [<static lib>...])
- 参数1:指定出要链接的静态库的名字,可以是全名 libxxx.a,也可以是掐头(lib)去尾(.a)之后的名字 xxx;
- 参数2:
-N
要链接的其它静态库的名字。
如果该静态库不是系统提供的(自己制作或者使用第三方提供的静态库)可能出现静态库找不到的情况,此时可以使用link_directories
将静态库的路径也指定出来:
link_directories(<lib path>)
示例:
# 包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
2.7.2 🍋链接动态库🍋
程序编写过程中,除了在项目中引入静态库,好多时候也会使用一些标准的或者第三方提供的一些动态库,关于动态库的制作、使用以及在内存中的加载方式和静态库都是不同的。
在cmake中链接动态库的命令如下:
target_link_libraries(
<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
target
:指定要加载动态库的文件的名字。
该文件可能是一个源文件;
该文件可能是一个动态库文件;
该文件可能是一个可执行文件。PRIVATE|PUBLIC|INTERFACE
:动态库的访问权限,默认为PUBLIC。
如果各个动态库之间没有依赖关系,无需做任何设置,三者没有没有区别,一般无需指定,使用默认的PUBLIC
即可。
动态库的链接具有传递性,如果动态库 A 链接了动态库B、C,动态库D链接了动态库A,此时动态库D相当于也链接了动态库B、C,并可以使用动态库B、C中定义的方法。
target_link_libraries(A B C)
target_link_libraries(D A)
PUBLIC
:在public后面的库会被Link到前面的target中,并且里面的符号也会被导出,提供给第三方使用。PRIVATE
:在private后面的库仅被link到前面的target中,并且终结掉,第三方不能感知你调了啥库。INTERFACE
:在interface后面引入的库不会被链接到前面的target中,只会导出符号。
链接系统动态库
动态库的链接和静态库是完全不同的:
- 静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
- 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存。
因此,在cmake中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后:
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)
在target_link_libraries(app pthread)
中:
app
: 对应的是最终生成的可执行程序的名字pthread
:这是可执行程序要加载的动态库,这个库是系统提供的线程库,全名为libpthread.so
,在指定的时候一般会掐头(lib
)去尾(.so
)。
链接第三方动态库
使用方式其本质跟链接系统动态库差不多,需要特别注意的是使用第三方动态库系统会找不到你库文件在哪里,所以需要你使用link_directories
来指定要链接的动态库的路径。
2.8 🍎日志🍎
在CMake中可以用用户显示一条消息,该命令的名字为message
。
message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
- (无) :重要消息
- STATUS :非重要消息
- WARNING:CMake 警告, 会继续执行
- AUTHOR_WARNING:CMake 警告 (dev), 会继续执行
- SEND_ERROR:CMake 错误, 继续执行,但是会跳过生成的步骤
- FATAL_ERROR:CMake 错误, 终止所有处理过程
CMake的命令行工具会在stdout上显示STATUS消息,在stderr上显示其他所有消息。CMake的GUI会在它的log区域显示所有消息。CMake警告和错误消息的文本显示使用的是一种简单的标记语言。文本没有缩进,超过长度的行会回卷,段落之间以新行做为分隔符。
# 输出一般日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 输出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 输出错误信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")
2.9 🍎变量操作🍎
2.9.1 🍋追加🍋
有时候项目中的源文件并不一定都在同一个目录中,但是这些源文件最终却需要一起进行编译来生成最终的可执行文件或者库文件。如果我们通过file
命令对各个目录下的源文件进行搜索,最后还需要做一个字符串拼接的操作,关于字符串拼接可以使用set
命令也可以使用list
命令。
使用set拼接
如果使用set
进行字符串拼接,对应的命令格式如下:
set(变量名1 ${变量名1} ${变量名2} ...)
关于上面的命令其实就是将从第二个参数开始往后所有的字符串进行拼接,最后将结果存储到第一个参数中,如果第一个参数中原来有数据会对原数据就行覆盖。
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
set(SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")
使用list拼接
如果使用list
进行字符串拼接,对应的命令格式如下:
list(APPEND <list> [<element> ...])
list
命令的功能比set
要强大,字符串拼接只是它的其中一个功能,所以需要在它第一个参数的位置指定出我们要做的操作,APPEND
表示进行数据追加,后边的参数和set就一样了。
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
list(APPEND SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")
在CMake中,使用set
命令可以创建一个list
。一个在list内部是一个由分号;分割的一组字符串。例如,set(var a b c d e)命令将会创建一个list:a;b;c;d;e,但是最终打印变量值的时候得到的是abcde。
set(tmp1 a;b;c;d;e)
set(tmp2 a b c d e)
message(${tmp1})
message(${tmp2})
输出的结果:
abcde
abcde
2.9.2 🍋字符串移除🍋
我们在通过file搜索某个目录就得到了该目录下所有的源文件,但是其中有些源文件并不是我们所需要的,比如下面这种目录结构:
├── add.cpp
├── main.cpp
└── sub.cpp
在当前这么目录有3个源文件,其中main.cpp是一个测试文件。如果我们想要把计算器相关的源文件生成一个动态库给别人使用,那么只需要add.cpp、sub.cpp这2个源文件就可以了。此时,就需要将main.cpp从搜索到的数据中剔除出去,想要实现这个功能,也可以使用list
。
list(REMOVE_ITEM <list> <value> [<value> ...])
通过上面的命令原型可以看到删除和追加数据类似,只不过是第一个参数变成了REMOVE_ITEM
。
示例:
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/*.cpp)
# 移除前日志
message(STATUS "message: ${SRC_1}")
# 移除 main.cpp
list(REMOVE_ITEM SRC_1 ${PROJECT_SOURCE_DIR}/main.cpp)
# 移除后日志
message(STATUS "message: ${SRC_1}")
可以看到,在第8行把将要移除的文件的名字指定给list就可以了。但是一定要注意通过 file
命令搜索源文件的时候得到的是文件的绝对路径(在list中每个文件对应的路径都是一个item,并且都是绝对路径),那么在移除的时候也要将该文件的绝对路径指定出来才可以,否是移除操作不会成功。
这里再列举一下list的一些其他功能:
- 获取
list
的长度。
list(LENGTH <list> <output variable>)
LENGTH
:子命令LENGTH用于读取列表长度list
:当前操作的列表output variable
:新创建的变量,用于存储列表的长度
- 读取列表中指定索引的的元素,可以指定多个索引。
list(GET <list> <element index> [<element index> ...] <output variable>)
list
:当前操作的列表element index
:列表元素的索引- 从0开始编号,索引0的元素为列表中的第一个元素;索引也可以是负数,-1表示列表的最后一个元素,-2表示列表倒数第二个元素,以此类推 当索引(不管是正还是负)超过列表的长度,运行会报错
output variable
:新创建的变量,存储指定索引元素的返回结果,也是一个列表。
- 将列表中的元素用连接符(字符串)连接起来组成一个字符串。
list (JOIN <list> <glue> <output variable>)
list
:当前操作的列表glue
:指定的连接符(字符串)output variable
:新创建的变量,存储返回的字符串
- 查找列表是否存在指定的元素,若果未找到,返回-1。
list(FIND <list> <value> <output variable>)
list
:当前操作的列表value
:需要再列表中搜索的元素output variable
:新创建的变量
如果列表list中存在value,那么返回value在列表中的索引,如果未找到则返回-1。
- 在list中指定的位置插入若干元素。
list(INSERT <list> <element_index> <element> [<element> ...])
- 将元素插入到列表的0索引位置。
list (PREPEND <list> [<element> ...])
- 将列表中最后元素移除。
list (POP_BACK <list> [<out-var>...])
- 将列表中第一个元素移除。
list (POP_FRONT <list> [<out-var>...])
- 将指定的元素从列表中移除。
list (REMOVE_ITEM <list> <value> [<value> ...])
- 将指定索引的元素从列表中移除。
list (REMOVE_AT <list> <index> [<index> ...])
- 移除列表中的重复元素。
list (REMOVE_DUPLICATES <list>)
- 列表翻转
list(REVERSE <list>)
2.10 🍎预定义宏🍎
下面的列表中为大家整理了一些CMake中常用的宏:
宏 | 功能 |
---|---|
PROJECT_SOURCE_DIR | 使用cmake命令后紧跟的目录,一般是工程的根目录 |
PROJECT_BINARY_DIR | 执行cmake命令的目录 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的CMakeLists.txt所在的路径 |
CMAKE_CURRENT_BINARY_DIR | target 编译目录 |
EXECUTABLE_OUTPUT_PATH | 重新定义目标二进制可执行文件的存放位置 |
LIBRARY_OUTPUT_PATH | 重新定义目标链接库文件的存放位置 |
PROJECT_NAME | 返回通过PROJECT指令定义的项目名称 |
CMAKE_BINARY_DIR | 项目实际构建路径,假设在build目录进行的构建,那么得到的就是这个目录的路径 |