本文档翻译自:https://docs.conan.io/en/latest/creating_packages/define_abi_compatibility.html#versioning-schema

    默认情况下,Conan假定semver兼容。 例如,如果版本从次要2.0更改为2.1,Conan将假定该API是兼容的(标头未更改),并且不需要为其构建新的二进制文件。 这也适用于补丁,即从2.1.10更改为2.1.11不需要重新构建。

    如果需要更改默认行为,则可以在package_id()方法中自定义应用的版本控制架构:

    1. from conans import ConanFile, CMake, tools
    2. from conans.model.version import Version
    3. class PkgConan(ConanFile):
    4. name = "my_lib"
    5. version = "1.0"
    6. settings = "os", "compiler", "build_type", "arch"
    7. requires = "my_other_lib/2.0@lasote/stable"
    8. def package_id(self):
    9. myotherlib = self.info.requires["my_other_lib"]
    10. # Any change in the MyOtherLib version will change current Package ID
    11. myotherlib.version = myotherlib.full_version
    12. # Changes in major and minor versions will change the Package ID but
    13. # only a MyOtherLib patch won't. E.g., from 1.2.3 to 1.2.89 won't change.
    14. myotherlib.version = myotherlib.full_version.minor()

    除了version外,还有其他帮助程序可用于确定某个依赖项的通道和用户是否也会影响二进制程序包,甚至所需的程序包ID都可以更改您自己的程序包ID。
    您可以使用以下模式确定任何需求中的以下变量是否更改了二进制包的ID:

    Modes / Variables **name** **version** **user** **channel** **package_id** RREV PREV
    semver_direct_mode() Yes Yes, only > 1.0.0 (e.g., 1.2.Z+b102) No No No No No
    semver_mode() Yes Yes, only > 1.0.0 (e.g., 1.2.Z+b102) No No No No No
    major_mode() Yes Yes (e.g., 1.2.Z+b102) No No No No No
    minor_mode() Yes Yes (e.g., 1.2.Z+b102) No No No No No
    patch_mode() Yes Yes (e.g., 1.2.3+b102) No No No No No
    base_mode() Yes Yes (e.g., 1.7+b102) No No No No No
    full_version_mode() Yes Yes (e.g., 1.2.3+b102) No No No No No
    full_recipe_mode() Yes Yes (e.g., 1.2.3+b102) Yes Yes No No No
    full_package_mode() Yes Yes (e.g., 1.2.3+b102) Yes Yes Yes No No
    unrelated_mode() No No No No No No No
    recipe_revision_mode() Yes Yes Yes Yes Yes Yes No
    package_revision_mode() Yes Yes Yes Yes Yes Yes Yes

    所有模式都可以应用于所有依赖项或单个依赖项:

    1. def package_id(self):
    2. # apply semver_mode for all the dependencies of the package
    3. self.info.requires.semver_mode()
    4. # use semver_mode just for MyOtherLib
    5. self.info.requires["MyOtherLib"].semver_mode()

    semver_direct_mode(): 这是默认模式。它使用semver_mode() 作为直接依赖项 (第一级依赖项,直接由包声明),使用unrelated_mode() 作为包的间接传递依赖项。它假设二进制将受到直接依赖关系的影响,它们已经编码了它们的可传递依赖关系如何影响它们。如上所述,这可能并不总是正确的,这就是可以自定义它的原因。
    在这种模式下,如果包依赖于 “MyLib”,而 “MyLib” 在传递上依赖于 “MyOtherLib”,则该模式表示:

    1. my_lib/1.2.3@user/testing => my_lib/1.Y.Z
    2. my_other_lib/2.3.4@user/testing =>
    • 因此,直接依赖关系仅映射到主要版本。更改其频道或使用版本my_lib/1.4.5 仍将生成my_lib/1.Y. Z,从而生成相同的包id。间接的、可传递的依赖关系根本不会影响包id。
    • semver_mode(): 在此模式下,只有主要发行版本 (从 1.0.0 开始) 才会更改包ID。1.0.0 之前的每个版本更改都会更改包ID,但仅应用 1.0.0 之后的主要更改。
    1. def package_id(self):
    2. self.info.requires["my_other_lib"].semver_mode()

    这导致:

    1. my_lib/1.2.3@user/testing => my_lib/1.Y.Z
    2. my_other_lib/2.3.4@user/testing => my_other_lib/2.Y.Z

    在这种模式下,从 0 开始的版本被认为是不稳定的,并映射到完整版本:

    1. my_lib/0.2.3@user/testing => my_lib/0.2.3
    2. my_other_lib/0.3.4@user/testing => my_other_lib/0.3.4

    major_mode(): 主要发行版本中的任何更改 (从 0.0.0 开始) 都会更改包ID。

    1. def package_id(self):
    2. self.info.requires["MyOtherLib"].major_mode()

    此模式基本上与semver_mode相同,但唯一的区别是semver认为不稳定的主要版本 0.Y. Z仍然仅映射到主要版本,丢弃次要部件并修补部件。
    minor_mode(): 所需依赖项的主要或次要 (不是补丁或构建) 版本的任何更改都会更改包ID。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].minor_mode()

    patch_mode(): 对所需依赖项的主要、次要或补丁 (非构建) 版本的任何更改都会更改包ID。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].patch_mode()

    base_mode(): 对所需依赖项的版本 (非构建) 的基础所做的任何更改都会更改包ID。请注意,在semver表示法的情况下,这可能会产生与patch_mode() 相同的结果,但实际上,即使没有严格的semver,它也旨在消除版本的构建部分。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].base_mode()

    full_version_mode(): 对所需依赖项版本的任何更改都会更改包ID。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].full_version_mode()
    1. my_other_lib/1.3.4-a4+b3@user/testing => my_other_lib/1.3.4-a4+b3

    full_recipe_mode(): 需求参考的任何变化 (用户和频道也是如此) 都会改变包ID。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].full_recipe_mode()

    这将保留整个依赖项引用,但依赖项的包id除外。

    1. my_other_lib/1.3.4-a4+b3@user/testing => my_other_lib/1.3.4-a4+b3@user/testing

    full_package_mode(): 所需版本、用户、频道或包ID的任何更改都会更改包ID。

    1. def package_id(self):
    2. self.info.requires["my_other_lib"].full_package_mode()

    对依赖项的任何更改 (包括其二进制包id) 将反过来为消费者包生成新的包id。

    1. MyOtherLib/1.3.4-a4+b3@user/testing:73b..fa56 => MyOtherLib/1.3.4-a4+b3@user/testing:73b..fa56

    unrelated_mode(): 要求不会更改包ID。

    1. def package_id(self):
    2. self.info.requires["MyOtherLib"].unrelated_mode()

    recipe_revision_mode(): 依赖项的完整参考和包ID,pkg/version @ user/channel # RREV:pkg_id (包括配方修订),将考虑计算消费者包ID

    1. mypkg/1.3.4@user/testing#RREV1:73b..fa56#PREV1 => mypkg/1.3.4-a4+b3@user/testing#RREV1
    2. .. code-block:: python
    3. def package_id(self):
    4. self.info.requires["mypkg"].recipe_revision_mode()

    package_revision_mode(): 完整的包参考pkg/version @ user/channel # RREV:ID # 上一个依赖项,包括配方修订版,将考虑二进制包ID和包修订,以计算消费者包ID
    这是最严格的模式。上游的任何变化都会产生新的消费者包id,成为一个完全确定性的二进制模型。

    1. # The full reference of the dependency package binary will be used as-is
    2. mypkg/1.3.4@user/testing#RREV1:73b..fa56#PREV1 => mypkg/1.3.4@user/testing#RREV1:73b..fa56#PREV1
    3. .. code-block:: python
    4. def package_id(self):
    5. self.info.requires["mypkg"].package_revision_mode()
    6. Given that the package ID of consumers depends on the package revision PREV of the dependencies, when
    7. one of the upstream dependencies doesn't have a package revision yet (for example it is going to be
    8. built from sources, so its PREV cannot be determined yet), the consumers package ID will be unknown and
    9. marked as such. These dependency graphs cannot be built in a single invocation, because they are intended
    10. for CI systems, in which a package creation/built is called for each package in the graph.

    您还可以手动调整各个属性:

    1. def package_id(self):
    2. myotherlib = self.info.requires["MyOtherLib"]
    3. # Same as myotherlib.semver_mode()
    4. myotherlib.name = myotherlib.full_name
    5. myotherlib.version = myotherlib.full_version.stable() # major(), minor(), patch(), base, build
    6. myotherlib.user = myotherlib.channel = myotherlib.package_id = None
    7. # Only the channel (and the name) matters
    8. myotherlib.name = myotherlib.full_name
    9. myotherlib.user = myotherlib.package_id = myotherlib.version = None
    10. myotherlib.channel = myotherlib.full_channel

    package_id() 的结果是包ID哈希,但是可以在生成的conaninfo.txt文件中检查详细信息。为包ID生成SHA1 哈希时,将考虑 [requires][options][settings],而 [full_xxxx] 字段显示完整的参考信息。
    默认行为生成一个conaninfo.txt,如下所示:

    1. [requires]
    2. MyOtherLib/2.Y.Z
    3. [full_requires]
    4. MyOtherLib/2.2@demo/testing:73bce3fd7eb82b2eabc19fe11317d37da81afa56