一、概述

CMake官网中对于include指令的介绍,如下:

翻译:从文件或模块加载并运行CMake代码。

CMake中的include 指令用于将其他CMake文件或模块包含到当前文件中,并且在当前作用域有效。这条指令会读取所包含文件中的代码,并立即执行这些命令,就好像它们直接写在 include 命令所在的位置一样。

CMake中的include指令一般用于语句的复用,也就是说,如果有一些语句需要在很多CMakeLists.txt文件中使用,为避免重复编写,可以将其写在.cmake文件中,然后在需要的CMakeLists.txt文件中进行include操作就行了。

CMake 的 include 指令默认是在全局作用域中包含文件,这意味着被包含文件中的任何变量、函数、宏或CMake指令在所有后续的 CMake 文件中都是可见的。如果你在一个文件中使用 include(other_file.cmake),而 other_file.cmake 中定义的变量、函数或宏,之后的任何地方都可以访问。如果两个文件都有同名变量,后被包含的文件中的变量将覆盖前一个文件中的变量,这可能导致意外的行为。

include作用域根据它们的定义位置和设置方式而有所不同。 理解include作用域的特性有助于避免变量冲突及管理 CMake 文件或模块的复杂性。这些特性是 CMake 强大的模块化和可组合性设计的基础,使得大型项目能够更好地管理和组织代码并避免代码重复。

二、指令详解

【1】基本语法

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
                      [NO_POLICY_SCOPE])

【2】参数含义

  • file: 指定一个CMake文件路径,通常情况下是以 .cmake 为后缀的文件。file 表示要包含的文件的路径,路径可以是相对路径或绝对路径。如果文件名不包含路径分隔符,CMake 会首先在当前目录查找指定的文件,如果没有找到,它还会根据 CMAKE_MODULE_PATH 和系统默认路径继续查找。
    -关于CMAKE_MODULE_PATH 看本文下面详解

  • module: 指定一个CMake模块的名称,CMake会在模块目录中查找该模块。如果指定的是一个模块(module)而不是一个文件,查找的对象会变成路径CMAKE_MODULE_PATH下的文件<modulename>.camke。如果在 CMAKE_MODULE_PATH 中找不到,CMake 会在默认的系统模块路径中继续查找。
    -关于CMAKE_MODULE_PATH 看本文下面详解

  • OPTIONAL:如果设置了这个选项,CMake在找不到指定文件或模块时不会产生错误,而是继续执行后面的指令。

  • RESULT_VARIABLE <var>:如果设置了RESULT_VARIABLE选项,那么var会被设置为被包含文件的完整路径,表示找到该文件,或者被设置为NOTFOUND,NOTFOUND表示没有找到该文件。

  • NO_POLICY_SCOPE:使用此选项时,包含的文件将不受当前作用域的政策设置影响,从而保证文件内部政策的独立性。如果你希望包含的文件能够独立于当前作用域的政策设置而运行,或者需要确保包含的文件在执行时遵循自己的逻辑和行为,使用 NO_POLICY_SCOPE 是合适的选择。
    -关于NO_POLICY_SCOPE 看本文下面详解

上面详细介绍了include指令的所有可选参数,但是一般情况下,都是直接写:

include(file|module)

【3】示例源码

目录结构
project/
├── cmake
│   └── test_cmake.cmake
├── CMakeLists.txt
└── main.c
main.c源码
#include <stdio.h>

int main() {
    printf("This is main\n");
    return 0;
}
test_cmake.cmake源码
message(STATUS "This is test_cmake.cmake")
CMakeLists.txt源码
cmake_minimum_required(VERSION 3.9.0)
project(demo)

message(STATUS "begin include")
include("cmake/test_cmake.cmake")
include("cmake/test_cmake1.cmake" OPTIONAL) #OPTIONAL 可选,文件不存在不报错
include("cmake/test_cmake1.cmake" OPTIONAL  RESULT_VARIABLE ret) # RESULT_VARIABLE 返回值,是否引用成功
message(STATUS "RESULT_VARIABLE ret= ${ret}") #NOTFOUND
include("cmake/test_cmake.cmake" OPTIONAL  RESULT_VARIABLE ret)
message(STATUS "RESULT_VARIABLE ret= ${ret}") #导入文件的绝对路径
message(STATUS "end include")

add_executable(app main.c)
编译运行

【CMake】CMake从入门到实战系列(十八)—— CMake中的include指令,提高项目的模块化和可重用性-LMLPHP

三、注意事项

循环包含:由于include指令的作用域是全局的,你需要小心避免循环包含。例如,如果文件A包含了文件B,而文件B又包含了文件A,这将导致无限递归和构建错误。

变量覆盖:被包含的文件中的变量设置可能会覆盖当前文件中的同名变量。因此,在包含其他文件之前,最好先设置或保存需要保护的变量。

路径问题:确保你正确指定了要包含的文件的路径。如果文件不存在或路径不正确,CMake将抛出一个错误。

四、源码下载地址

CMake从入门到实战系列(十八)—— CMake中的include指令

07-31 15:20