核心准则¶
最佳实践¶
build() 应该保持简单,在 generate() 中准备构建:配方中的
generate()
方法的目的是尽可能地准备构建。调用conan install
的用户将执行此方法,生成的 文件应允许用户尽可能轻松地进行“原生”构建(直接调用“cmake”、“meson”等)。因此,尽可能避免在build()
方法中使用任何逻辑,并将逻辑移动到generate()
方法有助于开发人员在本地实现与conan create
构建在本地缓存中生成的构建相同的构建。在生产环境中始终使用您自己的配置文件,而不是依赖于自动检测的配置文件,因为此类自动检测的输出可能会随着时间的推移而发生变化,从而导致意外的结果。配置文件(以及许多其他配置)可以使用
conan config install
进行管理。开发人员不应能够上传到服务器上的“开发”和“生产”存储库。只有 CI 构建在服务器上具有写权限。开发人员应该只具有读权限,最多可以访问一些用于与同事协作和共享内容的“游乐场”存储库,但这些包绝不会被使用、移动或复制到开发或生产存储库。
test_package 的目的是验证包的正确创建,而不是进行功能测试。
test_package
的目的是检查包是否已正确创建(即,它是否已将头文件、库等正确打包到正确的文件夹中),而不是检查包的功能是否正确。然后,它应该尽可能保持简单,例如构建并运行一个使用头文件并链接到打包库的可执行文件就足够了。此类执行也应该尽可能简单。任何类型的单元和功能测试都应该在build()
方法中完成。所有输入源必须对所有二进制配置通用:所有“源”输入,包括
conanfile.py
、conandata.yml
、exports
和exports_source
、source()
方法、在source()
方法中应用的补丁,不能以任何平台、操作系统或编译器为条件,因为它们在所有配置之间共享。此外,所有这些内容的行尾应该相同,建议在所有平台上始终只使用换行符,并且不要在 Windows 中转换为或检出到crlf
,因为这会导致不同的配方修订版本。尽可能保持 ``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 存储库的分支的包,建议在没有用户或通道的情况下使用它们,例如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 保留“公共”命名空间用于所有属性和方法,并保留_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()
必须使用校验和来验证服务器文件不会更改。不使用不可变源代码将导致未定义的行为。