核心指南

最佳实践

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

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

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

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

  • 所有输入源对于所有二进制配置必须是通用的:所有 “source” 输入,包括 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’。它们仅适用于在 “build” 上下文中运行的可执行文件,例如 cmakeninja,不适用于必须使用 requirestest_requires 的库或类似库的依赖项。

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

  • 强烈建议不要将用户/通道用于任何质量、阶段、成熟度或变量信息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 是无效的。这包括间接调用,例如在构建脚本(如 CMakeLists.txt)已作为 Conan 调用的结果执行时从该脚本运行 Conan。出于同样的原因,Conan Python API 不能从配方中使用:Conan Python API 只能从 Conan 自定义命令或用户 Python 脚本中调用,但绝不能从 conanfile.py 配方、钩子、扩展、插件或 Conan 执行的任何其他代码中调用。

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

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

  • 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() 必须使用校验和来验证服务器文件是否没有更改。不使用不可变源将是未定义的行为。