变量也是 cmake 中的一个重头戏,cmake 提供了很多内置变量,每一个变量都有它自己的含义,通过这个链接地址cmake-variables(7) — CMake 3.5.2 Documentation可以查询到所有的内置变量及其相应的介绍,如下所示:
在这一份文档中,对变量进行分类,分为:提供信息的变量、改变行为的变量、描述系统的变量、控制编译的变量等等,笔者也按照这个分类给大家介绍一些基本、常用的变量。
顾名思义,这种变量可以提供某种信息,既然如此,那么我们通常只需要读取变量即可,而不需要对变量进行修改:
变量 | 说明 |
PROJECT_SOURCE_DIR | 工程顶层目录,也就是顶层 CMakeLists.txt 源码所在目录 |
PROJECT_BINARY_DIR | 工程 BINARY_DIR , 也就是顶层 CMakeLists.txt 源码的 BINARY_DIR |
CMAKE_SOURCE_DIR | 与 PROJECT_SOURCE_DIR 等价 |
CMAKE_BINARY_DIR | 与 PROJECT_BINARY_DIR 等价 |
CMAKE_CURRENT_SOURCE_DIR | 当前源码所在路径 |
CMAKE_CURRENT_BINARY_DIR | 当前源码的 BINARY_DIR |
CMAKE_MAJOR_VERSION | cmake 的主版本号 |
CMAKE_MINOR_VERSION | cmake 的次版本号 |
CMAKE_VERSION | cmake 的版本号(主+次+修订) |
PROJECT_VERSION_MAJOR | 工程的主版本号 |
PROJECT_VERSION_MINOR | 工程的次版本号 |
PROJECT_VERSION | 工程的版本号 |
CMAKE_PROJECT_NAME | 工程的名字 |
PROJECT_NAME | 工程名,与 CMAKE_PROJECT_NAME 等价 |
PROJECT_SOURCE_DIR 和 PROJECT_BINARY_DIR
PROJECT_SOURCE_DIR 变量表示工程的顶级目录,也就是顶层 CMakeLists.txt 文件所在目录; PROJECT_BINARY_DIR 变量表示工程的BINARY_DIR ,也就是顶层 CMakeLists.txt 源码对应的 BINARY_DIR(输出文件目录)。 譬如工程目录结构如下所示:
├── build
├── CMakeLists.txt
└── main.c
CMakeLists.txt 文件内容如下:
# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO)
message(${PROJECT_SOURCE_DIR})
message(${PROJECT_BINARY_DIR})
CMakeLists.txt 中我们打印了 PROJECT_SOURCE_DIR 和 PROJECT_BINARY_DIR 变量,进入到 build 目录下,执行 cmake:
从打印信息可知,PROJECT_SOURCE_DIR 指的就是工程的顶层 CMakeLists.txt 源码所在路径,而 PROJECT_BINARY_DIR 指的是我们执行 cmake 命令的所在目录,也是顶层 CMakeLists.txt 源码的 BINARY_DIR。
同上
指的是当前源码的路径以及当前源码的 BINARY_DIR,通过示例来看看,譬如工程目录结构如下所示:
├── build
├── CMakeLists.txt
├── main.c
└── src
└── CMakeLists.txt
顶层 CMakeLists.txt 文件通过 add_subdirectory 加载子目录 src 下的 CMakeLists.txt,src 目录下 CMakeLists.txt 文件内容如下所示:
# src 下的 CMakeLists.txt
message(${PROJECT_SOURCE_DIR})
message(${PROJECT_BINARY_DIR})
message(${CMAKE_CURRENT_SOURCE_DIR})
message(${CMAKE_CURRENT_BINARY_DIR})
通过 message 将这些变量打印出来,对比看看,进入到 build 目录下,执行 cmake:
记录 cmake 的版本号,如下
# CMakeLists.txt
message(${CMAKE_VERSION})
message(${CMAKE_MAJOR_VERSION})
message(${CMAKE_MINOR_VERSION})
打印信息如下:
记录工程的版本号,其实可以给工程设置一个版本号,通过 project()命令进行设置,如下:
# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0) #设置工程版本号为 1.1.0
# 打印
message(${PROJECT_VERSION})
message(${PROJECT_VERSION_MAJOR})
message(${PROJECT_VERSION_MINOR})
打印信息如下:
两者等价,记录工程的名字:
# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0) #设置工程版本号为 1.1.0
# 打印工程名字
message(${CMAKE_PROJECT_NAME})
message(${PROJECT_NAME})
打印信息如下:
顾名思义,意味着这些变量可以改变某些行为,所以我们可以通过对这些变量进行设置以改变行为。
变量 | 说明 |
BUILD_SHARED_LIBS | 控制 cmake 是否生成动态库 |
CMAKE_BUILD_TYPE | 指定工程的构建类型,release 或 debug |
CMAKE_SYSROOT | 对应编译器的在--sysroot 选项 |
CMAKE_IGNORE_PATH | 设置被 find_xxx 命令忽略的目录列表 |
CMAKE_INCLUDE_PATH | 为find_file()和 find_path()命令指定搜索路径的目录列表 |
CMAKE_INCLUDE_DIRECTORIES_BEFORE | 用于控制 include_directories()命令的行为 |
CMAKE_LIBRARY_PATH | 指定 find_library()命令的搜索路径的目录列表 |
CMAKE_MODULE_PATH | 指定要由 include()或 find_package()命令加载的 CMake 模块的搜索路径的目录列表 |
CMAKE_PROGRAM_PATH | 指定 find_program()命令的搜索路径的目录列表 |
对于 add_library()命令,当没有显式指定生成动态库时(SHARED 选项),默认生成的是静态库;其实 们可以通过 BUILD_SHARED_LIBS 变量来控制 add_library()命令的行为,当将变量设置为 on 时表示使能动态库,则 add_library()默认生成的便是动态库文件;当变量设置为 off 或未设置时,add_library()默认生成的便是静态库文件。测试如下:
譬如工程目录结构如下所示:
├── build
├── CMakeLists.txt
├── hello
│ └── hello.c
└── world
└── world.c
顶层 CMakeLists.txt 文件如下所示:
# 顶层 CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0)
set(BUILD_SHARED_LIBS on)
add_library(hello hello/hello.c)
add_library(world world/world.c)
进入到 build 目录下,执行 cmake、make 进行构建、编译,将会生成动态库文件 libhello.so、libworld.so。
设置编译类型 Debug 或者 Release。debug 版会生成相关调试信息,可以使用 GDB 进行调试;release 不会生成调试信息:
# Debug 版本
set(CMAKE_BUILD_TYPE Debug)
# Release 版本
set(CMAKE_BUILD_TYPE Release)
cmake 会将该变量传递给编译器--sysroot 选项,通常在设置交叉编译时会使用到。
为 find_file()和 find_path()命令指定搜索路径的目录列表。它们分别用于查找文件、路径,我们需要传入一个文件名,find_file()命令会将该文件的全路径返回给我们;而 find_path() 命令则会将文件的所在目录返回给我们。
这两个命令去哪找文件呢?也就是通过CMAKE_INCLUDE_PATH 变量来进行指定 , CMAKE_INCLUDE_PATH 指定了一个目录列表,find_file()、find_path()会去这个目录列表中查找文件。接下来我们进行测试。
譬如工程目录结构如下所示:
├── build
├── CMakeLists.txt
└── src
└── 1.c
顶层 CMakeLists.txt 文件内容如下:
# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0) #设置工程版本号为 1.1.0
find_file(P_VAR 1.c)
message(${P_VAR})
通过 find_file 命令查找 1.c 文件,将路径信息记录在 P_VAR 变量中;现在我们没有设置 CMAKE_INCLUDE_PATH 变量,看看能不能找到 1.c 文件,cmake 打印信息如下:
很明显提示没有找到,现在我们对 CMAKE_INCLUDE_PATH 变量进行设置,如下所示:
# CMakeLists.txt
cmake_minimum_required("VERSION" "3.5")
project(HELLO VERSION 1.1.0) #设置工程版本号为 1.1.0
# 设置 CMAKE_INCLUDE_PATH 变量
set(CMAKE_INCLUDE_PATH ${PROJECT_SOURCE_DIR}/src)
# 查找文件
find_file(P_VAR 1.c)
message(${P_VAR})
此时打印信息为:
这次就成功找到了 hello.c 文件,并将文件的全路径返回给我们。
指定 find_library()命令的搜索路径的目录列表。find_library()命令用于搜索库文件,find_library()将会从 CMAKE_LIBRARY_PATH 变量设置的目录列表中进行搜索。
指定要由 include()或 find_package()命令加载的 CMake 模块的搜索路径的目录列表。
这个变量在前面给大家提到过,它可以改变 include_directories()命令的行为。include_directories()命令默认情况下会将目录添加到列表的后面,如果将 CMAKE_INCLUDE_DIRECTORIES_BEFORE 设置为 on,则 include_directories()命令会将目录添加到列表前面;同理若将 CMAKE_INCLUDE_DIRECTORIES_BEFORE 设置为 off 或未设置该变量,include_directories()会将目录添加到列表后面。
被 find_program()、find_library()、find_file()和 find_path()命令忽略的目录列表。表示这些命令不会去 CMAKE_IGNORE_PATH 变量指定的目录列表中搜索。
未完待续......