1. CMake如何确定继承关系
在 CMake 中,父子关系是通过文件系统中的目录结构来定义的。当你在一个目录中创建一个 CMakeLists.txt 文件时,该目录就被视为一个 CMake 项目的目录,而该文件中的内容将被用于配置和构建该目录中的项目。
当你在父目录的 CMakeLists.txt 文件中使用 `add_subdirectory()` 命令来包含子目录时,CMake 就会将子目录与父目录建立起父子关系。这意味着子目录中的 CMakeLists.txt 文件可以访问并继承父目录的变量、函数和设置,除非在子目录中显式地覆盖或修改了这些设置。
因此,父子关系是由项目的目录结构和 `add_subdirectory()` 命令来确定的。只有在父目录中包含了子目录,并且在子目录中包含了父目录的设置时,才能说这两个目录之间存在父子关系。
2. 继承关系
在 CMake 项目中,`find_package()` 和 `target_link_libraries()` 分别用于查找和链接外部库。通常,当你在根目录的 CMakeLists.txt 文件中使用了这些命令,并且子目录的 CMakeLists.txt 文件没有覆盖或修改这些设置时,这些设置将会被继承到子目录中。
在 CMake 中,当你在一个目录中包含另一个目录时,就会建立父子关系。这通常是通过在父目录的 CMakeLists.txt 文件中使用 `add_subdirectory()` 命令来实现的。
例如,假设有以下的目录结构:
project/
├── CMakeLists.txt (父目录)
├── subdirectory/
│ └── CMakeLists.txt (子目录)
在父目录的 CMakeLists.txt 文件中,你可以包含子目录,如下所示:
# 父目录的 CMakeLists.txt 文件
add_subdirectory(subdirectory)
这样做后,子目录中的 CMakeLists.txt 文件就能够访问和继承父目录的设置。
现在让我们考虑一个更具体的例子。假设在父目录的 CMakeLists.txt 文件中定义了一个变量 `FOO`,子目录的 CMakeLists.txt 文件也想使用这个变量。可以这样做:
# 父目录的 CMakeLists.txt 文件
set(FOO "Hello from the parent directory")add_subdirectory(subdirectory)# 子目录的 CMakeLists.txt 文件
message("In the subdirectory: ${FOO}")
在这个例子中,子目录的 CMakeLists.txt 文件能够访问并使用父目录中定义的变量 `FOO`,因为父目录通过 `add_subdirectory()` 命令包含了子目录。
因此,父目录和子目录之间的关系建立在包含关系的基础上,而不是在代码中直接指定父子关系。只要在父目录中包含了子目录,并且子目录中的 CMakeLists.txt 文件使用了父目录中定义的设置,就可以说这两个目录之间存在父子关系。
以上说明的是显示的继承关系,也包含隐式的继承关系,如果子目录的 CMakeLists.txt 文件没有使用父目录中定义的任何变量、函数或设置,并且没有任何其他方式显式地依赖于父目录,那么可以说它们之间没有显式的父子关系。
在这种情况下,尽管你可能在父目录的 CMakeLists.txt 文件中使用了 `add_subdirectory()` 命令包含了子目录,但子目录不会继承父目录的任何设置或变量,也不会被视为父目录的子项目。相反,子目录会被视为独立的项目,它们之间的联系仅限于目录结构。
这种情况下的父子关系是隐式的,因为你使用了 `add_subdirectory()` 命令包含了子目录,但子目录并没有直接依赖于父目录。
这种继承关系主要表现在项目构建过程中。当你在父目录中执行 CMake 构建时,它会递归地构建子目录,从而构建整个项目。因此,子目录会受到父目录构建过程的影响,即使子目录中的 CMakeLists.txt 文件没有显式地引用父目录的设置或变量。
这种继承关系主要影响构建过程,而不会直接影响 CMake 变量或设置的传递。如果在子目录中需要访问父目录的设置或变量,仍然需要在子目录的 CMakeLists.txt 文件中显式地引用它们。
3. 其他
在 CMake 中,`find_package()` 和 `target_link_libraries()` 命令的行为取决于它们的位置和作用域。通常情况下,子目录的 CMakeLists.txt 文件中的命令会覆盖父目录中相同名称的命令。
但是,如果在子目录的 CMakeLists.txt 文件中使用了 `PRIVATE`、`PUBLIC` 或 `INTERFACE` 关键字将目标链接到库时,它会将链接的设置限定在当前目标中,而不会影响到父目录或其他目标。这意味着,即使子目录中使用了 `target_link_libraries()` 命令,也不会影响到父目录的设置。
因此,如果子目录的 CMakeLists.txt 文件中的 `target_link_libraries()` 命令没有将目标链接到 某个库,那么父目录中的 连接到这个库的设置仍然会保持有效,并且可以在子目录中使用 这个库的头文件和链接库,而不会报错。
当在子目录的 CMakeLists.txt 文件中使用 `target_link_libraries()` 命令时,如果使用了 `PUBLIC`、`PRIVATE` 或 `INTERFACE` 关键字,它们会指定链接的属性范围。具体来说:
PUBLIC: 当使用 `PUBLIC` 关键字时,链接的设置会应用于当前目标和所有依赖该目标的目标。这意味着,这些设置会被继承到依赖目标中,同时也会保留在当前目标中。
PRIVATE: 当使用 `PRIVATE` 关键字时,链接的设置仅适用于当前目标,不会被传递到依赖目标中。
INTERFACE: 当使用 `INTERFACE` 关键字时,链接的设置不会应用于当前目标,而是仅应用于依赖目标。这意味着,这些设置会被传递到依赖目标中,但不会影响当前目标。
因此,如果在子目录的 CMakeLists.txt 文件中使用了 `target_link_libraries()` 命令,并且使用了 `PUBLIC` 关键字,那么链接的设置会同时继承父目录的设置,并保留在当前目标中。这样既可以继承父目录的设置,又可以在子目录中保留自己的设置,不会覆盖父目录的设置。