制作 target_link_library 接口依赖项

我是新的 CMake 和有点困惑与公共,私人和接口关键字相关的 target_link_libraries()。文档中提到,它们可以用于在一个命令中指定链接依赖项和链接接口。

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

40864 次浏览

如果您正在创建一个共享库,并且您的源 cpp文件 #include是另一个库的头文件(例如,QtNetwork) ,但是您的头文件不包括 QtNetwork头文件,那么 QtNetworkPRIVATE依赖项。

如果源文件和头包含另一个库的头,那么它是 PUBLIC依赖项。

如果源文件以外的头文件包含另一个库的头文件,那么它是 INTERFACE依赖项。

PUBLICINTERFACE依赖项的其他构建属性传播到使用库

@ steveire 接受的答案很棒,我只是想添加一个表格来快速看看其中的区别:

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

有些答案只说什么时候使用 PRIVATE/PUBLIC/INTERFACE,但是忽略了这些影响

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

二等兵
PRIVATE 后面的所有对象将仅用于链接到当前目标。

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

这不是我的主意,但这个 非常有用的解释帮助我了解了情况。最重要的部分引述如下作为参考:

  • 当 A 将 B 链接为 二等兵时,表示 A 在其实现中使用 B,但是在 A 的公共 API 的任何部分中都不使用 B。任何 调用 A 的代码不需要直接引用 这方面的一个例子可以是网络库 A 它可以构建为使用众多不同的 SSL 之一 图书馆内部(B 代表)。 A 代表一个统一的 客户端代码的接口,该接口不引用任何 内部 SSL 数据结构或函数 不知道 A 正在使用什么 SSL 实现(B) ,也不知道
    客户端代码需要关心的事情。
  • 当 A 将 B 链接为 接口时,表示 A 在其实现中不使用 B,而是在 A 的公共 API 中使用 B。密码 调用到 A 的语句可能需要引用来自 B 的事物,以便 这方面的一个例子是一个接口库 只是将调用转发到另一个库,但实际上 通过指针或其他方式引用对象 另一个例子是在 CMake 中将 A 定义为 接口库,这意味着它本身没有实际的实现, 它实际上只是一个其他图书馆的集合 这里可能过于简单化了,但是你已经知道了)。
  • 当 A 链接 B 为 公众时,它实质上是一个私有和接口的组合。它说 A 在它的实现中使用 B B 也用于 A 的公共 API。

首先考虑这对于包含搜索路径意味着什么 对 A 的链接,它也将需要任何包括搜索路径从 B 如果 在 A 的公共 API 中。因此,如果 A 将 B 链接为 PUBLIC 或 INTERFACE,则为目标 B 定义的任何头搜索路径也将 适用于任何链接到 A 的任何私人头部搜索路径 B 不会被带到任何只链接到 A 的地方 Target _ include _ directory ()命令可以处理这个问题 编译标志类似地使用 target _ edit _ Definition ()进行处理 和 target _ edit _ options ()。

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

如果你仔细观察,就会发现 A 链接 B 作为私人,B 的包含目录从不传播 但是如果 A 是一个静态库,那么 B 的链接 的行为就好像这个关系是 PUBLIC 的 链接 ,而不是其他依赖项(编译器选项/标志和包含搜索路径)。所有这一切的结果是,如果您选择 基于点中解释的私人、公共或界面 然后 CMake 将确保依赖项传播到 不管库是静态的还是 当然,这依赖于开发人员没有丢失的您 任何依赖项或指定错误的 PRIVATE/PUBLIC/INTERFACE 关系。

其他帖子已经回答了 PUBLIC/PRIVATE/INTERFACE 关键字的含义。我想再添加一个来澄清术语“链接依赖”和“链接接口”

  • 链接相关性: 要由目标链接的库列表。 目标属性 LINK _ LIBRARIES 保存此信息。
  • 链接接口: 由目标的依赖项链接的库列表。目标属性 INTERFACE _ LINK _ LIBRARIES 保存此信息。

“链接接口”这个术语可能来自于在 LINK _ INTERFACE _ LIBRARIES 属性周围使用的旧的 CMake 措辞,它已经被推荐使用 INTERFACE _ LINK _ LIBRARIES 属性。 请参阅 CMP0022的说明,它也使用术语“链接接口” Https://cmake.org/cmake/help/latest/policy/cmp0022.html

INTERFACE _ LINK _ LIBRARIES 定义链接接口。