CMake target_link_libraries接口依赖项

时间:2014-09-25 11:52:09

标签: cmake

我是CMAKE的新手,对与target_link_libraries相关的PUBLIC,PRIVATE和INTERFACE关键字感到困惑。文档提到它们可用于在一个命令中指定链接依赖关系和链接接口。

链接依赖关系和链接接口实际意味着什么?

4 个答案:

答案 0 :(得分:115)

如果要创建共享库和源cpp文件#include另一个库的头(例如,Say,QtNetwork),但是您的头文件不包含QtNetwork头,那么QtNetwork是PRIVATE依赖性。

如果源文件和标题包含其他库的标题,则它是PUBLIC依赖项。

如果您的头文件而不是您的源文件包含另一个库的标头,那么它是INTERFACE依赖项。

PUBLICINTERFACE依赖项的其他构建属性会传播到使用库。 http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#transitive-usage-requirements

答案 1 :(得分:3)

@steveire接受的答案很好。我只想添加一个表以快速查看区别:

.-----------.------------------.----------------.
|           | Linked by target | Link interface |
:-----------+------------------+----------------:
| PUBLIC    |        X         |        X       |
:-----------+------------------+----------------:
| PRIVATE   |        X         |                |
:-----------+------------------+----------------:
| INTERFACE |                  |        X       |
'-----------'------------------'----------------'
  • 按目标链接:目标源中包含的库(不是链接库的项目的依赖项)。
  • 链接界面:目标公共标头中包含的库(链接库的项目的依赖性)。

答案 2 :(得分:0)

某些回答仅说何时使用PRIVATE / PUBLIC / INTERFACE,但是影响被忽略。请参考:CMake-Public-Private-Interface

公共
紧随PUBLIC之后的所有对象都将用于链接到当前目标,并提供与依赖于当前目标的其他目标的接口。

PRIVATE
PRIVATE之后的所有对象将仅用于链接到当前目标。

界面
INTERFACE之后的所有对象将仅用于提供与当前目标有依赖关系的其他目标的接口。

答案 3 :(得分:0)

不是我的心血结晶,但这 extremely useful explanation 帮助我了解了情况。下面引用最重要的部分以供参考:

<块引用>
  • 当 A 在 B 中链接为 PRIVATE 时,表示 A 在其实现中使用了 B,但 B 未在 A 的公共 API 的任何部分中使用。任何 调用 A 的代码不需要直接引用 来自 B 的任何东西。这方面的一个例子可能是网络库 A 可以构建为使用多种不同的 SSL 之一 内部库(B 代表)。 A 呈现统一 客户端代码的接口,不引用任何 内部 SSL 数据结构或函数。客户端代码将有 不知道 A 正在使用什么 SSL 实现 (B),也不知道
    客户端代码需要关心。
  • 当 A 在 B 中作为 INTERFACE 链接时,表示 A 在其实现中没有使用 B,但 B 在 A 的公共 API 中使用。代码 调用 A 可能需要引用来自 B 的事物,以便 打这样的电话。一个例子是一个接口库,它 只是将调用转发到另一个库,但实际上并没有 通过指针以外的方式引用对象或 参考。另一个例子是 A 在 CMake 中定义为 接口库,这意味着它本身没有实际的实现, 它实际上只是其他库的集合(我是 这里可能过于简化了,但你明白了)。
  • 当 A 在 B 中链接为 PUBLIC 时,它本质上是 PRIVATE 和 INTERFACE 的组合。它说 A 在其实现中使用 B 并且 B 也用于 A 的公共 API。

首先考虑这对包含搜索路径意味着什么。如果有事 针对 A 的链接,它还需要来自 B 的任何包含搜索路径,如果 B 在 A 的公共 API 中。因此,如果 A 在 B 中链接为 PUBLIC 或 INTERFACE,则为目标 B 定义的任何标头搜索路径也将 适用于任何链接到 A. 的任何 PRIVATE 标头搜索路径 B 不会被带到任何只链接到 A 的东西。 target_include_directories() 命令处理这个。情况与 编译标志类似地用 target_compile_definitions() 处理 和 target_compile_options()。

现在考虑所涉及的实际库的情况。如果 A 是 一个共享库,那么 A 将在其中编码对 B 的依赖。 可以使用 Linux 上的 ldd、otool 等工具检查此信息 在 Mac 上,还有类似 Dependency Walker(又名depends.exe)的东西 视窗。如果其他代码直接链接到 A,那么它也会有 将其编码为对 A 的依赖。然而,它不会有 依赖于 B,除非 A 将 B 中的链接作为 PUBLIC 或 INTERFACE。到目前为止,所以 好的。但是,如果 A 是静态库,情况就会改变。 静态库不携带有关它们的其他库的信息 取决于。出于这个原因,当 A 在 B 中作为 PRIVATE 链接而另一个 目标 C 链接在 A 中,CMake 仍会将 B 添加到库列表中 为 C 链接,因为 A 需要 B 的一部分,但 A 本身 没有编码到其中的依赖项。所以即使 B 是一个 A、C 的内部实现细节仍然需要将 B 添加到 链接器命令,CMake 方便地为您处理。

如果你仔细观察,你会注意到当 B 中的 A 链接为 PRIVATE,B 的包含目录永远不会传播 到链接到 A 的东西,但如果 A 是一个静态库,那么 B 的链接表现得好像关系是公开的。静态库的这种 PRIVATE-becomes-PUBLIC 行为仅适用于 这 链接,而不是其他依赖项(编译器选项/标志和包含搜索路径)。所有这一切的结果是,如果您选择 PRIVATE、PUBLIC 或 INTERFACE 基于点中的解释 以上几点,然后 CMake 将确保依赖项传播到 需要它们的地方,无论库是静态的还是 共享。当然,这确实取决于您,开发人员不会错过 任何依赖项或指定错误的 PRIVATE/PUBLIC/INTERFACE 关系。