修订¶
本节介绍如何在不明确创建新版本的情况下修改给定食谱或源代码,但仍将通过一种称为修订的机制在内部跟踪这些更改。
创建不同的修订¶
让我们从一个基本的“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”
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.cpp
、CMakeLists.txt
等,即食谱中导出的所有文件)。
我们现在可以编辑conanfile.py
,定义license
值
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
食谱以定义它需要第一个创建的修订
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!
上传修订¶
上传命令默认只上传最新修订
# 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
也可以返回需要构建的信息)。