Conan 进阶:仓库管理、本地开发与版本控制
2026/6/16 21:45:17 网站建设 项目流程

原文:Conan Documentation — Release 2.29.0


第一部分:使用 Conan 仓库

3.3.1 管理远程仓库(remotes)

Conan 默认从ConanCenter获取包。你可以添加其他远程仓库。

# 查看已配置的远程仓库$ conan remote list conancenter: https://center2.conan.io[Verify SSL: True]# 添加远程仓库$ conan remoteaddmyremote https://mycompany.jfrog.io/api/conan/myrepo# 添加本地目录作为远程仓库$ conan remoteaddmylocalrepo ./repo --allowed-packages="hello/*"# 删除远程仓库$ conan remote remove myremote

3.3.2 上传包

# 上传包(仅最新 recipe revision + 所有二进制)$ conan upload hello/1.0-c-r=myremote# 上传所有 revisions$ conan upload hello/1.0#* -c -r=myremote

3.3.3 搜索包

# 从远程仓库搜索$ conan list"*"-r=conancenter# 搜索特定包$ conan list"zlib/*"-r=conancenter# 搜索本地缓存$ conan list hello

3.3.4 从 ConanCenter 获取包

从 Conan 2.9.2 开始,默认远程仓库已更改为https://center2.conan.io。如果遇到旧的默认远程配置,更新:

$ conan remote update conancenter--url="https://center2.conan.io"

贡献到 ConanCenter 请访问:https://github.com/conan-io/conan-center-index

3.3.5 本地配方索引仓库

对于不适合 ConanCenter 的包,可以创建本地配方索引仓库:

$mkdirrepo&&cdrepo $ conan new local_recipes_index-dname=hello-dversion=0.1\-durl=https://github.com/conan-io/libhello/archive/refs/tags/0.0.1.zip\-dsha256=1dfb66cfd1e2fb7640c88cc4798fe25853a51b628ed9372ffc0ca285fe5be16b

目录结构:

repo/ recipes/ hello/ all/ conandata.yml conanfile.py test_package/ config.yml

添加为本地远程:

$ conan remoteaddmylocalrepo ./repo --allowed-packages="hello/*"

从本地索引安装:

$ conan list"*"-r=mylocalrepo $ conaninstall--requires=hello/0.1-r=mylocalrepo--build=missing

注意:本地配方索引仓库不存储二进制包,每个消费者需要自行--build=missing


第二部分:本地开发包

3.4.1 包开发流程

每次改代码都运行conan create很慢。Conan 提供了本地开发流程,让你在本地目录中测试 recipe 的各个阶段。

第一步:conan source

测试source()方法,从远程获取源代码到本地src/目录:

$ conansource.conanfile.py(hello/1.0): Calling source()in.../src Downloading main.zip conanfile.py(hello/1.0): Unzipping3.7KB Unzipping100%
第二步:conan install

安装依赖、生成构建配置:

$ conaninstall.-------- Finalizinginstall(deploy, generators)-------- conanfile.py(hello/1.0): Generator'CMakeDeps'calling'generate()'conanfile.py(hello/1.0): Generating aggregatedenvfiles

会在build/目录生成 toolchain 和环境文件:

build/ Release/ generators/ conan_toolchain.cmake conanbuild.sh conanrun.sh ...
第三步:conan build

构建包:

$ conan build.... -- Conan toolchain: C++ Standard11with extensions ON -- Conan toolchain: Setting BUILD_SHARED_LIBS=OFF -- Configuringdone-- Generatingdone[100%]Built target hello

也可以直接用 CMake 构建(CMake >= 3.23):

$cdsrc $ cmake--presetconan-release $ cmake--build--presetconan-release[100%]Built target hello
第四步:conan export-pkg

将本地构建的产物打包到 cache 中,同时运行 test_package:

$ conan export-pkg.conanfile.py(hello/1.0): Packaged1'.h'file: hello.h conanfile.py(hello/1.0): Packaged1'.a'file: libhello.a conanfile.py(hello/1.0): Package'b1d267f77ddd5d10d06d2ecf5a6bc433fbb7eeed'created... -------- Testing the package: Running test()-------- hello/1.0(test package): RUN: ./example hello/1.0: Hello World Release!

3.4.2 可编辑模式下的包(Editable Mode)

Editable mode 让其他包直接引用你本地工作目录中的包,而无需先conan create

场景:你在本地开发say/1.0库,同时hello包依赖它。你想修改say后立即在hello中看到效果。

第一步:启用 editable mode
$cdsay $ conan editableadd.--name=say--version=1.0

输出:

Reference 'say/1.0' added to editable packages
第二步:构建 say 包本地
$cdsay $ conaninstall.-sbuild_type=Release $ cmake--presetconan-release $ cmake--build--presetconan-release[100%]Built target say
第三步:hello 消费包引用 editable say
$cd../hello $ conaninstall.-sbuild_type=Release# Linux/macOS$ cmake--presetconan-release --log-level=VERBOSE# Windows$ cmake--presetconan-default --log-level=VERBOSE... -- Conan: Target declared'say::say'-- Conan: Library say found<local_folder>/say/build/Release/libsay.a... $ cmake--build--presetconan-release[100%]Built target hello

注意输出中say::say本地的say/build/Release/libsay.a链接,而不是 Conan 缓存。

第四步:修改 say 代码立即生效

修改say/src/say.cpp后,只需重新构建say,不需要任何 Conan 操作:

$cd../say $ cmake--build--presetconan-release[100%]Built target say# hello 下次构建时自动使用新的 libsay.a$cd../hello $ cmake--build--presetconan-release
第五步:退出 editable mode
$cd../say $ conan editable remove--refs=say/1.0

3.4.3 理解 Conan 包布局(Package Layout)

为了支持 cached 和 editable 两种模式共存,需要在layout()方法中正确配置。

完整的 layout() 示例
importosfromconanimportConanFilefromconan.tools.cmakeimportCMakeclassSayConan(ConanFile):name="say"version="1.0"exports_sources="CMakeLists.txt","src/*","include/*"deflayout(self):# 1. 定义文件夹结构self.folders.source="."self.folders.build=os.path.join("build",str(self.settings.build_type))self.folders.generators=os.path.join(self.folders.build,"generators")# 2. cpp.package — 告诉消费者在缓存中找什么self.cpp.package.libs=["say"]self.cpp.package.includedirs=["include"]self.cpp.package.libdirs=["lib"]# 3. cpp.source — 告诉消费者在 editable 模式下找头文件self.cpp.source.includedirs=["include"]# 4. cpp.build — 告诉消费者在 editable 模式下找库文件self.cpp.build.libdirs=["."]defbuild(self):cmake=CMake(self)cmake.configure()cmake.build()
缓存模式查找路径
$ cmake--presetconan-release --log-level=VERBOSE... -- Conan: Library say found<CACHE>/p/say8938ceae216fc/p/lib/libsay.a
Editable 模式查找路径
$ cmake--presetconan-release --log-level=VERBOSE... -- Conan: Library say found<LOCAL>/say/build/Release/libsay.a

3.4.4 Workspaces(工作区)

⚠️ 警告:Workspace 是实验性功能,需要设置环境变量CONAN_WORKSPACE_ENABLE=will_break_next才能启用。生产环境不可用。

用于管理多个 editable 模式下包之间的依赖关系。

# 创建工作区模板$ conan new workspace

目录结构:

. ├── CMakeLists.txt ├── app1/ ├── liba/ ├── libb/ ├── conanws.py └── conanws.yml

创建自定义工作区:

$mkdirmyproject&&cdmyproject $ conan workspace init.$ conan new cmake_lib-dname=hello-dversion=1.0-ohello $ conan new cmake_exe-dname=app-dversion=1.0-drequires=hello/1.0-oapp# 将包添加到工作区$ conan workspaceaddhello $ conan workspaceaddapp# 构建所有包$ conan workspace build $ app/build/Release/app hello/1.0: Hello World Release!app/1.0: Hello World Release!

第三部分:版本管理

3.5.1 版本

最基本的版本管理——手动修改conanfile.py

classpkgRecipe(ConanFile):name="pkg"version="1.0"
$ conan create.$ conan list"pkg/*"Local Cache pkg pkg/1.0

创建多个版本:

$ conan create.--version=1.0$ conan create.--version=1.1$ conan create.--version=1.2$ conan list"pkg/*"Local Cache pkg pkg/1.0 pkg/1.1 pkg/1.2
自动版本设置——从文件读取
fromconan.tools.filesimportloadclasspkgRecipe(ConanFile):name="pkg"defset_version(self):self.version=load(self,"version.txt")
自动版本设置——从 Git Tag 获取
fromconan.tools.scmimportGitclasspkgRecipe(ConanFile):name="pkg"defset_version(self):git=Git(self)tag=git.run("describe --tags")self.version=tag
$gittag1.5$ conan create.... pkg/1.5

3.5.2 版本范围

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

行为演示:

$ conan create pkg--version=1.0$ conaninstallapp# → 使用 pkg/1.0$ conan create pkg--version=1.1$ conaninstallapp# → 自动使用 pkg/1.1(不需改 app)$ conan create pkg--version=2.0$ conaninstallapp# → 仍然使用 pkg/1.2(2.0 不在范围内)

版本范围表达式对照表:

表达式含义匹配示例
[>=1.0 <2.0]明确范围1.0, 1.5, 1.9
[~1]近似 1.x1.3, 1.8.1
[~2.5]近似 2.5.x2.5.0, 2.5.3
[^1.2]兼容 1.x1.2.1, 1.3, 1.51
[^0.1.2]兼容 0.1.x0.1.2.1, 0.1.3
[1.2.3.*]字符串前缀匹配1.2.3.5, 1.2.3.abc

Conan 版本排序规则:数字按数值比较,字母按字典序,预发布版本小于正式版本。

3.5.3 Revisions(修订版本)

每次构建包时,即使版本号不改变,Conan 也会自动跟踪变更:

# 第一次创建$ conan new cmake_lib-dname=hello-dversion=1.0$ conan create.hello/1.0: Hello World Release!$ conan list"hello/1.0#*"revisions 2475ece651f666f42c155623228c75d2# 修改 src/hello.cpp 中 "Hello" → "Bye"$ conan create.hello/1.0: Bye World Release!$ conan list"hello/1.0#*"revisions 2475ece651f666f42c155623228c75d2 2b547b7f20f5541c16d0b5cbcf207502# ← 新 revision,版本号还是 1.0

Recipe revision= conanfile.py + 所有导出文件的哈希
Package revision= 二进制内容的哈希

锁定特定 revision:

defrequirements(self):self.requires("hello/1.0#2475ece651f666f42c155623228c75d2")

上传 revisions:

# 仅最新 revision$ conan upload hello/1.0-c-r=myremote# 所有 revisions$ conan upload hello/1.0#* -c -r=myremote

Windows 注意:Git 默认使用 CRLF 换行符,这会导致 Windows 和 Linux 计算出不同的 revision。

3.5.4 Lockfiles(锁定文件)

Lockfile 锁定依赖图的"快照",确保后续构建可重现。

创建 lockfile
$ conan lock create.

生成的conan.lock

{"version":"0.5","requires":["matrix/1.0#905c3f0babc520684c84127378fefdd0%1675278126.0552447"],"build_requires":[],"python_requires":[]}
使用 lockfile

创建新版本不会影响已锁定的项目:

$ conan create matrix--version=1.1$cdengine $ conaninstall.Requirements matrix/1.0#905c3f0babc520684c84127378fefdd0 - Cache # 仍然用 1.0

没有显式指定--lockfile时,Conan 自动查找当前目录的conan.lock

部分 lockfile
$ conaninstall.-sarch=x86 --lockfile-partial
演进 lockfile
# 添加新版本到 lockfile$ conan lockadd--requires=matrix/1.1# 更新并清理 lockfile$ conaninstall.-sarch=x86 --lockfile-out=conan.lock --lockfile-clean
多配置 lockfile 合并
$ conan lock create.--lockfile-out=64.lock --lockfile-clean $ conan lock create.-sarch=x86 --lockfile-out=32.lock --lockfile-clean $ conan lock merge--lockfile=32.lock--lockfile=64.lock --lockfile-out=conan.lock

3.5.5 依赖冲突

当依赖图中不同包要求不同版本的同一包时,会产生冲突。

创建冲突场景:

game/1.0 ├── engine/1.0 → matrix/1.0 └── intro/1.0 → matrix/1.1
$ conan create matrix--version=1.0$ conan create matrix--version=1.1$ conan create engine--version=1.0$ conan create intro--version=1.0$ conaninstallgame

输出:

ERROR: Version conflict: 'matrix/1.0' required by 'engine/1.0', while 'matrix/1.1' required by 'intro/1.0'

解决方案:

  1. 使用版本范围,让上游作者统一到一个版本区间
  2. 使用 lockfile 固定所有依赖到一致的状态
  3. 升级或降级其中一个依赖以消除冲突

完整命令速查表

场景命令
创建包conan new cmake_lib -d name=xxx -d version=1.0
构建包conan create .
查看缓存conan list xxx
配置不同构建-s build_type=Debug,-o shared=True
上传包conan upload hello/1.0 -c -r=myremote
添加远程conan remote add xxx <url>
本地开发(source)conan source .
本地开发(install)conan install .
本地开发(build)conan build .
本地开发(打包)conan export-pkg .
Editable 模式conan editable add . --name=xxx --version=1.0
退出 Editableconan editable remove --refs=xxx/1.0
创建 lockfileconan lock create .
锁定 revisionself.requires("pkg/1.0#<hash>")
版本范围self.requires("pkg/[>=1.0 <2.0]")
自动版本号conan create . --version=1.0set_version()

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询