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 将失败并出现错误,而不是假定它是系统提供的库的名称。
我不太了解别名表达式的应用。 我明白我可以写这样的东西
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 totarget_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 policyCMP0028
).
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 将失败并出现错误,而不是假定它是系统提供的库的名称。