核心指南

良好实践

  • build() 应该保持简洁,在 generate() 中准备构建:配方中的 generate() 方法旨在尽可能多地准备构建。用户调用 conan install 将执行此方法,生成的文件应允许用户尽可能轻松地进行“原生”构建(直接调用“cmake”、“meson”等)。因此,尽可能避免在 build() 方法中编写任何逻辑,并将其移动到 generate() 方法中,有助于开发人员在本地实现与 conan create 在本地缓存中构建所产生的相同的构建。

  • 在生产环境中始终使用自己的配置文件,而不是依赖自动检测的配置文件,因为自动检测的输出会随时间变化,从而导致意外结果。配置文件(以及许多其他配置)可以通过 conan config install 进行管理。

  • 开发人员不应有权上传到服务器上的“开发”和“生产”存储库。只有 CI 构建在服务器上具有写入权限。开发人员应该只有读取权限,最多只能访问一些用于与同事协作和共享的“试验”存储库,但这些包永远不会被使用、移动或复制到开发或生产存储库中。

  • test_package 的目的是验证包的正确创建,而不是用于功能测试test_package 的目的是检查包是否已正确创建(即,是否已将头文件、库等正确打包到正确的文件夹中),而不是检查包的功能是否正确。因此,它应该尽可能简单,例如构建并运行一个使用头文件并链接到打包库的可执行文件就足够了。此类执行也应尽可能简单。任何单元测试和功能测试都应在 build() 方法中完成。

  • 所有输入源对于所有二进制配置必须是通用的:所有“源”输入,包括 conanfile.pyconandata.ymlexportsexports_sourcesource() 方法以及在 source() 方法中应用的补丁,都不能根据任何平台、操作系统或编译器进行条件设置,因为它们在所有配置之间共享。此外,所有这些内容的行尾应该相同,建议在所有平台中始终只使用换行符,并且在 Windows 中不要转换为 crlf,因为这会导致不同的配方修订。

  • 尽可能保持 ``python_requires`` 简单。避免传递性 python_requires,使其尽可能减少,最多以“扁平”结构明确地要求它们,而不要让 python_requires 依赖其他 python_requires。除非绝对必要,否则避免继承(通过 python_requires_extend),并完全避免多重继承,因为它极其复杂,并且与内置的 Python 继承方式不同。

  • 目前 Conan 缓存不是并发的。避免任何形式的并发或并行,例如不同的并行 CI 任务应该使用不同的缓存(通过 CONAN_HOME 环境变量)。这在将来可能会改变,我们将致力于提供缓存的并发性,但在那之前,并发任务请使用隔离的缓存。

  • 避免将“force”和“override”特性作为版本控制机制。 不建议将 forceoverride 特性作为通用的版本控制解决方案来解决冲突,而应将其作为解决版本冲突的临时性方法。应尽可能避免使用它们,建议在图中更新版本或版本范围,以避免不使用覆盖和强制的冲突。

  • 请不要滥用“tool_requires”。这些仅用于在“构建”上下文中运行的 cmakeninja 等可执行文件,不适用于库或类库依赖项,这些依赖项必须使用 requirestest_requires

  • 调用 Conan 时,位置参数应首先指定,在任何命名参数之前。例如,conan install . -s="os=Windows" 是正确的,但 conan install -s="os=Windows" . 是不正确的。同样,建议在命名参数的名称和值之间使用 = 而不是空格。这是为了避免解析命令行参数时出现一些歧义场景。

  • 强烈不鼓励将 user/channel 用于任何质量、阶段、成熟度或可变信息channel 部分是遗留的,在大多数情况下应避免使用,或者使用固定的字符串,如 stableuser 可用于组织内部的私有包,而对于来自 ConanCenter 或 conan-center-index Github 存储库分支的包,建议不使用任何用户或通道,例如 zlib/1.3.1 ConanCenter 引用,即使是对这些第三方库的配方和包进行自定义也是如此。

  • 管理包质量、阶段或成熟度晋升的方式是使用不同的服务器存储库,众所周知的开发人员最佳实践建议通过在这些不同的服务器存储库之间进行晋升(复制)不可变工件或包来管理流水线,例如,在通过某些质量检查后,将包从 staging 存储库复制到 production 存储库。但非常重要的是,这种晋升绝不能以任何方式更改这些包,它们必须是完全不可变的,甚至不能更改其 user/channel,这就是为什么上述观点不鼓励使用用户和通道,包和工件必须是不可变的。

禁用实践

  • Conan 不可重入:不能从 Conan 自身调用 Conan 进程。这包括从配方代码、钩子、插件以及基本上在 Conan 调用时已经执行的任何代码中调用 Conan。这样做将导致未定义的行为。例如,从 conanfile.py 中运行 conan search 是无效的。这包括间接调用,例如在 Conan 调用导致构建脚本(如 CMakeLists.txt)已经执行时,从该构建脚本中运行 Conan。出于同样的原因,不能从配方中使用 Conan Python API:Conan Python API 只能从 Conan 自定义命令或用户 Python 脚本中调用,但绝不能从 conanfile.py 配方、钩子、扩展、插件或 Conan 执行的任何其他代码中调用。

  • 设置和配置(conf)在配方中是只读的:设置和配置不能在配方中定义或赋值。在配方中不应执行 self.settings.compiler = "gcc" 这样的操作。这是未定义的行为,随时可能崩溃,或者只是被忽略。设置和配置只能在配置文件、命令行参数或 profile.py 插件中定义。

  • 配方保留名称:Conan conanfile.py 配方用户属性和方法应始终以 _ 开头。Conan 保留“公共”命名空间用于所有属性和方法,_conan 用于私有属性和方法。使用任何未文档化的 Python 函数、方法、类、属性,即使它在 Python 意义上是“公共的”,如果该元素未在此文档中进行文档化,则属于未定义的行为。

  • Conan 工件是不可变的:一旦 Conan 包和工件进入 Conan 缓存,它们就被认为是不可变的。任何试图修改导出的源、配方、conandata.yml 或任何导出或打包的工件的行为都是未定义的。例如,不可能在 package_info() 方法或 package_id() 方法中修改包的内容,这些方法绝不应修改、删除或在包内创建新文件。如果需要修改某些包,可以使用自己的自定义 deployer

  • Conan 缓存路径是内部实现细节:Conan 缓存路径是内部实现细节。Conan 配方提供 self.build_folder 等抽象来表示文件夹的必要信息,并提供 conan cache path 等命令来获取当前文件夹的信息。Conan 缓存可以在调试时作为只读进行检查,但不允许通过 Conan 命令行或公共 API 之外的任何其他方式编辑、修改或删除 Conan 缓存中的工件或文件。

  • 配方中使用的源必须是不可变的。一旦配方导出到 Conan 缓存中,就期望源是不可变的,也就是说,将来检索源将始终检索完全相同的源。不允许使用移动目标,例如 git 分支或持续在服务器上重写的文件的下载。git 检出必须是不可变的标签或提交,并且 download()/get() 必须使用校验和来验证服务器文件没有更改。不使用不可变源将导致未定义的行为。