自定义 Conan 生成器

如果需要使用 Conan 默认情况下不支持的构建系统或工具,可以使用自定义生成器创建自己的集成。这可以通过三种不同的方式完成。

作为 python_requires 的自定义生成器

在 Conan 中使用自定义生成器的一种方法是将其作为 python_requires 使用。您可以声明一个 MyGenerator 类,其中包含在 mygenerator/1.0 python_requires 包中生成某些文件的所有逻辑

mygenerator/conanfile.py
from conan import ConanFile
from conan.tools.files import save


class MyGenerator:
    def __init__(self, conanfile):
        self._conanfile = conanfile

    def generate(self):
        deps_info = ""
        for dep, _ in self._conanfile.dependencies.items():
            deps_info += f"{dep.ref.name}, {dep.ref.version}\n"
        save(self._conanfile, "deps.txt", deps_info)


class PyReq(ConanFile):
    name = "mygenerator"
    version = "1.0"
    package_type = "python-require"

然后 conan create mygenerator 并像这样在您自己的包的 generate 方法中使用它

pkg/conanfile.py
from conan import ConanFile


class MyPkg(ConanFile):
    name = "pkg"
    version = "1.0"

    python_requires = "mygenerator/1.0"
    requires = "zlib/1.3.1", "bzip2/1.0.8"

    def generate(self):
        mygenerator = self.python_requires["mygenerator"].module.MyGenerator(self)
        mygenerator.generate()

然后,对这个 pkg 配方执行 conan install pkg,将创建一个 deps.txt 文本文件,其中包含

zlib, 1.2.11
bzip2, 1.0.8

这种方法的好处是可以将您自己的自定义生成器作为包进行版本控制,并且可以作为 Conan 包共享这些生成器。

使用全局自定义生成器

如果您将它们存储在 [CONAN_HOME]/extensions/generators 文件夹中,也可以全局使用您的自定义生成器。您可以将它们直接放在该文件夹中,也可以使用 conan config install 命令进行安装。

[CONAN_HOME]/extensions/generators/mygen.py
from conan.tools.files import save


class MyGenerator:
    def __init__(self, conanfile):
        self._conanfile = conanfile

    def generate(self):
        deps_info = ""
        for dep, _ in self._conanfile.dependencies.items():
            deps_info = f"{dep.ref.name}, {dep.ref.version}"
        save(self._conanfile, "deps.txt", deps_info)

然后您可以使用名称在配方中使用它们,或使用 -g 参数在命令行中使用它们

conan install --requires=zlib/1.2.13 -g MyGenerator

来自 tool_requires 的生成器

警告

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

直接依赖的工具要求也可以用来提供自定义生成器。以下示例展示了如何创建一个自定义生成器,该生成器生成一个包含包依赖项的文件,就像上面的示例一样,但使用 tool_require 而不是 python_require 将生成器注入到配方中,通过将它们添加到 self.generator_info 属性中,在 package_info 方法中。请注意,该属性默认情况下为 None,因此您需要显式地将其设置为生成器列表。

mygenerator/conanfile.py
from conan import ConanFile
from conan.tools.files import save

class MyGenerator:
    def __init__(self, conanfile):
        self._conanfile = conanfile

    def generate(self):
        deps_info = ""
        for dep, _ in self._conanfile.dependencies.items():
            deps_info = f"{dep.ref.name}, {dep.ref.version}"
        save(self._conanfile, "deps.txt", deps_info)

class MyToolReq(ConanFile):
    name = "mygenerator-tool"
    version = "1.0"

    def package_info(self):
        self.generator_info = [MyGenerator]

然后,在您的配方中使用 mygenerator-tool 包的 tool_requires 将自动将生成器注入到配方中。

注意

请注意,也可以使用 tool_requires 注入内置生成器,方法是通过名称添加它们:self.generator_info = ["CMakeDeps"]tool_require 此包会将 CMakeDeps 生成器注入到配方中,就像在它的 generators 属性中声明一样。