创建conan包-定义软件包信息
本文是基于对conan官方文档Define the package information翻译而来, 更详细的信息可以去查阅conan官方文档。
1 Define the package information
When creating a recipe to package a library, it is important to define the information about the package so consumers can get the information correctly. Conan achieves this by decoupling the information of the package from the format needed using Generators, that translate the generic information into the appropriate format file.
在创建对库进行打包的配方时,必须定义包的相关信息,以便用户能够正确获取信息。conan通过使用生成器将软件包信息与所需格式解耦来实现这一点,生成器可将通用信息转换为适当的格式文件。
This generic information is defined inside the recipe, using the package_info()
method. There you can declare package information like the location of the header files, library names, defines, flags…
这些通用信息通过 package_info()
方法在配方中定义。在这里,你可以声明包信息,如头文件的位置、库名、定义、标志…
from conans import ConanFile
class MyConan(ConanFile):
name = "cool_library"
...
def package_info(self):
self.cpp_info.includedirs = ["include/cool"]
self.cpp_info.libs = ["libcool"]
self.cpp_info.defines = ["DEFINE_COOL=1"]
The package information is done using the attributes of the cpp_info
object. This information will be aggregated by Conan and exposed via self.deps_cpp_info
to consumers and generators.
软件包信息是通过 cpp_info
对象的属性完成的。Conan 将汇总这些信息,并通过 self.deps_cpp_info
向用户和生成器公开。
Important
This information is important as it describes the package contents in a generic way with a pretty straightforward syntax that can later be translated to a suitable format. The advantage of having this information here, is that the package could be consumed from a different build system that the one used to compile the library. For example, a library that builds using Autotools can be consumed later in CMake with this information using any of the CMake generators.
这些信息非常重要,因为它以通用的方式描述了软件包的内容,语法非常简单,以后可以翻译成合适的格式。在这里提供这些信息的好处是,可以从与编译库所使用的构建系统不同的构建系统中使用软件包。例如,使用 Autotools 构建的库可以在 CMake 中使用任何 CMake 生成器,并在随后使用这些信息。
See also
Read package_info() to learn more about this method.
阅读 package_info() 了解有关此方法的更多信息。
1.1 Using Components
If your package contains more than one library or you want to define separated components so consumers can have more granular information, you can use components in your package_info()
method.
如果您的软件包包含一个以上的库,或者您想定义分离的组件,以便用户可以获得更详细的信息,您可以在package_info()
方法中使用组件。
When you are creating a Conan package, it is recommended to have only one library (.lib, .a, .so, .dll…) per package. However, especially with third-party projects like Boost, Poco or OpenSSL, they would contain several libraries inside.
创建conan软件包时,建议每个软件包只包含一个库(.lib、.a、.so、.dll…)。不过,特别是像 Boost、Poco 或 OpenSSL 这样的第三方项目,它们内部会包含多个库。
Usually those libraries inside the same package depend on each other and modelling the relationship among them is required.
通常情况下,同一软件包中的这些库相互依赖,因此需要对它们之间的关系进行建模。
With components, you can model libraries and executables inside the same package and how one depends on the other. Each library or executable will be one component inside cpp_info
like this:
有了组件,你就可以对同一软件包内的库和可执行文件进行建模,并了解其中一个如何依赖于另一个。每个库或可执行文件都是 cpp_info
中的一个组件,就像这样:
def package_info(self):
self.cpp_info.names["cmake_find_package"] = "OpenSSL"
self.cpp_info.names["cmake_find_package_multi"] = "OpenSSL"
self.cpp_info.components["crypto"].names["cmake_find_package"] = "Crypto"
self.cpp_info.components["crypto"].libs = ["libcrypto"]
self.cpp_info.components["crypto"].defines = ["DEFINE_CRYPTO=1"]
self.cpp_info.components["ssl"].names["cmake"] = "SSL"
self.cpp_info.components["ssl"].includedirs = ["include/headers_ssl"]
self.cpp_info.components["ssl"].libs = ["libssl"]
self.cpp_info.components["ssl"].requires = ["crypto"]
You can define dependencies among different components using the requires
attribute and the name of the component. The dependency graph for components will be calculated and values will be aggregated in the correct order for each field.
您可以使用 requires
属性和组件名称定义不同组件之间的依赖关系。组件的依赖关系图将被计算出来,每个字段的值将按照正确的顺序汇总。
def package_info(self):
self.cpp_info.components["LibA"].libs = ["liba"] # Name of the library for the 'LibA' component
self.cpp_info.components["LibA"].requires = ["LibB"] # Requires point to the name of the component
self.cpp_info.components["LibB"].libs = ["libb"]
self.cpp_info.components["LibC"].libs = ["libc"]
self.cpp_info.components["LibC"].requires = ["LibA"]
self.cpp_info.components["LibD"].libs = ["libd"]
self.cpp_info.components["LibD"].requires = ["LibA"]
self.cpp_info.components["LibE"].libs = ["libe"]
self.cpp_info.components["LibE"].requires = ["LibB"]
self.cpp_info.components["LibF"].libs = ["libf"]
self.cpp_info.components["LibF"].requires = ["LibD", "LibE"]
For consumers and generators, the order of the libraries from this components graph will be:
对于消费者和生成者来说,组件图中库的排列顺序为:
self.deps_cpp_info.libs == ["libf", "libe", "libd", "libc", "liba", "libb"]
Declaration of requires from other packages is also allowed:
也允许声明其他软件包的要求:
class MyConan(ConanFile):
...
requires = "zlib/1.2.11", "openssl/1.1.1g"
def package_info(self):
self.cpp_info.components["comp1"].requires = ["zlib::zlib"] # Depends on all components in zlib package
self.cpp_info.components["comp2"].requires = ["comp1", "openssl::ssl"] # Depends on ssl component in openssl package
By default, components won’t link against any other package required by the recipe. The requires list has to be populated explicitly with the list of components from other packages to use: it can be the full requirement (zlib::zlib) or a single component (openssl::ssl).
默认情况下,组件不会链接到配方所需的任何其他软件包。需要使用其他软件包中的组件列表来明确填充 requires
列表:它可以是完整的需求(zlib::zlib
),也可以是单个组件(openssl::ssl
)。
Important
The information of components is aggregated to the global cpp_info
scope and the usage of components should be transparent.
组件的信息汇总到全局的 cpp_info
范围,组件的使用应该是透明的。
Consumers can get this information via self.deps_cpp_info
as usual and use it in the build()
method of any dependent recipe:
用户可以像往常一样通过 self.deps_cpp_info
获取此信息,并在任何依赖配方的 build()
方法中使用:
class PocoTimerConan(ConanFile):
...
requires = "zlib/1.2.11", "openssl/1.0.2u"
...
def build(self):
# Get the include directories of the SSL component of openssl package
self.deps_cpp_info["openssl"].components["ssl"].include_paths
Recipes that require packages that declare components can also take advantage of this granularity, they can declare in the cpp_info.requires
attribute the list of components from the requirements they want to link with:
需要声明组件的软件包的配方也可以利用这种粒度,它们可以在 cpp_info.requires
属性中声明它们想要链接的需求中的组件列表:
class Library(ConanFile):
name = 'library'
requires = "openssl/1.0.2u"
def package_info(self):
self.cpp_info.requires = ['openssl::ssl']
In the previous example, the ‘library’ package and transitively all its consumers will link only with the component ssl from the openssl package.
在上例中,"library "软件包及其所有用户只能链接 openssl
软件包中的 ssl
组件。
See also
Read components reference for more information.