build_requirements()

build_requirements() 方法在功能上等同于 requirements() 方法,它在后者之后执行。 理论上,它不是绝对必要的,在这个方法内部的所有事情都可以在 requirements() 方法的末尾完成。 尽管如此,build_requirements() 仍然非常适合拥有一个专门的地方来定义 tool_requirestest_requires

def build_requirements(self):
   self.tool_requires("cmake/3.23.5")
   self.test_requires("gtest/1.13.0")

对于简单的情况,属性语法可能就足够了,例如 tool_requires = "cmake/3.23.5"test_requires = "gtest/1.13.0"。 对于有条件或参数化的需求,方法形式可能是必要的。

tool_requirestest_requires 方法只是 requires 的专门实例,具有一些预定义的特性值。 有关特性的更多信息,请参阅 requires() 参考

有 2 个 实验性 confs 可以用来避免扩展这些类型的需求

  • tools.graph:skip_build 允许完全跳过 tool_requires 依赖项。 如果满足两个条件,则可以这样做:需要这些工具的软件包不需要从源代码构建,并且工具需求不影响使用者的 package_id。 如果发生这种情况,Conan 将引发错误。

  • tools.graph:skip_test 允许完全跳过 test_requires 依赖项。 如果跳过这些依赖项,但随后某些软件包需要从源代码构建,并且 tools.build:skip_test 未激活,则将无法找到 test_requires。 因此,在大多数情况下,也应定义 tools.build:skip_test

请注意,如果工具和/或测试需求被跳过,它们将不会成为依赖关系图的一部分,也不会成为可能生成的锁定文件或软件包列表的一部分,这可能会对未来的可重现性产生影响。 此外,在大多数情况下,Conan 能够将工具和测试需求标记为不必要(Skip),从而避免下载庞大的二进制文件,只需下载通常非常快速的 recipe 即可。 这意味着在大多数情况下,这些 confs 不是必需的,Conan 默认值很好,请在了解权衡的情况下使用它们。

tool_requires()

tool_requires 等同于具有以下特性的 requires()

  • build=True。 此依赖项位于“build”上下文中,在构建时是必需的,但在应用程序运行时不是必需的,并将接收“build”配置文件和配置。

  • visible=False。 工具需求的依赖关系不会向下游传播。 例如,一个软件包可以调用 tool_requires("cmake/3.23.5"),但这并不意味着消费者软件包也使用 cmake,他们甚至可以使用不同的构建系统或不同的版本,而不会引起冲突。

  • run=True。 此依赖项具有一些需要在构建时运行的可执行文件或运行时。

  • headers=False 工具需求没有头文件。

  • libs=False: 工具需求没有要由消费者链接的库(如果它有库,它们将在“build”上下文中,并且可能与消费者软件包的“host”上下文不兼容)。

请记住,tool_requires 专门用于依赖像 cmakeninja 这样的工具,这些工具在“build”上下文中运行,但不适用于将链接到二进制文件中的类似库的依赖项。 对于库或类似库的依赖项,请使用 requirestest_requires

<host_version>

警告

此功能是实验性的,可能会发生重大更改。 有关更多信息,请参阅 Conan 稳定性 部分。

当您将相同的软件包 recipe 用作 requirestool_requires,并且您希望避免下游冲突(如果任何用户决定在 host 上下文中覆盖原始 requires 版本)时,此语法很有用,即,用户最终可能会在同一依赖项的 host 和 build 上下文中获得两个不同的版本。

简而言之,<host_version> 说明符允许我们确保为 tool_requires 解析的版本始终与 host 需求的版本匹配。

例如,让我们展示一个使用 protobuf 的简单 recipe

from conan import ConanFile

class mylibRecipe(ConanFile):
    name = "mylib"
    version = "0.1"
    def requirements(self):
        self.requires("protobuf/3.18.1")
    def build_requirements(self):
        self.tool_requires("protobuf/<host_version>")

然后,如果任何用户想要使用 mylib/0.1,但使用另一个版本的 protobuf,则不应有任何问题覆盖它

from conan import ConanFile

class myappRecipe(ConanFile):
    name = "myapp"
    version = "0.1"
    def requirements(self):
        self.requires("mylib/0.1")
        self.requires("protobuf/3.21.9", override=True)

上游定义的 <host_version> 确保 host 和 build 上下文使用相同版本的该需求。

此外,语法 <host_version:mylib> 可用于指定要跟踪的软件包的名称,如果 requirestool_requires 具有不同的名称。 例如

from conan import ConanFile

class mylibRecipe(ConanFile):
    name = "mylib"
    version = "0.1"
    def requirements(self):
        self.requires("gettext/2.31")
    def build_requirements(self):
        self.tool_requires("libgettext/<host_version:gettext>")

test_requires

test_requires 等同于具有以下特性的 requires()

  • test=True。 此依赖项是“test”依赖项,存在于“host”上下文中,但不旨在成为最终产品的一部分。

  • visible=False。 测试需求的依赖关系不会向下游传播。 例如,一个软件包可以调用 self.test_requires("gtest/1.13.0"),但这并不意味着消费者软件包也使用 gtest,他们甚至可以使用不同的测试框架,或者使用相同但版本不同的 gtest,而不会引起冲突。

如有必要,可以进一步修改 tool_requires()test_requires() 的各个特性,例如

def build_requirements(self):
   self.tool_requires("cmake/3.23.5", options={"shared": False})

如果存在具有冲突版本的传递性测试需求,则 test_requires() 允许使用 force=True 特性,同样,tool_requires() 支持 override=True 特性,用于覆盖直接工具需求的可能的传递性依赖关系。

注意

最佳实践

  • tool_requires 专门用于构建时工具,而不是将包含并链接到消费者软件包中的库。 对于具有某些特殊特性的库,请使用具有自定义特性值的 requires()

  • self.test_requires()self.tool_requires() 方法应专门在 build_requirements() 方法中使用,唯一的例外是 requirements() 方法。 禁止在任何其他方法中使用它们。 要在某些方法中访问有关依赖项的信息(如有必要),应使用 self.dependencies 属性。