依赖具有不同选项的相同版本的工具需求¶
注意
这是一个高级用例。 在绝大多数情况下,没有必要这样做。
通常,尝试执行以下操作
def build_requirements(self):
self.tool_requires("gcc/1.0")
self.tool_requires("gcc/1.0")
将生成“冲突”,显示类似 Duplicated requirement
的错误。
但是,在某些特殊情况下,我们可能需要依赖相同的 tool_requires
版本,但使用该 tool_requires
的不同二进制文件。 这可以通过将不同的 options
传递给那些 tool_requires
来实现。 请首先克隆源代码以重新创建此项目。 你可以在 GitHub 上的 examples2 存储库中找到它们
git clone https://github.com/conan-io/examples2.git
cd examples2/examples/graph/tool_requires/different_options
在那里,我们有一个带有的 gcc
伪配方
class Pkg(ConanFile):
name = "gcc"
version = "1.0"
options = {"myoption": [1, 2]}
def package(self):
# This fake compiler will print something different based on the option
echo = f"@echo off\necho MYGCC={self.options.myoption}!!"
save(self, os.path.join(self.package_folder, "bin", f"mygcc{self.options.myoption}.bat"), echo)
save(self, os.path.join(self.package_folder, "bin", f"mygcc{self.options.myoption}.sh"), echo)
os.chmod(os.path.join(self.package_folder, "bin", f"mygcc{self.options.myoption}.sh"), 0o777)
这不是一个真正的编译器,它使用 shell 或 bat 脚本来伪造它,在执行时打印 MYGCC=current-option
。 请注意,二进制文件本身称为 mygcc1
和 mygcc2
,也就是说,它在可执行文件名本身中包含该选项。
我们可以使用以下命令为 gcc/1.0
创建 2 个不同的二进制文件
$ conan create gcc -o myoption=1
$ conan create gcc -o myoption=2
现在,在 wine
文件夹中有一个 conanfile.py
像这样
class Pkg(ConanFile):
name = "wine"
version = "1.0"
def build_requirements(self):
self.tool_requires("gcc/1.0", run=False, options={"myoption": 1})
self.tool_requires("gcc/1.0", run=False, options={"myoption": 2})
def generate(self):
gcc1 = self.dependencies.build.get("gcc", options={"myoption": 1})
assert gcc1.options.myoption == "1"
gcc2 = self.dependencies.build.get("gcc", options={"myoption": 2})
assert gcc2.options.myoption == "2"
def build(self):
ext = "bat" if platform.system() == "Windows" else "sh"
self.run(f"mygcc1.{ext}")
self.run(f"mygcc2.{ext}")
第一个要点是 build_requirements()
方法,该方法对两个二进制文件执行 tool_requires()
,但定义了 run=False
和 options={"myoption": value}
特征。 这非常重要:我们告诉 Conan 我们实际上不需要运行来自这些软件包的任何东西。 由于 tool_requires
不可见,因此它们不定义标头或库,并且它们定义不同的 options
,因此没有任何东西可以使 Conan 将这两个 tool_requires
识别为冲突。 因此,可以构造依赖关系图而不会出错,并且 wine/1.0
软件包将包含到 gcc/1.0
的 2 个不同的工具需求,其中 myoption=1
和 myoption=2
。
当然,我们不会运行来自这些 tool_requires
的任何东西是不正确的,但是现在 Conan 没有意识到这一点,并且完全由用户负责管理它。
警告
使用 run=False
会使 tool_requires()
完全不可见,这意味着 profile [tool_requires]
将无法覆盖其版本,但它会创建一个额外的工具需求依赖项,其中包含从 profile 注入的版本。 你可能想排除特定的软件包,例如 !wine/*: gcc/3.0
。
该配方仍然可以在 generate()
方法中访问每个不同的 tool_require
版本,只需为我们想要的依赖项提供选项值即可 self.dependencies.build.get("gcc", options={"myoption": 1})
。
最后,最重要的是这些工具的使用完全由用户负责。 包含可执行文件的两个 tool_requires
的 bin
文件夹将位于路径中,这要归功于默认情况下更新 PATH 环境变量的 VirtualBuildEnv
生成器。 在这种情况下,可执行文件是不同的,例如 mygcc1.sh```and ``mygcc2.sh
,因此这不是问题,并且每个都将在其软件包中找到。
但是,如果可执行文件完全相同,例如 gcc.exe
,那么有必要获得完整的文件夹(通常在 generate()
方法中),例如 self.dependencies.build.get("gcc", options={"myoption": 1}).cpp_info.bindir
并使用完整路径来消除歧义。
让我们看看它的工作原理。 如果我们执行
$ conan create wine
...
wine/1.0: RUN: mygcc1.bat
MYGCC=1!!
wine/1.0: RUN: mygcc2.bat
MYGCC=2!!