cmake 别名的用处

cmake usefulness of aliases

我不太了解别名表达式的应用。 我明白我可以写这样的东西

cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
project(myLibs)
add_library(${PROJECT_NAME} src/test.cpp)
add_library(myLibs::myLibs ALIAS ${PROJECT_NAME})
...

然后使用

  target_link_libraries(${TARGET_NAME}
  myLibs::myLibs

在另一个文件中 link 库到一些可执行文件等

但我为什么要那样做?我不妨跳过别名定义,直接使用构建库的目标名称

target_link_libraries(${TARGET_NAME}
myLibs

以您的 add_library() 为例,CMake 目标的名称将例如直接链接到目标的输出文件名。

因此 ALIAS 目标主要用于为目标提供更拼写或结构化的名称,例如添加一个 "namespace".

cmake-developer documentation 给出了以下关于命名空间的建议:

When providing imported targets, these should be namespaced (hence the Foo:: prefix); CMake will recognize that values passed to target_link_libraries() that contain :: in their name are supposed to be imported targets (rather than just library names), and will produce appropriate diagnostic messages if that target does not exist (see policy CMP0028).

TLDR:它为其他项目提供了更大的灵活性。

对我来说,添加 ALIAS 的主要动机与 installing/packaging 以及其他项目如何使用您的项目有关。安装项目时,可以导出其目标。 install() 命令的两种相关形式是:

install(TARGETS target... EXPORT exportName ...)
install(EXPORT exportName ... NAMESPACE myNS:: ...)

首先是安装您的实际目标(即二进制文件),但它还包括 EXPORT 关键字。这告诉 CMake 这个目标安装是 exportName 导出集的一部分。上面的第二个命令然后为 exportName 导出集安装一个文件,该文件包含为集合中的每个目标创建导入目标的 CMake 代码。它将 myNS:: 添加到该集合中的所有目标(这是您的问题的关键点)。这个导出的文件将包含在您项目的配置包文件中(这是一个相当复杂的主题,您可以获取更多详细信息 here)。然后其他项目可以通过首先执行 find_package() 来针对您安装的项目进行构建,这将重新创建所有导出的目标,除了它们现在都将以 myNS:: 为前缀。然后它链接到这些命名空间目标,就好像它们是它自己构建的一部分一样。我跳过了一些细节,但这些是与您的问题最相关的要点。

现在,消费项目可能不想使用 find_package(),而是可能希望使用 add_subdirectory() 将您的项目直接引入其构建。这将是一种从源代码而不是针对预构建二进制包构建项目的方法。自从在 CMake 3.11 中添加 FetchContent module 以来,它正成为一种更受欢迎的方法。如果您的项目提供的 ALIAS 目标的名称与导出的目标名称相匹配,则使用项目无需更改其任何 target_link_libraries() 命令。无论它是针对预构建的二进制包构建还是通过 add_subdirectory() 引入您的项目,它都会链接到命名空间目标名称(即您问题中的 myLibs::myLibs),在任何一种情况下都可以正常工作。

至于 :: 的作用,当包含 :: 的名称出现在 target_link_libraries() 命令中时,它只会被解释为 CMake 目标(假设策略 CMP0028 是设置为 NEW,它现在应该总是这样)。如果不存在这样的目标,CMake 将失败并出现错误,而不是假定它是系统提供的库的名称。