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 导出之前检查其内容。基本上,pre_export() 函数检查 conanfile 对象的属性,查看是否存在 URL、license 和 description,如果缺少,则通过 conanfile.output 向用户发出警告。这是在 recipe 导出到本地缓存之前完成的。

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

从模块导入

hook 接口应始终放置在以 hook_ 开头并以 .py 扩展名的 Python 文件中。它也应该存储在 <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_modulecustom.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_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 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:它是一个常规的 ConanFile 对象,从接收到 Conan 命令的 recipe 中加载。它具有其正常的属性和动态对象,例如 build_folderpackage_folderoutputdependenciesoptions

存储、激活和共享

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

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

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

官方 Hooks

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