package_id()¶
Conan 为每个配置计算一个唯一的 package_id
引用,包括 settings
、options
和 dependencies
版本。 此 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
项目或“target”设置。
可用的自动实现¶
警告
此功能是实验性的,可能会发生重大更改。 有关更多信息,请参见 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")
如果一个包正在构建一个可执行文件以用作工具,并且希望每个 OS 和体系结构只有一个可执行文件以提高效率,则 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
下创建一个新的包修订。
部分信息擦除¶
也可以为给定的值子集部分擦除信息。 例如,如果我们希望对于使用 4.5 到 5.0 版本之间的 gcc
编译的所有二进制文件具有相同的 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
,并且该包二进制文件对于每个“target”配置都不同,例如对于某些交叉编译器,如果编译器本身对于它所定位的不同体系结构可能不同,则有必要将 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 二进制模型。