核心准则¶
良好实践¶
build() 应该保持简洁,应改在 generate() 中准备构建: 食谱的
generate()
方法的目的是尽可能地准备构建。调用conan install
的用户将执行此方法,生成的 文件应允许用户尽可能轻松地进行“原生”构建(直接调用“cmake”、“meson”等)。 因此,尽可能避免在build()
方法中编写任何逻辑,并将其移至generate()
方法 有助于开发人员在本地实现与conan create
在本地缓存中 构建所产生的构建相同的构建。在生产环境中始终使用您自己的 profile,而不是依赖于自动检测到的 profile,因为这种自动检测的输出可能会随时间变化,导致意外结果。 Profiles(以及许多其他配置)可以使用
conan config install
进行管理。开发人员不应有权上传到服务器上的“开发”和“生产”仓库。只有 CI 构建在服务器上拥有写入权限。开发人员应仅拥有读取权限,最多可以访问一些用于与同事协作和共享内容的“游乐场”仓库,但这些仓库中的包永远不会被使用、移动或复制到开发或生产仓库。
test_package 的目的是验证包的正确创建,而不是进行功能测试。
test_package
的目的是检查包是否已正确创建(即,是否已将头文件、库等正确打包到正确的文件夹中),而不是检查包的功能是否正确。因此,应使其尽可能简单,例如构建并运行一个使用头文件并链接已打包库的可执行文件就足够了。此类执行也应尽可能简单。任何类型的单元测试和功能测试都应在build()
方法中进行。所有输入源必须对所有二进制配置通用: 所有“源”输入,包括
conanfile.py
、conandata.yml
、exports
和exports_source
、source()
方法,以及在source()
方法中应用的补丁,不能依赖于任何条件,如平台、操作系统或编译器,因为它们在所有配置之间共享。此外,所有这些内容的行尾格式应相同,建议在所有平台中始终只使用换行符(line-feeds),并且在 Windows 中不要转换为或检出为crlf
,因为这会导致不同的食谱修订版本。让 ``python_requires`` 尽可能简单。避免传递性
python_requires
,使其尽可能精简,最多在“扁平”结构中显式要求它们,而不是让一个python_requires
要求另一个python_requires
。如果非严格必要,避免继承(通过python_requires_extend
),并务必避免多重继承,因为它极其复杂,且与内置 Python 的工作方式不同。目前 **Conan 缓存不是并发的**。避免任何类型的并发或并行操作,例如不同的并行 CI 作业应使用不同的缓存(通过 CONAN_HOME 环境变量)。这未来可能会改变,我们将致力于提供缓存的并发性,但在那之前,请为并发任务使用隔离的缓存。
避免将 ‘force’ 和 ‘override’ 特性用作版本控制机制。
force
和override
用于解决冲突的特性不建议作为通用的版本控制解决方案,而仅作为解决版本冲突的临时变通方法。应尽可能避免使用它,推荐的方法是在依赖图中更新版本或版本范围,以避免不使用 override 和 force 的冲突。请不要滥用 ‘tool_requires’。它们仅用于在“构建”上下文中运行的可执行文件,例如
cmake
和ninja
,不适用于库或类似库的依赖项,那些必须使用requires
或test_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 进程。这包括从食谱代码、钩子、插件以及基本上任何在调用 Conan 时已经执行的代码中调用 Conan。这样做会导致未定义行为。例如,在
conanfile.py
中运行conan search
是无效的。这包括间接调用,例如在构建脚本(如CMakeLists.txt
)已因 Conan 调用而执行时,从该构建脚本中运行 Conan。出于同样的原因,**Conan Python API 不能在食谱中使用**: Conan Python API 只能从 Conan 自定义命令或用户 Python 脚本中调用,但绝不能从conanfile.py
食谱、钩子、扩展、插件或任何其他由 Conan 执行的代码中调用。settings 和 configuration (conf) 在食谱中是只读的: 不能在食谱中定义或赋值 settings 和 configuration。不应该在食谱中做类似
self.settings.compiler = "gcc"
的事情。那是未定义行为,可能随时崩溃,或者只是被忽略。 Settings 和 configuration 只能在 profile 中、命令行参数中或在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()
必须使用校验和来验证服务器文件不会改变。不使用不可变源文件将是未定义行为。