package_id()¶
Conan 为每种配置(包括 settings、options 和 dependencies 版本)计算一个唯一的 package_id 引用。这个 package_id() 方法允许对计算出的 package_id 进行一些自定义和更改,其总目标是放宽一些全局二进制兼容性假设。
总的来说,settings 和 options 的每个不同值都会创建一个不同的 package_id。可以通过不同的方法来放宽或扩展此规则。
给定的包配方可以在其
package_id()中决定最终的二进制文件独立于某些设置,例如,如果它是一个仅头文件库,它会使用输入设置来构建一些测试,它可能会完全清除所有配置,因此最终的package_id始终相同,与输入无关。同样,C 库可能希望从其二进制package_id中删除compiler.cppstd和/或compiler.libcxx的影响,因为作为 C 库,其二进制文件将是独立的。给定的包配方可以实现一些信息的局部擦除,例如,为了获得一个编译器版本范围的相同
package_id。这种类型的二进制兼容性通常最好通过全局compatibility插件或compatibility()方法来解决,如果全局插件不够的话。包配方可以决定在其计算出的
package_id中注入额外的变异性,添加conf项或“目标”设置。
可用的自动实现¶
警告
此功能是实验性的,可能会发生重大更改。有关更多信息,请参阅 Conan 稳定性 部分。
当 package_id() 方法未定义时,可以在 implements ConanFile 属性中指定以下自动实现:
auto_header_only¶
当配方声明了一个选项 header_only=True 或 package_type 为 "header-library" 时,Conan 将自动管理清除设置和选项的包 ID。它可以这样添加到配方中:
from conan import ConanFile
class Pkg(ConanFile):
implements = ["auto_header_only"]
...
然后,如果在配方中没有指定 package_id() 方法,Conan 将自动管理它并在 package_id() 中自动调用 self.info.clear(),使 package_id 独立于设置、选项、配置和需求。
如果您需要在配方中实现自定义行为,但同时还需要此逻辑,则必须明确声明,例如,像这样:
def package_id(self):
if self.package_type == "header-library":
self.info.clear()
else:
self.info.settings.rm_safe("compiler.libcxx")
self.info.settings.rm_safe("compiler.cppstd")
信息擦除¶
这是一个 package_id 放宽策略。让我们检查第一种情况:一个仅头文件库,它拥有输入的 settings,因为它仍然希望在其 build() 方法中使用它们进行一些单元测试。为了获得所有配置的唯一最终二进制文件,因为最终的工件在所有情况下都应该是相同的(只是头文件),则需要执行以下操作:
settings = "os", "compiler", "arch", "build_type"
def build(self):
cmake = CMake(self) # need specific settings to build
...
cmake.test() # running unit tests for the current configuration
def package_id(self):
# Completely clear all the settings from the ``package_id`` information ("info" object)
# All resulting ``package_id`` will be the same, irrespective of configuration
self.info.settings.clear()
警告
信息的修改始终发生在 self.info 对象上,而不是 self.settings 或 self.options 上。
如果一个包只是一个 C 库,但在 configure() 方法中无法删除 compiler.cppstd 和 compiler.libcxx(这是大多数情况下推荐的方法,以确保这些标志不用于构建),因为 C 库有 C++ 单元测试,并且测试不打包,最终二进制文件将独立于 C++,因此可以删除这些:
settings = "os", "compiler", "arch", "build_type"
def build(self):
# building C++ tests for a C library
def package_id(self):
del self.info.settings.compiler.cppstd
# Some compilers might not declare libcxx subsetting
self.info.settings.rm_safe("compiler.libcxx")
如果一个包正在构建一个可执行文件以用作工具,并且每个操作系统和架构只希望有一个可执行文件以提高效率,那么 package_id() 可以删除其他设置和选项(如果存在)。
# this will be a "tool_require"
package_type = "application"
settings = "os", "compiler", "arch", "build_type"
def package_id(self):
del self.info.settings.compiler
del self.info.settings.build_type
请注意,这并不意味着 compiler 和 build_type 应该从每个应用程序可执行文件中删除。对于其他不是工具但最终要发布的最终产品,最常见的情况是为不同的编译器、编译器版本、构建类型等维护不同的构建是最佳方法。这也意味着我们正在擦除一些信息。我们将无法获得用于我们正在使用的二进制文件的编译器和构建类型的信息(它不会出现在 conan list 输出中,也不会出现在服务器元数据中)。如果我们使用不同的编译器或构建类型编译一个新的二进制文件,它将在相同的 package_id 下创建一个新的包修订版。
部分信息擦除¶
还可以为给定的值子集部分擦除信息。例如,如果我们希望所有使用 gcc 在 4.5 到 5.0 版本之间编译的二进制文件具有相同的 package_id,我们可以这样做:
def package_id(self):
v = Version(str(self.info.settings.compiler.version))
if self.info.settings.compiler == "gcc" and (v >= "4.5" and v < "5.0"):
# The assigned string can be arbitrary
self.info.settings.compiler.version = "GCC 4 between 4.5 and 5.0"
这将导致除 gcc 之外的所有其他编译器以及该范围之外的其他版本具有不同的 package_id,但对于所有 gcc 4.5-5.0 版本将只有一个 package_id 二进制文件。这也带来了上述关于丢失创建此二进制文件的信息的缺点。
在一般情况下不推荐使用此方法,并且最好通过全局 compatibility 插件或配方 compatibility() 方法来处理。
注意
不仅可以擦除 settings,还可以擦除其他类型的信息,如 options 和 conf 项。
添加信息¶
默认情况下,有些信息不会添加到 package_id 中。如果我们正在为一个工具创建一个包,用作 tool_require,并且碰巧这样的包二进制文件对于每个“目标”配置都会不同,例如某些交叉编译器的情况,如果编译器本身可能因其正在针对的不同架构而异,那么就有必要通过以下方式将 settings_target 添加到 package_id 中:
def package_id(self):
self.info.settings_target = self.settings_target
默认情况下,conf 项不会影响 package_id。可以通过以下方式在配方级别显式地将其包含在内:
def package_id(self):
self.info.conf.define("user.myconf:myitem", self.conf.get("user.myconf:myitem"))
虽然这可以通过 tools.info.package_id:confs = ["user.myconf:myitem"] 配置对所有配方在没有 package_id() 方法的情况下实现。
使用正则表达式模式:您可以在 tools.info.package_id:confs 中使用正则表达式模式。这意味着,您不必指定每个单独的配置项,而是可以使用正则表达式模式来匹配多个配置。这在处理大量配置或配置遵循可预测的命名模式时特别有用。例如:
tools.info.package_id:confs=[".*"]匹配所有配置。tools.info.package_id:confs=["tools\..*"]匹配以“tools.”开头的配置。tools.info.package_id:confs=["(tools\.deploy|core)"]匹配以“tools.deploy”或“core”开头的配置。
另请参阅
有关
package_id()方法的说明,请参阅 关于仅头文件包的教程。有关 Conan 二进制模型的完整视图,请阅读 二进制模型参考。