Hooks

Conan hooks 是一项旨在扩展 Conan 功能的功能,用于在软件包创建过程的不同阶段(例如构建前和构建后)执行某些正交操作,例如某些质量检查。

Hook 结构

Hook 是一个 Python 函数,它将在 Conan 工作流的特定点执行,以自定义客户端行为,而无需修改客户端源或 recipe 源。

这是一个简单的 hook 示例

hook_example.py
 from conan.tools.files import load

 def pre_export(conanfile):
     for field in ["url", "license", "description"]:
         field_value = getattr(conanfile, field, None)
         if not field_value:
             conanfile.output.error(f"[REQUIRED ATTRIBUTES] Conanfile doesn't have '{field}'.
                                       It is recommended to add it as attribute.")

此 hook 在导出 recipe 之前检查 recipe 内容。 基本上,pre_export() 函数检查 conanfile 对象的属性,以查看是否存在 URL、许可证和描述,如果缺少,则通过 conanfile.output 向用户发出消息警告。 这是在将 recipe 导出到本地缓存之前完成的。

可以执行任何类型的 Python 脚本。 您可以创建全局函数并从不同的 hook 函数调用它们,从相对模块导入并警告、报错甚至引发异常以中止 Conan 客户端的执行。

从模块导入

hook 接口应始终放置在 Python 文件中,该文件的名称以 hook_ 开头,并以 .py 结尾。 它也应该存储在 <conan_home>/extensions/hooks 文件夹中。 但是,如果您的系统上安装了它们,或者如果它们是使用 Conan 安装的,则可以使用从导入模块的功能。

hook_example.py
 import requests
 from conan.tools.files import replace_in_file

 def post_package(conanfile):
     if not os.path.isdir(os.path.join(conanfile.package_folder, "licenses")):
         response = requests.get('https://api.github.com/repos/company/repository/contents/LICENSE')

您还可以从相对模块导入功能

hooks
├── custom_module
│   ├── custom.py
│   └── __init__.py
└── hook_printer.py

在我的 custom_module 中的 custom.py 中有

custom.py
 def my_printer(conanfile):
     conanfile.output.info("my_printer(): CUSTOM MODULE")

并且可以在 hook 中使用导入模块,就像常规 Python 一样

hook_printer.py
 from custom_module.custom import my_printer

 def pre_export(conanfile):
     my_printer(conanfile)

Hook 接口

在这里,您可以看到所有可用 hook 函数的完整示例

hook_full.py
 def pre_export(conanfile):
     conanfile.output.info("Running before to execute export() method.")

 def post_export(conanfile):
     conanfile.output.info("Running after of executing export() method.")

 def pre_validate(conanfile):
     conanfile.output.info("Running before executing the validate() method.")

 def post_validate(conanfile):
     conanfile.output.info("Running after executing the validate() method.")

 def pre_source(conanfile):
     conanfile.output.info("Running before to execute source() method.")

 def post_source(conanfile):
     conanfile.output.info("Running after of executing source() method.")

 def pre_generate(conanfile):
     conanfile.output.info("Running before to execute generate() method.")

 def post_generate(conanfile):
     conanfile.output.info("Running after of executing generate() method.")

 def pre_build(conanfile):
     conanfile.output.info("Running before to execute build() method.")

 def post_build(conanfile):
     conanfile.output.info("Running after of executing build() method.")

 def post_build_fail(conanfile):
     conanfile.output.info("Running after failed execution of build() method.")

 def pre_package(conanfile):
     conanfile.output.info("Running before to execute package() method.")

 def post_package(conanfile):
     conanfile.output.info("Running after of executing package() method.")

 def pre_package_info(conanfile):
     conanfile.output.info("Running before to execute package_info() method.")

 def post_package_info(conanfile):
     conanfile.output.info("Running after of executing package_info() method.")

hook 函数旨在对其执行进行自我描述。 例如,pre_package() 函数在执行 recipe 的 package() 方法之前被调用。

所有 hook 方法都仅用相同的单个对象填充

  • conanfile: 它是从接收到 Conan 命令的 recipe 加载的常规 ConanFile 对象。 它具有其常规属性和动态对象,例如 build_folderpackage_folderoutputdependenciesoptions

存储、激活和共享

Hooks 是存储在 <conan_home>/extensions/hooks 文件夹下的 Python 文件,它们的文件名应以 hook_ 开头,并以 .py 扩展名结尾

一旦 hook 文件存储在 hook 文件夹中,hooks 的激活就会自动完成。 如果存储在子文件夹中,它也会自动工作。

要停用 hook,应将其文件从 hook 文件夹中删除。 没有可以停用但将文件存储在 hooks 文件夹中的配置。

官方 Hooks

Conan hooks GitHub 的自己的存储库中存在一些官方维护的 hooks,但大多数仅与 Conan 1.x 兼容,所以请首先检查 README 以获取有关哪些 hooks 与 Conan v2 兼容的信息。