我们很高兴地宣布,Conan 2.0 的最新版本中已实现了一些长期需求的功能,但由于 Conan 1.X 的遗留问题和限制,这些功能几乎无法实现。Conan 2.0 的一大优势是其新的架构和设计允许维护人员快速构建和发布像这三个新功能一样的功能。

  • 使用 [plaform_requires] 功能,可以在依赖项图中完全删除任何 Conan 配方中定义的 requires,并使用系统安装的依赖项。此功能在不同场景下非常有用,例如避免配方获取 cmake Conan 包,因为它们是 tool_requires = "cmake/version",并且使用系统安装的依赖项,而无需修改任何配方。
  • 使用 [replace_requires] 功能,可以通过任何其他依赖项(只要它与 API 兼容)替换依赖项图中任何配方 requires 依赖项。此功能可用于替换常规 requires 以获得系统包装器等效项,或替换 API 兼容包,例如将 zlib 替换为 zlib-ng 或将 libjpeg 替换为 libjpeg-turbo,而无需修改任何配方。
  • 使用新的 conan graph explain 命令,可以详细解释何时缺少二进制文件,将缺少的二进制文件的设置、选项和依赖项与缓存和远程仓库中现有的二进制文件进行比较,并显示类似差异的结果。

此外,前两个功能能够应用于常规 requirestool_requires。让我们详细了解一下这些新功能。

用系统依赖项替换 Conan 依赖项

Conan 配方可以在其代码中包含 requirestool_requires,例如,我们将使用一个典型的 tool_requires 引用 Conan cmake 包,版本至少为 3.25,因为 mypkg 中的 CMakeLists.txt 需要一些现代 CMake 功能。

from conan import ConanFile

class Pkg(ConanFile):
    name =   "mypkg"
    tool_requires = "cmake/[>=3.25]"

现在,无论何时从源代码构建 mypkg,它都会下载一个 cmake/xxx Conan 包,将其注入并使用它进行构建。这在过去发生过,无论用户在其系统中安装了哪个 CMake。使用此新功能,用户可以在其配置文件中定义

[platform_tool_requires]
cmake/3.26

定义他们在系统中安装的版本。使用此配置文件,现在 mypkg 将不再从服务器下载 cmake 包,而是使用系统安装的版本。唯一的条件是系统安装的版本必须可用于构建,在这种 CMake 情况下,它应该位于系统 PATH(或在 tools.cmake:cmake_program 配置中定义的位置)。

平台要求系统能够检查版本。例如,如果某个配方具有 tool_requires = "cmake/[>=3.27]",那么它将知道系统安装的 CMake 不足,它仍然会下载一个满足约束的 cmake 包,并将其用于该包,使用系统安装的 CMake 用于所有其他对系统 3.26 版本感到满意的包。

通过 [platform_requires] 功能,为常规 requires 提供相同的功能。这可能是删除像 requires = "openssl/3.1" 这样的 Conan 依赖项的情况,该依赖项需要一个 Conan 包,而是使用系统安装的 openssl。例如,当交叉构建到某些嵌入式目标时,这可能很方便,这些目标将在系统中提供自己的特定 openssl(例如在构建期间的 sysroot 中),这些目标必须使用。请注意,系统 openssl 必须可用于消费者,以便消费者能够完全透明地链接它,因为 Conan 将不再向消费者注入有关它的任何信息。在许多情况下,无法实现这种透明使用,因为消费者仍然需要一些额外的信息来定位和使用这些系统安装的依赖项。在这种情况下,以下 [replace_requires] 将是推荐的方法

用 [replace_requires] 替换 API 兼容要求

在某些情况下,更改依赖项图中定义的 requires 可能非常方便。

例如,如果我们项目中的所有配方都需要 requires = "zlib/1.3",然后我们想引入使用 zlib-ng 替代方案的能力,则有两种不同的方法:只需在所有地方替换要求并始终使用 zlib-ng(如果我们可以删除 zlib),或者基于输入 optionsconf 实现条件要求。第一种方法在像 ConanCenter 这样的地方可能无法实现,第二种方法可能很繁琐且容易出错。

使用此新功能,可以通过在配置文件中定义来实现

[replace_requires]
zlib/*: zlib-ng/*

这将替换每个 requires = "zlib/<anyversion>" 以获得相同的要求,相当于 requires = "zlib-ng/<anyversion>",使用与声明版本相同的版本。

但有时,版本之间没有一对一映射,对于这些情况,也可以明确声明映射

[replace_requires]
zlib/1.0: zlib-ng/11.0
zlib/2.0: zlib-ng/12.0

同样,也可以使用版本范围进行替换

[replace_requires]
zlib/3.0: zlib-ng/[>=13.0]

在这种情况下,对 zlib/3.0 的精确匹配将被该特定范围内 zlib-ng 中的匹配项替换。但其他版本的 zlib/xxx 不会被替换。可以在第一个模式中也定义版本范围

[replace_requires]
zlib/[>=3.0]: zlib-ng/[>=13.0]

在这种情况下,如果原始范围 zlib/[>=3.0] 通过配方 requires 得到满足,则将进行替换,无论是范围内的精确版本,还是如果配方也声明了版本范围,只要范围之间存在一些重叠。

此功能还有一些其他有趣的用例:例如,它可以用于**临时**解决冲突,而无需修改任何 conanfile。请注意,这不是永久冲突解决策略,但它在开发和测试事物时可能很有用。

最后,对于上述情况,必须从系统中使用 openssl(可能它位于 sysroot 中),但它需要一些额外信息以便于其他包使用。在这样的情况下,用户可以

  • 首先编写一个替代的 openssl/<version>@system,它不构建任何内容,但主要在其 package_info() 中定义信息,以便其他包能够定位和使用它。

  • 然后定义包含以下内容的配置文件

    [replace_requires]
    openssl/*: openssl/*@system
    

使用该配置文件,requires = "openssl/version" 的出现将被 requires = "openssl/version@system" 替换,它将使用之前提供的包装器配方,其中包含有关该 sysroot 中该依赖项的详细信息。

The [replace_requires] 对常规 requires 有效。还有一个 [replace_tool_requires] 用于相同目的,但用于 tool_requires,具有相同的规则和行为。

在构建和主机配置文件中使用 [platform_requires] 和 [replace_requires]

由于 [platform_requires][platform_tool_requires][replace_requires][replace_tool_requires] 在配置文件中定义,因此可以在“主机”和“构建”配置文件中定义它们。

这意味着可以控制在哪个上下文中执行这些替换。例如,使用 [replace_requires] 替换 sysroot 中 openssl 的交叉构建场景,如果由于某种原因构建上下文碰巧需要 openssl 作为传递依赖项,则构建上下文不想使用 sysroot 中的 openssl。因此,[replace_requires] 应该只发生在“主机”配置文件中,而不是在“构建”配置文件中。

另一方面,上述使用 [platform_tool_requires] 的 CMake 示例适用于两种情况。即使我们是否正在交叉构建,"主机"(常规库和应用程序)上下文中的包将使用系统安装的 CMake。但是,如果“构建”上下文中的任何依赖项,作为 tool_requires 使用的任何应用程序都需要从源代码构建,它可能需要 CMake 本身作为传递 tool_requires,并且它可以使用系统安装的 CMake 如果可能。对于这种情况,我们希望在“主机”和“构建”配置文件中都定义相同的 [platform_tool_requires]

图的额外功能:了解为什么某些二进制文件使用“conan graph explain”丢失

Conan 1.X 中常见的难题之一是安装应该作为预编译二进制文件存在的 Conan 包,然后遇到“缺少二进制文件”错误。该错误看起来像这样

$ conan install --requires=zlib/1.3 -s build_type=Debug

conan missing binary

即使此错误消息提供了一些有关缺少二进制文件的信息,但为什么缺少该二进制文件并不明显。现在,正如错误消息所建议的那样,我们有 conan graph explain。基本上键入相同的 conan install 命令,但现在使用 graph explain 以获得类似以下内容的结果

$ conan graph explain --requires=zlib/1.3 -s build_type=Debug

conan graph explain

这清楚地解释并用颜色突出显示了此二进制文件丢失的原因。在本例中,这是因为 ConanCenter 没有为该编译器版本构建调试二进制文件,并且只有发布二进制文件可用。

The conan graph explain command 旨在解释导致二进制文件丢失的所有可能差异,从设置、选项、依赖项版本、配置等方面的差异。

结论

Conan 2 中的新增内容提供了一些非常强大的功能,这些功能允许在依赖项解析中实现更大的灵活性,并实现了一些长期需求,例如能够替换 API 兼容要求或使用系统安装的工具而不是配方声明的工具。

请查看文档以了解 replace_requiresplatform_requiresconan graph explain。我们期待您对这些功能的反馈,请随时分享您的想法,报告任何错误或在 GitHub 问题中提出任何疑问。