build_requirements()¶
build_requirements()
方法在功能上等同于 requirements()
方法,并且在其之后执行。它并非严格必需,理论上该方法中的所有内容都可以放在 requirements()
方法的末尾。尽管如此,build_requirements()
对于提供一个专门用于定义 tool_requires
和 test_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_requires
和 test_requires
方法只是 requires
的特化实例,并带有一些预定义的 trait 值。有关 trait 的更多信息,请参阅 requires() 参考。
有两个实验性的 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
。
请注意,如果工具和/或测试需求被跳过,它们将不会成为依赖图的一部分,也不会成为任何生成的 lockfile 或包列表的一部分,这可能会影响未来的可重现性。此外,在大多数情况下,Conan 能够将工具和测试需求标记为不必要(Skip
),从而避免下载大型二进制文件,而仅下载通常非常快的 recipe。这意味着在大多数情况下,这些 confs
是不必要的,Conan 的默认设置是好的,请在使用时注意权衡。
tool_requires()¶
tool_requires
等同于 requires()
,并具有以下 trait:
build=True
。此依赖项位于“build”上下文中,在构建时必需,但在应用程序运行时不必需,并且将接收“build” profile 和配置。visible=False
。对 tool requirement 的依赖不会向下传播。例如,一个包可以调用tool_requires("cmake/3.23.5")
,但这并不意味着消费包也使用cmake
,它们甚至可以使用不同的构建系统或不同的版本,而不会引起冲突。run=True
。此依赖项包含一些需要在构建时运行的可执行文件或运行时。headers=False
。tool requirement 没有头文件。libs=False
:tool requirement 没有供消费者链接的库(如果它有库,它们将位于“build”上下文中,并且可能与消费包的“host”上下文不兼容)。
请记住,tool_requires
仅用于 cmake
或 ninja
等工具,这些工具在“build”上下文中运行,而不是用于将链接到二进制文件中的类似库的依赖项。对于库或类似库的依赖项,请使用 requires
或 test_requires
。
<host_version>¶
警告
此功能是实验性的,可能会发生重大更改。有关更多信息,请参阅 Conan 稳定性 部分。
当您使用相同的包 recipe 作为 requires 和 tool_requires,并且想要避免下游冲突(如果任何用户决定在 host 上下文中覆盖原始 requires 版本)时,此语法非常有用。也就是说,用户最终可能会在同一依赖项的 host 和 build 上下文中获得两个不同的版本。
简而言之,<host_version>
指定符允许我们确保为 tool_requires 解析的版本始终与 host requirement 的版本匹配。
例如,让我们展示一个使用 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>
来指定要跟踪的包的名称,以防 requires 和 tool_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()
,并具有以下 trait:
test=True
。此依赖项是“test”依赖项,存在于“host”上下文中,但不是最终产品的一部分。visible=False
。对 test requirement 的依赖不会向下传播。例如,一个包可以调用self.test_requires("gtest/1.13.0")
,但这并不意味着消费包也使用gtest
,它们甚至可以使用不同的测试框架,或者相同的gtest
但不同的版本,而不会引起冲突。
警告
由于 test_requires
定义了一个 visible=False
trait,因此必须小心避免在具有正常 requirement 的情况下,与在 test_requires
中使用的相同包存在传递依赖项。这是因为具有直接 visible=False
requirement 的情况,如果传递依赖项对当前 recipe 作为测试依赖项请求的同一包具有 visible=True
requirement,则可能会导致冲突。在不同可见性规则到达同一包的情况下,将使用可见的传递依赖项并将其向下传播。
如有必要,可以进一步修改 tool_requires()
和 test_requires()
的单个 trait,例如:
def build_requirements(self):
self.tool_requires("cmake/3.23.5", options={"shared": False})
test_requires()
允许 force=True
trait,以防出现版本冲突的传递测试依赖项,同样,tool_requires()
支持 override=True
trait,用于覆盖直接工具需求可能存在的传递依赖项。
注意
最佳实践
tool_requires
仅用于构建时工具,而不是用于包含和链接到消费包中的库。对于具有某些特殊特征的库,请使用具有自定义 trait 值的requires()
。self.test_requires()
和self.tool_requires()
方法应仅在build_requirements()
方法中使用,唯一可能的例外是requirements()
方法。禁止在任何其他方法中使用它们。要访问方法中必要时关于依赖项的信息,应使用self.dependencies
属性。