核心准则¶
良好实践¶
build() 应该简单,而是在 generate() 中准备构建: recipe 的
generate()
方法的目的是尽可能多地准备构建。调用conan install
的用户将执行此方法,并且生成的文件应允许用户尽可能轻松地进行“原生”构建(直接调用“cmake”、“meson”等)。因此,尽可能避免在build()
方法中包含任何逻辑,并将其移动到generate()
方法,这有助于开发人员实现与本地缓存中conan create
构建生成的相同的构建。始终在生产中使用您自己的 profile,而不是依赖自动检测的 profile,因为这种自动检测的输出会随时间变化,从而导致意外的结果。profile(和许多其他配置)可以使用
conan config install
进行管理。开发人员不应能够上传到服务器上的“开发”和“生产”仓库。只有 CI 构建在服务器上具有写入权限。开发人员应仅具有读取权限,最多只能访问一些“playground”仓库,用于与同事一起工作和共享内容,但这些软件包永远不会被使用、移动或复制到开发或生产仓库。
test_package 的目的是验证软件包的正确创建,而不是用于功能测试。
test_package
的目的是检查软件包是否已正确创建(即,它是否已将头文件、库等正确地打包到正确的文件夹中),而不是软件包的功能是否正确。 然后,它应该尽可能简单,例如构建和运行一个使用头文件并链接到打包库的可执行文件就足够了。 这种执行也应该尽可能简单。 任何类型的单元和功能测试都应在build()
方法中完成。所有输入源对于所有二进制配置必须是通用的:所有“source”输入,包括
conanfile.py
、conandata.yml
、exports
和exports_source
、source()
方法,以及在source()
方法中应用的补丁,不能以任何条件(平台、操作系统或编译器)为条件,因为它们在所有配置之间共享。 此外,所有这些事物的行尾符都应该是相同的,建议始终在所有平台上仅使用换行符,并且不要在 Windows 中转换或签出到crlf
,因为这会导致不同的 recipe 修订。保持 ``python_requires`` 尽可能简单。 避免传递
python_requires
,保持它们尽可能精简,并且最多在“扁平”结构中显式地要求它们,而没有python_requires
要求其他的python_requires
。 如果不是绝对必要,则避免继承(通过python_requires_extend
),并且不惜一切代价避免多重继承,因为它非常复杂,并且它的工作方式与内置的 Python 不同。目前,Conan 缓存不是并发的。 避免任何类型的并发或并行性,例如,不同的并行 CI 作业应使用不同的缓存(使用 CONAN_HOME 环境变量)。 这将来可能会发生变化,我们将努力在缓存中提供并发性,但在那之前,请为并发任务使用隔离的缓存。
避免使用“force”和“override”特征作为版本控制机制。 不建议将
force
和override
特征作为解决冲突的通用版本控制解决方案,而只是作为解决版本冲突的临时解决方法。 应尽可能避免使用它,并且建议更新图中的版本或版本范围以避免没有覆盖和强制的冲突。请不要滥用 '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 引用一样,即使对于自定义那些第三方库的 recipes 和软件包也是如此。管理软件包质量、阶段或成熟度升级的方式是使用不同的服务器仓库,并且众所周知的开发人员最佳实践建议通过在这些不同的服务器仓库之间执行升级(复制)不可变的 artifacts 或软件包来管理管道,例如将软件包从
staging
仓库复制到production
仓库,一旦它们通过了一些质量检查。 但非常重要的是,这种升级不会以任何方式更改这些软件包,这些软件包必须是完全不可变的,甚至不能更改其user/channel
,这就是上述观点不鼓励使用 user 和 channel 的原因,软件包和 artifacts 必须是不可变的。
禁止的实践¶
Conan 不是可重入的:无法从 Conan 本身调用 Conan 进程。 这包括从 recipe 代码、hooks、插件以及基本上在调用 Conan 时已执行的每个代码调用 Conan。 这样做会导致未定义的行为。 例如,从
conanfile.py
运行conan search
是无效的。 这包括间接调用,例如在构建脚本(如CMakeLists.txt
)中运行 Conan,而此构建脚本已经作为 Conan 调用的结果被执行。 出于同样的原因,无法从 recipe 中使用 Conan Python API:Conan Python API 只能从 Conan 自定义命令或从用户 Python 脚本中调用,但永远不能从conanfile.py
recipes、hooks、extensions、插件或 Conan 执行的任何其他代码中调用。设置和配置 (conf) 在 recipe 中是只读的:设置和配置无法在 recipe 中定义或赋值。 不应在 recipe 中执行类似
self.settings.compiler = "gcc"
的操作。 这是未定义的行为,并且可能随时崩溃,或者只是被忽略。 设置和配置只能在 profile、命令行参数或profile.py
插件中定义。Recipes 保留名称:Conan
conanfile.py
recipes 用户属性和方法应始终以_
开头。 Conan 为所有属性和方法保留“公共”命名空间,为私有属性和方法保留_conan
。 使用任何未记录的 Python 函数、方法、类、属性,即使它在 Python 意义上是“公共的”,如果此类元素未在此文档中记录,也是未定义的行为。Conan artifacts 是不可变的:一旦 Conan 软件包和 artifacts 进入 Conan 缓存,它们就被认为是不可变的。 任何试图修改导出的源代码、recipe、conandata.yml 或任何导出的或打包的 artifacts 的尝试都是未定义的行为。 例如,无法修改
package_info()
方法或package_id()
方法中的软件包内容,这些方法绝不应修改、删除或在软件包中创建新文件。 如果需要修改某些软件包,可以使用您自己的自定义deployer
。Conan 缓存路径是内部实现细节: Conan 缓存路径是内部实现细节。Conan recipe 提供了类似
self.build_folder
的抽象来表示关于文件夹的必要信息,并提供了像conan cache path
这样的命令来获取当前文件夹的信息。Conan 缓存可能在调试时以只读方式检查,但不允许通过任何其他方式(Conan 命令行或公共 API 除外)编辑、修改或删除 Conan 缓存中的 artifacts 或文件。recipe 中使用的 sources 必须是不可变的。一旦 recipe 被导出到 Conan 缓存,就应该确保 sources 是不可变的,也就是说,将来检索 sources 时总是检索到完全相同的 sources。不允许使用移动的目标,例如
git
分支或在服务器上不断重写的文件的下载。git
checkout 必须是不可变的 tag 或 commit,并且download()/get()
必须使用校验和来验证服务器文件是否发生更改。不使用不可变的 sources 将导致未定义的行为。