修订版

本节介绍如何在不显式创建新版本的情况下,对给定的配方或源代码进行修改,并仍然通过一种称为修订版的机制内部跟踪这些更改。

创建不同的修订版

让我们从一个基本的“hello”包开始

$ mkdir hello && cd hello
$ conan remove hello* -c # clean possible existing ones
$ conan new cmake_lib -d name=hello -d version=1.0
$ conan create .
hello/1.0: Hello World Release!
...

现在我们可以列出缓存中现有的配方修订版

$ conan list "hello/1.0#*"
Local Cache
  hello
    hello/1.0
      revisions
        2475ece651f666f42c155623228c75d2 (2023-01-31 23:08:08 UTC)

如果现在编辑 src/hello.cpp 文件,将输出消息从“Hello”更改为“Bye”

hello/src/hello.cpp
void hello(){

    #ifdef NDEBUG
    std::cout << "hello/1.0: Bye World Release!\n";
    ...

因此,如果我们再次创建包,而不更改版本 hello/1.0,我们将获得一个新的输出

$ conan create .
hello/1.0: Bye World Release!
...

即使版本相同,内部也会创建一个新的修订版 2b547b7f20f5541c16d0b5cbcf207502

$ conan list "hello/1.0#*"
Local Cache
  hello
    hello/1.0
      revisions
        2475ece651f666f42c155623228c75d2 (2023-01-31 23:08:08 UTC)
        2b547b7f20f5541c16d0b5cbcf207502 (2023-01-31 23:08:25 UTC)

这个配方 修订版 是配方内容的哈希值,包括 conanfile.py 和导出的源代码(src/main.cppCMakeLists.txt 等,即配方中导出的所有文件)。

现在我们可以编辑 conanfile.py,以定义 license

hello/conanfile.py
class helloRecipe(ConanFile):
    name = "hello"
    version = "1.0"

    # Optional metadata
    license = "MIT"
    ...

因此,如果我们再次创建包,输出将相同,但我们也会获得一个新的修订版,因为 conanfile.py 已更改

$ conan create .
hello/1.0: Bye World Release!
...
$ conan list "hello/1.0#*"
Local Cache
  hello
    hello/1.0
      revisions
        2475ece651f666f42c155623228c75d2 (2023-01-31 23:08:08 UTC)
        2b547b7f20f5541c16d0b5cbcf207502 (2023-01-31 23:08:25 UTC)
        1d674b4349d2b1ea06aa6419f5f99dd9 (2023-01-31 23:08:34 UTC)

重要

配方 修订版 是内容的哈希值。 可以使用 revision_mode = "scm" 将其更改为 Git 提交哈希值。 但无论如何,重要的是每个修订版都代表一个不可变的源,包括配方和源代码

  • 如果源代码使用 exports_sources 管理,则它们将自动包含在哈希值中

  • 如果从外部位置检索源代码,例如下载的 tarball 或 git 克隆,则它应该通过强制检出唯一的不可变标签或提交来保证唯一性。 像分支名称或 HEAD 这样的移动目标将会被破坏,因为修订版被认为是不可变的。

源代码或配方的任何更改都应始终意味着一个新的修订版。

警告

行尾问题

Git 默认情况下,将在 Windows 系统上使用 CRLF 行尾检出文件。 这导致与 Linux 系统相比不同的文件,Linux 系统将使用 LF 行尾。 由于文件不同,在 Windows 上计算的 Conan 配方修订版将与在其他平台(如 Linux)上的修订版不同。 请查看更多关于此问题以及如何在 FAQ 专用部分 中解决此问题的信息。

使用修订版

默认情况下,配方修订版解析为每个给定版本的最新修订版。 在上面的例子中,我们可以有一个 chat/1.0 包,它使用上面的 hello/1.0

$ cd ..
$ mkdir chat && cd chat
$ conan new cmake_lib -d name=chat -d version=1.0 -d requires=hello/1.0
$ conan create .
...
Requirements
chat/1.0#17b45a168519b8e0ed178d822b7ad8c8 - Cache
hello/1.0#1d674b4349d2b1ea06aa6419f5f99dd9 - Cache
...
hello/1.0: Bye World Release!
chat/1.0: Hello World Release!

我们可以看到默认情况下,它解析为最新的修订版 1d674b4349d2b1ea06aa6419f5f99dd9,因此我们也看到 hello/1.0: Bye World 修改后的消息。

可以在配方中显式依赖于给定的修订版,因此可以修改 chat/1.0 配方以定义它需要第一个创建的修订版

chat/conanfile.py
def requirements(self):
    self.requires("hello/1.0#2475ece651f666f42c155623228c75d2")

因此,创建 chat 现在将强制使用第一个修订版

$ conan create .
...
Requirements
chat/1.0#12f87e1b8a881da6b19cc7f229e16c76 - Cache
hello/1.0#2475ece651f666f42c155623228c75d2 - Cache
...
hello/1.0: Hello World Release!
chat/1.0: Hello World Release!

注意

请注意,在版本范围内固定修订版不起作用,Conan 会发出警告。

上传修订版

默认情况下,上传命令只会上传最新的修订版

# upload latest revision only, all package binaries
$ conan upload hello/1.0 -c -r=myremote

如果出于某种原因我们想要上传所有现有的修订版,可以使用

# upload all revisions, all binaries for each revision
$ conan upload hello/1.0#* -c -r=myremote

在服务器端,上传的最新修订版将成为最新的修订版,并且默认情况下将解析为该修订版。 因此,上述命令按顺序上传不同的修订版(从较旧的修订版到最新的修订版),以便在服务器端尊重修订版的相对顺序。

请注意,如果另一台机器决定上传一段时间前创建的修订版,它仍然会成为服务器端的最新修订版,因为它是在服务器端以该时间创建的。

包修订版

创建的包二进制文件也会计算其内容的哈希值,形成 包修订版。 但它们在性质上与 配方修订版 非常不同。 配方修订版自然是预期的,源代码或配方的任何更改都会导致新的配方修订版。 但包二进制文件不应该有超过一个 包修订版,因为二进制文件的可变性已经编码在唯一的 package_id 中。 换句话说,如果配方修订版相同(完全相同的输入配方和源代码),并且 package_id 相同(完全相同的配置配置文件、设置等),那么该二进制文件应该只构建一次。

由于 C 和 C++ 构建不是确定性的,因此即使不进行任何修改,相同包的后续构建也可能会创建新的包修订版

# Build again 2 times the latest
$ conan create .
$ conan create .

在 Windows 等操作系统中,此构建将不可重现,并且生成的工件将具有不同的校验和,从而导致新的包修订版

$ conan list "hello/1.0:*#*"
Local Cache
  hello
    hello/1.0
      revisions
        1d674b4349d2b1ea06aa6419f5f99dd9 (2023-02-01 00:03:29 UTC)
          packages
            2401fa1d188d289bb25c37cfa3317e13e377a351
              revisions
                8b8c3deef5ef47a8009d4afaebfe952e (2023-01-31 23:08:40 UTC)
                8e8d380347e6d067240c4c00132d42b1 (2023-02-01 00:03:12 UTC)
                c347faaedc1e7e3282d3bfed31700019 (2023-02-01 00:03:35 UTC)
              info
                settings
                arch: x86_64
                build_type: Release
                ...

默认情况下,包修订版也将解析为最新的修订版。 但是,无法在配方中显式固定包修订版,配方只能要求达到上面定义的配方修订版。

警告

最佳实践

对于任何给定的配方修订版 + package_id 而言,拥有超过 1 个包修订版是一种气味或潜在的不良做法。 这意味着在不需要时重新构建了某些内容,浪费了计算和存储资源。 有方法可以避免这样做,例如 conan create . --build=missing:hello* 只会在该包二进制文件不存在(或运行 conan graph info 也可以返回需要构建的信息)时构建它。