本文是基于对conan官方文档Packaging Approaches翻译而来, 更详细的信息可以去查阅conan官方文档。
Package recipes have three methods for controlling the package’s binary compatibility and for implementing different packaging approaches: package_id()
, build_id()
and package_info()
.
软件包配方有三种方法来控制软件包的二进制兼容性和实现不同的打包方法: package_id()、
build_id() 和
package_info()`。
These methods let package creators select the method most suitable for each library.
这些方法可让软件包创建者选择最适合每个库的方法。
A typical approach is to have one configuration for each package containing the artifacts. Using this approach, for example, the debug pre-compiled libraries will be in a different package than the release pre-compiled libraries.
一种典型的方法是为每个包含工件的软件包设置一个配置。例如,使用这种方法,debug预编译库与release预编译库将放在不同的软件包中。
So if there is a package recipe that builds a “hello” library, there will be one package containing the release version of the “hello.lib” library and a different package containing a debug version of that library (in the figure denoted as “hello_d.lib”, to make it clear, it is not necessary to use different names).
因此,如果有一个软件包配方可以构建一个 "hello "库,那么就会有一个软件包包含 "hello.lib "库的发布版本,另一个软件包包含该库的debug版本(在图中表示为 “hello_d.lib”,这只是为了更加清楚,其实是没有必要使用不同的名称)。
Using this approach, the package_info()
method, allows you to set the appropriate values for consumers, letting them know about the package library names, necessary definitions and compile flags.
使用这种方法,package_info()
方法可以为用户设置适当的值,让他们了解包库名称、必要的定义和编译标志。
class HelloConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
def package_info(self):
self.cpp_info.libs = ["mylib"]
It is very important to note that it is declaring the build_type
as a setting. This means that a different package will be generated for each different value of such setting.
需要注意的是,它将 build_type
声明为一个设置。这意味着不同的设置值将生成不同的软件包。
The values declared by the packages (the include
, lib
and bin
subfolders are already defined by default, so they define the include
and library
path to the package) are translated to variables of the respective build system by the used generators. That is, running the cmake generator will translate the above definition in the conanbuildinfo.cmake to something like:
软件包声明的值(默认情况下已经定义了 include
、lib
和 bin
子文件夹,因此它们定义了软件包的 include
和library
路径)会被使用的生成器转换为相应编译系统的变量。也就是说,运行 cmake 生成器后,conanbuildinfo.cmake 中的上述定义将被转换为类似内容:
set(CONAN_LIBS_MYPKG mylib)
# ...
set(CONAN_LIBS mylib ${CONAN_LIBS})
Those variables, will be used in the conan_basic_setup()
macro to actually set the relevant cmake
variables.
这些变量将用于 conan_basic_setup()
宏,以实际设置相关的 cmake
变量。
If the developer wants to switch configuration of the dependencies, they will usually switch with:
如果开发人员要切换依赖项的配置,通常会使用
$ conan install -s build_type=Release ...
# when need to debug
$ conan install -s build_type=Debug ...
These switches will be fast, since all the dependencies are already cached locally.
这些切换会很快,因为所有依赖项都已缓存在本地。
This process offers a number of advantages:
这种处理方式具有许多优点:
Read more about this in package_info().
有关这方面的更多信息,请参阅 package_info() 。
This approach is discouraged. The support for defining multi-configuration packages (self.cpp_info.release
, self.cpp_info.debug
), will be removed in Conan 2.0, as discussed and approved by the Tribe in https://github.com/conan-io/tribe/pull/21. New generators and helpers in conan.tools.xxxx
, like CMakeDeps
or MSBuildDeps
already ignore cpp_info
multi-configuration definitions.
我们不鼓励采用这种方法。定义多重配置包(self.cpp_info.release
, self.cpp_info.debug
)的支持将在柯南 2.0 中被移除,这在 https://github.com/conan-io/tribe/pull/21 中得到了部落的讨论和批准。在 conan.tools.xxxx
中的新生成器和助手,如 CMakeDeps
或 MSBuildDeps
已经忽略了 cpp_info
多重配置定义。
You may want to package both debug and release artifacts in the same package, so it can be consumed from IDEs like Visual Studio. This will change the debug/release
configuration from the IDE, without having to specify it in the command line. This type of package can contain different artifacts for different configurations and can be used to include both the release and debug version of a library in the same package.
您可能希望将debug工件和release工件打包在同一个软件包中,以便从 Visual Studio 等集成开发环境中使用。这将从集成开发环境中更改debug/release
配置,而无需在命令行中指定。这种类型的软件包可以包含不同配置的不同工件,并可用于在同一软件包中包含一个库的release版本和debug版本。
A complete working example of the following code can be found in the examples repo: https://github.com/conan-io/examples
以下代码的完整工作示例可在示例库中找到: https://github.com/conan-io/examples
$ git clone https://github.com/conan-io/examples.git
$ cd features/multi_config
$ conan create . user/channel
Creating a multi-configuration debug/release
package is simple
创建多配置debug/release
软件包非常简单
The first step will be to remove build_type
from the settings. It will not be an input setting and the generated package will always contain both debug and release artifacts.
第一步是从设置中移除 build_type
。它将不再是一个输入设置,生成的软件包将始终包含debug和release两部分。
The Visual Studio runtime is different for debug and release (MDd
or MD
) and is set using the default runtime (MD
/MDd
). If this meets your needs, we recommend removing the compiler.runtime
subsetting in the configure()
method:
Visual Studio 运行时对于debug和release(MDd
或MD
)是不同的,并使用默认运行时(MD
/MDd
)进行设置。如果这符合您的需要,我们建议删除 configure()
方法中的 compiler.runtime
子设置:
class HelloConan(ConanFile):
# build_type has been omitted. It is not an input setting.
settings = "os", "compiler", "arch"
generators = "cmake"
# Remove runtime and use always default (MD/MDd)
def configure(self):
if self.settings.compiler == "Visual Studio":
del self.settings.compiler.runtime
def build(self):
cmake_release = CMake(self, build_type="Release")
cmake_release.configure()
cmake_release.build()
cmake_debug = CMake(self, build_type="Debug")
cmake_debug.configure()
cmake_debug.build()
In this example, the binaries will be differentiated with a suffix in the CMake syntax, so we have to add this information to the data provided to the consumers in the package_info
function:
在本例中,二进制文件将通过 CMake 语法中的后缀加以区分,因此我们必须在 package_info
函数中向用户提供的数据中添加这一信息:
set_target_properties(mylibrary PROPERTIES DEBUG_POSTFIX _d)
Such a package can define its information for consumers as:
这样的软件包可以为用户提供以下信息
def package_info(self):
self.cpp_info.release.libs = ["mylibrary"]
self.cpp_info.debug.libs = ["mylibrary_d"]
This will translate to the CMake variables:
这会转化为 CMake 变量:
set(CONAN_LIBS_MYPKG_DEBUG mylibrary_d)
set(CONAN_LIBS_MYPKG_RELEASE mylibrary)
# ...
set(CONAN_LIBS_DEBUG mylibrary_d ${CONAN_LIBS_DEBUG})
set(CONAN_LIBS_RELEASE mylibrary ${CONAN_LIBS_RELEASE})
And these variables will be correctly applied to each configuration by conan_basic_setup()
helper.
这些变量将被 conan_basic_setup()
helper正确应用到每个配置中。
In this case you can still use the general and not config-specific variables. For example, the include directory when set by default to include remains the same for both debug and release. Those general variables will be applied to all configurations.
在这种情况下,你仍然可以使用通用变量,而不是特定于配置的变量。例如,默认设置为 include 时,"include "目录对于debug版本和release版本都是一样的。这些通用变量将应用于所有配置。
The above code assumes that the package will always use the default Visual Studio runtime (MD
/MDd
). To keep the package configurable for supporting static(MT)/dynamic(MD) linking with the VS runtime library, you can do the following:
上述代码假定软件包将始终使用默认的 Visual Studio 运行库 (MD
/MDd
)。要保持软件包的可配置性,以支持与 VS 运行时库的静态(MT)/动态(MD)链接,可以执行以下操作:
compiler.runtime
setting, e.g. do not implement the configure()
method removing it.compiler.runtime
设置,例如,在执行 configure()
方法时不要删除该设置。CONAN_LINK_RUNTIME
variable to define the runtime and define CONAN_LINK_RUNTIME_MULTI
instead.CONAN_LINK_RUNTIME
变量来定义运行时,而应定义 CONAN_LINK_RUNTIME_MULTI
。CONAN_LINK_RUNTIME_MULTI
variable to correctly setup up the runtime for debug and release flags.CONAN_LINK_RUNTIME_MULTI
变量来正确设置debug和release标志的运行时。package_id()
methods for MD/MDd and for MT/MTd defining the packages to be built.package_id()
"方法,定义要构建的软件包。All these steps are already coded in the repo https://github.com/conan-io/examples/tree/master/features/multi_config and commented out as “Alternative 2”.
所有这些步骤都已在 repo https://github.com/conan-io/examples/tree/master/features/multi_config中编码,并注释为 “备选方案 2”。
The automatic conversion of multi-config variables to generators is currently implemented in the cmake
, visual_studio
, txt
, and cmake_find_package
generators (and also for their corresponding _multi
implementations). If you want to have support for them in another build system, please open a GitHub issue.
多重配置变量到生成器的自动转换目前在 cmake
、visual_studio
、txt
和 cmake_find_package
生成器(以及它们相应的 _multi
实现)中实现。如果您希望在其他联编系统中获得对它们的支持,请在 GitHub 上提交问题。
It’s possible that an existing build script is simultaneously building binaries for different configurations, like debug/release, or different architectures (32/64bits), or library types (shared/static). If such a build script is used in the previous “Single configuration packages” approach, it will definitely work without problems. However, we’ll be wasting precious build time, as we’ll be rebuilding the project for each package, then extracting the relevant artifacts for the relevant configuration, while ignoring the others.
现有的编译脚本有可能同时为不同的配置编译二进制文件,如debug/release,或不同的架构(32/64 位),或库类型(共享/静态)。如果在之前的 "单一配置包 "方法中使用这样的编译脚本,肯定会顺利运行。但是,我们将浪费宝贵的构建时间,因为我们将为每个软件包重建项目,然后提取相关配置的相关工件,而忽略其他配置。
It is more efficient to build the logic, whereby the same build can be reused to create different packages:
构建逻辑的效率更高,同样的构建可以重复用于创建不同的软件包:
This can be done by defining a build_id()
method in the package recipe that will specify the logic.
这可以通过在软件包配方中定义一个 "build_id()
"方法来实现,该方法将指定逻辑。
settings = "os", "compiler", "arch", "build_type"
def build_id(self):
self.info_build.settings.build_type = "Any"
def package(self):
if self.settings.build_type == "Debug":
#package debug artifacts
else:
# package release
Note that the build_id()
method uses the self.info_build
object to alter the build hash. If the method doesn’t change it, the hash will match the package folder one. By setting build_type="Any"
, we are forcing that for both the Debug and Release values of build_type
, the hash will be the same (the particular string is mostly irrelevant, as long as it is the same for both configurations). Note that the build hash sha3
will be different of both sha1
and sha2
package identifiers.
请注意,"build_id()
"方法使用 "self.info_build
"对象来更改构建哈希值。如果该方法没有更改,哈希值将与软件包文件夹的哈希值一致。通过设置 build_type="Any"
,我们将强制Debug和 Release 两种 build_type
值的哈希值相同(特定字符串并不重要,只要两种配置的哈希值相同即可)。请注意,编译哈希值 sha3
与软件包标识符 sha1
和 sha2
不同。
This does not imply that there will be strictly one build folder. There will be a build folder for every configuration (architecture, compiler version, etc). So if we just have Debug/Release build types, and we’re producing N packages for N different configurations, we’ll have N/2 build folders, saving half of the build time.
这并不意味着只有一个构建文件夹。每种配置(架构、编译器版本等)都会有一个构建文件夹。因此,如果我们只有 Debug/Release 两种构建类型,并且要为 N 种不同的配置生成 N 个软件包,那么就会有 N/2 个构建文件夹,从而节省一半的构建时间。
Read more about this in build_id().
有关这方面的更多信息,请参阅 build_id() 。