build_requirements()¶
build_requirements()
方法在功能上与 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() 参考。
有 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()
,并带有以下 traits:
build=True
。此依赖项位于“build”上下文中,在构建时是必需的,但在应用程序运行时不是必需的,并且将接收“build” profile 和配置。visible=False
。对工具依赖的依赖项不会向下传播。例如,一个包可以调用tool_requires("cmake/3.23.5")
,但这并不意味着消费者包也使用cmake
,它们甚至可以使用不同的构建系统或不同的版本,而不会引起冲突。run=True
。此依赖项包含一些需要在构建时运行的可执行文件或运行时。headers=False
。工具依赖项没有头文件。libs=False
:工具依赖项没有供消费者链接的库(如果它有库,它们将位于“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 需求的版本匹配。
例如,我们用一个简单的 recipe 展示如何使用 *protobuf*。
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()
,并带有以下 traits:
test=True
。此依赖项是“test”依赖项,存在于“host”上下文中,但不是最终产品的一部分。visible=False
。对测试依赖项的依赖项不会向下传播。例如,一个包可以调用self.test_requires("gtest/1.13.0")
,但这并不意味着消费者包也使用gtest
,它们甚至可以使用不同的测试框架,或者相同版本gtest
的不同版本,而不会引起冲突。
警告
由于 test_requires
定义了 visible=False
trait,因此必须小心,避免与正常需求出现同名包的传递依赖,这些同名包也被用在 test_requires
中。这是因为具有直接 visible=False
需求可能会产生冲突,如果传递依赖项对当前 recipe 作为测试依赖项要求的同一个包具有 visible=True
需求。在这些规则不同可见性到达同一个包的情况下,将使用可见的传递依赖项并将其向下传播。
如果需要,可以进一步修改 tool_requires()
和 test_requires()
的各个 traits,例如:
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 属性。