设置和选项如何影响软件包 ID

在 Conan 中,软件包 ID 是软件包二进制文件的唯一标识符,它考虑了所有影响其二进制兼容性的因素。这些因素包括配方选项和设置,以及依赖项或工具依赖项。

我们来看看设置和选项如何影响软件包 ID,以及一些不应该影响软件包 ID 的示例。

设置如何影响软件包 ID

设置是项目范围的变量,例如编译器、其版本或操作系统本身。这些变量值必须定义,它们应该与开发环境的值匹配,并且不能像选项那样拥有默认值。

例如,让我们定义一个仅依赖操作系统的配方来生成软件包。

from conan import ConanFile

class Pkg(ConanFile):
    name = "pkg"
    version = "1.0.0"
    settings = "os"  # Only OS setting affects the package ID

如果我们为此配方生成一个 Linux 软件包,我们将获得以下软件包 ID:

 $ conan create . --settings os=Linux
 ...
 pkg/1.0.0: Package '9a4eb3c8701508aa9458b1a73d0633783ecc2270' created

 $ conan list pkg/1.0.0:*
 Local Cache
   pkg
     pkg/1.0.0
       revisions
           476929a74c859bb5f646363a4900f7cf (2024-03-07 09:13:43 UTC)
             packages
               9a4eb3c8701508aa9458b1a73d0633783ecc2270
                 info
                   settings
                     os: Linux

如果我们用 Windows 执行相同的操作,现在软件包 ID 将有所不同。

 $ conan create . --settings os=Windows
 ...
 pkg/1.0.0: Package 'ebec3dc6d7f6b907b3ada0c3d3cdc83613a2b715' created

 $ conan list pkg/1.0.0:*
 Local Cache
   pkg
     pkg/1.0.0
       revisions
           476929a74c859bb5f646363a4900f7cf (2024-03-07 09:13:43 UTC)
             packages
               9a4eb3c8701508aa9458b1a73d0633783ecc2270
                 info
                   settings
                     os: Linux
               ebec3dc6d7f6b907b3ada0c3d3cdc83613a2b715
                 info
                   settings
                     os: Windows

每当设置或子设置的值发生变化时,软件包 ID 将会有所不同,以反映这一点。

设置最常见的用法是模拟可能影响软件包 ID 的不同项目范围的方面。一个这样做过的配方将是:

from conan import ConanFile

class Pkg(ConanFile):
    name = "pkg"
    version = "1.0.0"
    settings = "os", "arch", "compiler", "build_type"

现在,使用不同的编译器版本编译一个软件包将导致不同的软件包 ID。

 $ conan create . --settings compiler.version=192
 ...
 pkg/1.0.0: Package '4f267380690f99b3ef385199826c268f63147457' created

 $ conan create . --settings compiler.version=193
 ...
 pkg/1.0.0: Package 'c13a22a41ecd72caf9e556f68b406569547e0861' created

 $ conan list pkg/1.0.0:*
 Local Cache
   pkg
     pkg/1.0.0
       revisions
         f1f48830ecb04f3b328429b390fc5de8 (2024-03-07 09:21:07 UTC)
           packages
             4f267380690f99b3ef385199826c268f63147457
               info
                 settings
                   arch: x86_64
                   build_type: Release
                   compiler: msvc
                   compiler.cppstd: 14
                   compiler.runtime: dynamic
                   compiler.runtime_type: Release
                   compiler.version: 192
                   os: Windows
             c13a22a41ecd72caf9e556f68b406569547e0861
               info
                 settings
                   arch: x86_64
                   build_type: Release
                   compiler: msvc
                   compiler.cppstd: 14
                   compiler.runtime: dynamic
                   compiler.runtime_type: Release
                   compiler.version: 193
                   os: Windows

移除用作 tool_requires 的软件包的设置

有时,某个设置不应该影响最终的软件包 ID。例如,当一个配方打包了一个通过 tool_requires 用于构建其他软件包的工具时。

在这种情况下,编译工具所需的编译器值对于消费者来说并不那么重要,因为我们只希望执行该工具来构建其他项目。因此,我们可以最终从软件包 ID 中移除编译器的影响。

from conan import ConanFile

class CMake(ConanFile):
    name = "cmake"
    version = "1.0.0"
    settings = "os", "arch", "compiler", "build_type"  # Only OS and architecture influence the resulting package

    def build(self):
        # self.settings.compiler value will be used here to compile cmake

    def package_id(self):
        # Remove compiler setting from package ID
        del self.info.settings.compiler

为什么不从 settings 属性中移除设置?因为在 build() 方法中仍然需要编译器值来执行可执行文件的编译。

注意

如果我们正在生成自己的可执行文件(我们自己的应用程序,而不是 tool_require),**则不建议从软件包 ID 中移除编译器设置**,因为我们总是希望知道软件包是使用特定编译器生成的。

但是,如果我们正在打包一个甚至不需要编译器输入即可构建的工具(例如 Python 脚本),我们也可以直接移除设置属性。

from conan import ConanFile

class MyPythonScripts(ConanFile):
    name = "my-python-scripts"
    version = "1.0.0"
    # No settings this time

或者,如果工具是平台特定的,我们可以只保留操作系统和架构信息。

from conan import ConanFile

class MyScripts(ConanFile):
    name = "my-scripts"
    version = "1.0.0"
    settings = "os", "arch"

选项如何影响软件包 ID

选项用于指定单个配方的特定特征,这与设置不同,后者通常在项目中的配方之间保持一致。它们通常是库、可执行文件或 conan 软件包可能具有的特定特征的集合。

例如,shared 选项是生产共享库的配方中非常常见的选项。然而,它不能作为设置,因为并非所有配方都生产共享库。

from conan import ConanFile

class Pkg(ConanFile):
    name = "pkg"
    version = "1.0.0"
    options = {"shared": [True, False]}
    default_options = {"shared": True}

与之前设置的案例一样,选项的不同值将影响软件包 ID,因此会根据选项生成不同的软件包。

 $ conan create . --options shared=True
 ...
 pkg/1.0.0: Package '1744785cb24e3bdca70e27041dc5abd20476f947' created

 $ conan create . --options shared=False
 ...
 pkg/1.0.0: Package '55c609fe8808aa5308134cb5989d23d3caffccf2' created

同样,可能存在一些“选项”是配方中生成软件包所需的输入,但它们不应被计入软件包 ID。一个例子是用于控制构建阶段某些内容但对软件包结果没有影响的选项,例如编译的详细程度。在这种情况下,配方应在 package_id() 方法 中移除该选项。

但是,总的建议是,**选项应始终影响软件包 ID**,如果我们希望有一个配方输入**不**影响它,则应通过配置文件的 conf 部分 来实现。然后,在配方中,我们应该只添加:

from conan import ConanFile

class MyPkg(ConanFile):
    name = "my-pkg"
    version = "1.0.0"

    def build(self):
        verbosity = self.conf.get("user.my-pkg:verbosity")
        self.output.info(f"Using verbosity level: {verbosity})
        ...
myprofile
[conf]
user.my-pkg:verbosity=silent

这样,软件包 ID 将不受影响,配方将更清晰(没有与软件包 ID 无关的选项),并且可以通过配置文件的 conf 部分轻松管理输入。