核心准则

良好实践

  • `build()` 方法应保持简单,构建准备工作应在 `generate()` 方法中完成:配方(recipes)的 generate() 方法旨在尽可能地准备构建。调用 conan install 的用户将执行此方法,生成的文件应尽可能方便用户进行“原生”构建(直接调用“cmake”、“meson”等)。因此,尽可能避免在 build() 方法中包含任何逻辑,并将其移至 generate() 方法,有助于开发人员在本地实现与在本地缓存中执行 conan create 构建所产生的相同构建。

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

  • 开发人员不应拥有在服务器上上传到“开发”和“生产”仓库的权限。只有CI构建才拥有服务器上的写入权限。开发人员应只拥有读取权限,最多只能访问一些用于与同事协作和共享的“沙盒”仓库,但这些仓库中的包绝不能用于、移动或复制到开发或生产仓库。

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

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

  • 保持 python_requires 尽可能简单。避免传递性 python_requires,使其尽可能精简,最多在“扁平”结构中明确要求它们,即 python_requires 不再要求其他 python_requires。如果非严格必要,请避免继承(通过 python_requires_extend),并务必避免多重继承,因为它极其复杂,且与Python内置的继承机制工作方式不同。

  • 目前,Conan 缓存不支持并发。避免任何形式的并发或并行,例如,不同的并行CI任务应使用不同的缓存(通过 CONAN_HOME 环境变量)。未来这可能会有所改变,我们将努力提供缓存并发功能,但在那之前,请为并发任务使用独立的缓存。

  • 避免将“force”和“override”特性用作版本控制机制。 forceoverride 特性用于解决冲突,但不推荐作为通用的版本控制解决方案,而应仅作为解决版本冲突的临时性变通方法。应尽可能避免使用它们,推荐的方法是在依赖图中更新版本或版本范围,以避免不使用 overrideforce 的冲突。

  • 请勿滥用“tool_requires”。这些仅适用于在“构建”上下文(build context)中运行的可执行文件,例如 cmakeninja,而不适用于库或类似库的依赖项,后者必须使用 requirestest_requires

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

  • 强烈不建议将 user/channel 用于任何质量、阶段、成熟度或可变信息channel 部分已非常过时,在大多数情况下应避免使用,或使用如 stable 这样的固定字符串。user 可以用于组织内部的私有包,而对于来自 ConanCenter 或 conan-center-index GitHub 仓库分支的包,即使是定制这些第三方库的配方和包,也建议不带任何 user 或 channel 使用它们,就像 zlib/1.3.1 ConanCenter 引用那样。

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

禁止实践

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

  • 设置(Settings)和配置(conf)在配方中是只读的:设置和配置不能在配方中定义或赋值。不应在配方中执行类似 self.settings.compiler = "gcc" 的操作。这是未定义行为,随时可能导致崩溃或被忽略。设置和配置只能在配置文件(profiles)、命令行参数或 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() 必须使用校验和来验证服务器文件没有改变。不使用不可变源将导致未定义行为。