版本范围

在前一节中,我们以 pkg 包的多个版本结尾。让我们删除它们并创建以下简单项目

pkg/conanfile.py
from conan import ConanFile

class pkgRecipe(ConanFile):
    name = "pkg"
app/conanfile.py
from conan import ConanFile

class appRecipe(ConanFile):
    name = "app"
    requires = "pkg/1.0"

让我们创建 pkg/1.0 并安装 app,看看它需要 pkg/1.0

$ conan remove "pkg*" -c
$ conan create pkg --version=1.0
... pkg/1.0 ...
$ conan install app
...
Requirements
    pkg/1.0

然后,如果我们创建 pkg/1.1 的新版本,app 将不会自动使用它

$ conan create pkg --version=1.1
... pkg/1.0 ...
# Note how this still uses the previous 1.0 version
$ conan install app
...
Requirements
    pkg/1.0

因此,我们可以修改 app conanfile 以显式使用新的 pkg/1.1 版本,但我们可以使用以下版本范围表达式(由 [expression] 括号引入)

app/conanfile.py
from conan import ConanFile

class appRecipe(ConanFile):
    name = "app"
    requires = "pkg/[>=1.0 <2.0]"

当我们现在安装 app 的依赖项时,它将自动使用该范围内的最新版本,即使我们创建一个新的版本,也不需要修改 app conanfile

# this will now use the newer 1.1
$ conan install app
...
Requirements
    pkg/1.1

$ conan create pkg --version=1.2
... pkg/1.2 ...
# Now it will automatically use the newest 1.2
$ conan install app
...
Requirements
    pkg/1.2

只要更新的版本在定义的范围内,就会这样。如果我们创建一个 pkg/2.0 版本,app 将不会使用它

$ conan create pkg --version=2.0
... pkg/2.0 ...
# Conan will use the latest in the range
$ conan install app
...
Requirements
    pkg/1.2

使用版本范围时,缓存中的版本优先于远程版本,因此如果您有一个本地 pkg/1.2 包,它将被使用而不是远程包,即使远程包更新。为确保您使用最新的可用版本,您可以使用 install/create 命令中的 --update 参数。请注意,--update 参数将查找命令中指定的所有远程仓库中可能存在的更新版本,并且不会在找到第一个更新的版本时停止。

版本范围可以在多个位置定义

  • conanfile.py recipe 的 requirestool_requirestest_requirespython_requires

  • conanfile.txt 文件中的 [requires][tool_requires][test_requires] 部分中

  • 在命令行参数(如 --requires=--tool_requires)中。

  • 在 profile 的 [tool_requires] 部分中

语义版本控制

语义版本控制规范或 semver,指定软件包应始终使用 3 个点分隔的数字(如 MAJOR.MINOR.PATCH)进行版本控制,每个数字都有非常具体的含义。

Conan 将 semver 规范扩展到任意数量的数字,并且还允许在其中包含小写字母。这是因为在 1.X 期间收集了大量来自用户的经验和反馈,并且很明显,在 C++ 中,版本控制方案通常更复杂,用户需要更大的灵活性,允许像 1.2.3.a.8 这样的版本(如果需要)。

Conan 版本非数字标识符遵循与包名称相同的规则,它们只能包含小写字母。 这是为了避免 1.2.3-Beta1.2.3-beta 成为不同的版本,这可能存在问题,甚至存在安全风险。

在必要时(例如,确定版本范围内的最新版本),版本排序是通过从左到右分别比较版本中每个点分隔的实体来完成的。 数字将按数字进行比较,因此 2 < 11,并且包含字母的条目将按字母顺序进行比较(即使它们也包含一些数字)。

与 semver 规范类似,Conan 可以管理 预发布版本构建版本,格式为:VERSION-prerelease+build。 Conan 还将按照相同的规则对预发布版本和构建版本进行排序,并且每个版本也可以包含任意数量的项目,例如 1.2.3-pre.1.2.1+build.45.a。 请注意,semver 标准不对构建版本应用任何排序,但 Conan 会这样做,其逻辑与用于排序主版本和预发布版本的逻辑相同。

重要

请注意,预发布版本的排序有时可能会令人困惑。 预发布版本发生在它所限定的版本之前。 因此,1.1-alpha.11.1 旧,而不是更新。

范围表达式

范围表达式可以具有比较运算符,用于下限和上限,用空格分隔。 此外,允许隔离的下限和上限,尽管通常不建议在正常的版本控制方案中使用,尤其是仅下限。requires = "pkg/[>=1.0 <2.0]" 将包括 1.0、1.2.3 和 1.9 等版本,但不包括 0.3、2.0 或 2.1 版本。

波浪号 ~ 运算符可用于定义“近似”相等的版本范围。requires = "pkg/[~1]" 将包括 1.3 和 1.8.1 等版本,但不包括 0.8 或 2.0 等版本。 同样,requires = "pkg/[~2.5]" 将包括 2.5.0 和 2.5.3,但不包括 2.1、2.7、2.8。

插入符号 ^ 运算符与波浪号非常相似,但允许最后定义的数字发生变化。requires = "pkg/[^1.2]" 将包括 1.2.1、1.3 和 1.51,但不包括 1.0、2、2.0。

也可以使用 OR 运算符应用多个条件,例如 requires = "pkg/[>1 <2.0 || ^3.2]",但在实践中不建议使用这种复杂的表达式,而应仅在非常极端的情况下使用。

可以对字符串的末尾使用字符串匹配,以简化某些范围,否则这些范围将需要更复杂的条件(此功能是实验性的)。 定义 requires=pkg/[1.2.3.*] 将匹配任何以 1.2.3. 开头的版本,并丢弃其他版本。 例如,它将匹配 1.2.3.51.2.3.abc,但它将丢弃 1.2.3(因为它没有最后的点)。

最后,请注意默认情况下不会解析预发布版本。 将它们包含在范围中的方法是通过 include_prerelease 选项(requires = "pkg/[>1 <2, include_prerelease]")或通过 core.version_ranges:resolve_prereleases=True 配置显式启用它们。 在此示例中,将包括 1.0-pre.1 和 1.5.1-pre1,但会排除 2.0-pre1。

注意

虽然可以在 requires 版本范围中硬编码 include_prerelease,但通常不建议这样做。 预发布版本应该是选择加入的,并由用户控制,用户可以决定是否要使用预发布版本。 此外,请注意 include_prereleases 不接收任何参数,因此无法使用 include_prerelease=False 停用预发布版本。

有关有效范围表达式的更多信息,请转到 Requires 参考