【问题标题】:Getting imported targets through `find_package`?通过`find_package`获取导入的目标?
【发布时间】:2016-03-05 15:21:42
【问题描述】:

CMake manual of Qt 5 使用 find_package 并表示:

为每个 Qt 模块创建导入的目标。应该首选导入的目标名称,而不是在 target_link_libraries 等 CMake 命令中使用 Qt5<Module>_LIBRARIES 之类的变量。

它是 Qt 特有的还是 find_package 为所有库生成导入的目标documentation of find_package in CMake 3.0 说:

找到包时,包特定的信息通过包本身记录的变量和导入目标提供。

manual for cmake-packages 说:

使用find_package 的结果要么是一组IMPORTED 目标,要么是一组对应于构建相关信息的变量。

但我没有看到另一个 FindXXX.cmake-script 文档说创建了一个导入的目标

【问题讨论】:

    标签: cmake


    【解决方案1】:

    find_package 现在是双头野兽:

    CMake 直接支持两种形式的包,Config-file PackagesFind-module Packages

    Source

    现在,这实际上意味着什么?

    查找模块包可能是您最熟悉的。他们执行一个 CMake 代码脚本(例如 this one),对 find_libraryfind_path 等函数进行大量调用,以确定库的位置。

    这种方法的最大优点是它非常通用。只要文件系统上有东西,我们就可以找到它。最大的缺点是它提供的信息通常比该事物的物理位置多。也就是说,查找模块操作的结果通常只是一堆文件系统路径。这意味着像传递依赖或多个构建配置这样的建模是相当困难的。

    如果您试图找到的东西本身是用 CMake 构建的,这将变得特别痛苦。在这种情况下,您已经在构建脚本中建模了一堆东西,现在您需要为查找脚本煞费苦心地重构它们,以便下游项目可以使用它。

    这就是配置文件包大放异彩的地方。与 find-modules 不同,运行脚本的结果不仅仅是一堆路径,而是创建了功能齐全的 CMake 目标。对于依赖项目,看起来依赖项已作为同一项目的一部分构建。

    这允许以非常方便的方式传输更多信息。明显的缺点是配置文件脚本比查找脚本复杂得多。因此,您不想自己编写它们,而是让 CMake 为您生成它们。或者更确切地说,让依赖项提供一个配置文件作为其部署的一部分,然后您可以简单地使用 find_package 调用加载该文件。这正是 Qt5 所做的。

    这也意味着,如果您自己的项目是一个库,请考虑generating a config file as part of the build process。这不是 CMake 最直接的功能,但结果非常强大。

    以下是这两种方法在 CMake 代码中的典型外观的快速比较:

    查找模块样式

    find_package(foo)
    target_link_libraries(bar ${FOO_LIBRARIES})
    target_include_directories(bar ${FOO_INCLUDE_DIR})
    # [...] potentially lots of other stuff that has to be set manually
    

    配置文件样式

    find_package(foo)
    target_link_libraries(bar foo)
    # magic!
    

    tl;dr:如果依赖项提供了配置文件包,则始终首选配置文件包。如果没有,请改用查找脚本。

    【讨论】:

    • 那么,为什么 cmake 会先查找模块并回退到配置?似乎配置模式提供了更好的信息,应该先完成。但是,如果配置模式和模块模式导入具有不同名称的目标,那就糟透了。如果您依赖 config 模式是唯一找到的模式,那么这可能会产生严重的问题,然后将一个模块添加到 cmake 中,该模块不会像您预期的那样导入目标。
    • @johnb003 这是出于历史原因,不会破坏与现有脚本的向后兼容性。您可以通过将CONFIGNO_MODULE 传递给find_package 调用来强制CMake 进入配置样式。在任何情况下,调用通常不应该是模棱两可的。在绝大多数情况下,您只能找到一种类型的脚本,因此不会发生冲突。对于有歧义的少数情况,您应该明确说明您希望find_package 在哪种模式下运行。
    • 明白,你可以强制配置模式,但这很尴尬。发生这种情况的简单示例是,如果您通过可重定位的安装路径分发一组 3rd 方包。问题是您不想开始将 3rd 方库的所有 find_package 调用破解为“CONFIG”模式,它应该可以正常工作。 CMake 文档甚至主张您应该只使用圆锥形:find_package(<package> [major[.minor]] [EXACT] [REQUIRED|QUIET])
    • 一些 Find-module 包,例如 Boost,包含多个库。配置文件包是否考虑了这一点? foo 可以像上面的 target_link_libraries(bar foo) 示例那样解析多个库吗?
    • 来自 FindBoost.cmake:Boost::<C> - Target for specific component dependency (shared or static library); <C> is lower-case。例如:Boost::filesystem.
    【解决方案2】:

    实际上find_package 的结果并没有“魔法”:这个命令只是搜索适当的FindXXX.cmake 脚本并执行它。

    如果 Find 脚本设置了XXX_LIBRARY 变量,则调用者可以使用该变量。

    如果 Find 脚本创建了导入的目标,那么调用者可以使用这些目标。

    如果 Find 脚本 既不设置 XXX_LIBRARY 变量也不创建 导入的目标......那么,脚本的使用会有所不同。

    find_package 的文档描述了 Find 脚本的通常用法。但无论如何,您都需要查阅有关具体脚本的文档(该文档通常包含在脚本本身中)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多