取决于相同工具-require的不同版本¶
注意
这是一个高级用例。在绝大多数情况下,这并非必要。
通常情况下,尝试执行类似操作
def build_requirements(self):
self.tool_requires("gcc/1.0")
self.tool_requires("gcc/2.0")
将会产生一个“冲突”,显示类似 重复 依赖 的错误。在大多数情况下,这是正确的,因为显然不可能使用 2 个版本的相同编译器来构建当前包。
然而,在某些特殊情况下,可能需要这样做。让我们重现潜在的场景。请先克隆源代码以重现此项目。你可以在 GitHub 上的 examples2 仓库 中找到它们
git clone https://github.com/conan-io/examples2.git
cd examples2/examples/graph/tool_requires/different_versions
在那里,我们有一个假的 gcc 配方,其中
class Pkg(ConanFile):
name = "gcc"
def package(self):
echo = f"@echo off\necho MYGCC={self.version}!!"
save(self, os.path.join(self.package_folder, "bin", f"mygcc{self.version}.bat"), echo)
save(self, os.path.join(self.package_folder, "bin", f"mygcc{self.version}.sh"), echo)
os.chmod(os.path.join(self.package_folder, "bin", f"mygcc{self.version}.sh"), 0o777)
这不是一个实际的编译器,它通过 shell 或 bat 脚本模拟它,该脚本在执行时会打印 MYGCC=current-version。请注意,二进制文件本身名为 mygcc1.0 和 mygcc2.0,也就是说,它在可执行文件名本身中包含版本。
我们可以为 gcc/1.0 和 gcc/2.0 创建 2 个不同的版本,如下所示
$ conan create gcc --version=1.0
$ conan create gcc --version=2.0
现在,在 wine 文件夹中,有一个 conanfile.py 如下所示
class Pkg(ConanFile):
name = "wine"
version = "1.0"
def build_requirements(self):
# If we specify "run=False" they no longer conflict
self.tool_requires("gcc/1.0", run=False)
self.tool_requires("gcc/2.0", run=False)
def generate(self):
# It is possible to individually reference each one
gcc1 = self.dependencies.build["gcc/1.0"]
assert gcc1.ref.version == "1.0"
gcc2 = self.dependencies.build["gcc/2.0"]
assert gcc2.ref.version == "2.0"
def build(self):
ext = "bat" if platform.system() == "Windows" else "sh"
self.run(f"mygcc1.0.{ext}")
self.run(f"mygcc2.0.{ext}")
第一点很重要是 build_requirements() 方法,它对两个版本都执行 tool_requires(),但定义了 run=False。这非常重要:我们告诉 Conan 我们实际上不需要运行这些包中的任何内容。由于 tool_requires 不可见,它们不会定义头文件或库,因此没有任何内容使 Conan 将这两个 tool_requires 识别为冲突。因此,依赖图可以在没有错误的情况下构建,并且 wine/1.0 包将包含两个 tool_requires 到 gcc/1.0 和 gcc/2.0。
当然,并非我们不会运行这些 tool_requires 中的任何内容,但现在 Conan 不知道这一点,并且完全由用户负责管理它。
警告
使用 run=False 使 tool_requires() 完全不可见,这意味着配置文件 [tool_requires] 将无法覆盖其版本,但它会创建一个带有从配置文件注入的版本的新工具-require 依赖项。你可能需要使用类似 !wine/*: gcc/3.0 的内容排除特定的包。
该配方仍然可以在 generate() 方法中访问每个不同的 tool_require 版本,只需提供完整的引用,例如 self.dependencies.build["gcc/1.0"]。
最后,最重要的一点是,这些工具的使用完全由用户负责。由于默认情况下 VirtualBuildEnv 生成器会更新 PATH 环境变量,因此这两个 tool_requires 的 bin 文件夹包含可执行文件,将在路径中。在这种情况下,可执行文件不同,例如 mygcc1.0.sh 和 mygcc2.0.sh,因此没有问题,每个可执行文件都将位于其包内。
但是,如果可执行文件完全相同,例如 gcc.exe,那么有必要在 generate() 方法中获取完整的文件夹,例如使用 self.dependencies.build["gcc/1.0"].cpp_info.bindir,并使用完整路径进行区分。
让我们看看它是否有效。如果我们执行
$ conan create wine
...
wine/1.0: RUN: mygcc1.0.bat
MYGCC=1.0!!
wine/1.0: RUN: mygcc2.0.bat
MYGCC=2.0!!