本文档翻译自:https://docs.conan.io/en/latest/creating_packages/package_information.html

创建用于类库包的配方时,重要的是定义有关包装的信息,以便消费者可以正确获取信息。 Conan通过将生成器的信息与使用Generators所需的格式解耦来实现此目的,Generators将通用信息转换为适当的格式文件。
使用package_info()方法在配方内部定义此通用信息。 在这里,您可以声明包信息,例如头文件的位置,库名,定义,标志……

  1. from conans import ConanFile
  2. class MyConan(ConanFile):
  3. name = "cool_library"
  4. ...
  5. def package_info(self):
  6. self.cpp_info.includedirs = ["include/cool"]
  7. self.cpp_info.libs = ["libcool"]
  8. self.cpp_info.defines= ["DEFINE_COOL=1"]

包信息使用cpp_info对象的属性完成。此信息将由Conan汇总,并通过self.deps_cpp_info向消费者和生成器公开。

:::info Important
该信息非常重要,因为它以一种非常简单的语法以通用的方式描述了包装内容,随后可以将其转换为合适的格式。 在这里拥有此信息的优点是,可以从用于编译该库的另一种构建系统中使用该软件包。 例如,使用Autotools构建的库可以稍后在CMake中使用任何CMake生成器使用此信息来使用。 :::

使用组件

如果您的程序包包含多个库,或者您想定义单独的组件,以便使用者可以使用更详细的信息,则可以在package_info()方法中使用组件。

:::success Waring
这是一项实验性功能,可能会在将来的发行版中进行重大更改。 :::

创建Conan软件包时,建议每个软件包仅包含一个库(.lib,.a,.so,.dll…)。 但是,特别是对于Boost,Poco或OpenSSL等第三方项目,它们将在其中包含多个库。
通常,同一包中的那些库相互依赖,并且需要对它们之间的关系进行建模。
使用组件,您可以在同一程序包中对库和可执行文件进行建模,以及它们如何相互依赖。 每个库或可执行文件都是cpp_info中的一个组件,如下所示:

  1. def package_info(self):
  2. self.cpp_info.name = "OpenSSL"
  3. self.cpp_info.components["crypto"].names["cmake_find_package"] = "Crypto"
  4. self.cpp_info.components["crypto"].libs = ["libcrypto"]
  5. self.cpp_info.components["crypto"].defines = ["DEFINE_CRYPTO=1"]
  6. self.cpp_info.components["ssl"].names["cmake"] = "SSL"
  7. self.cpp_info.components["ssl"].includedirs = ["include/headers_ssl"]
  8. self.cpp_info.components["ssl"].libs = ["libssl"]
  9. self.cpp_info.components["ssl"].requires = ["crypto"]

您可以使用require属性和组件名称定义不同组件之间的依赖关系。 将为每个字段计算组件的依赖性图,并以正确的顺序汇总值。

  1. def package_info(self):
  2. self.cpp_info.components["LibA"].libs = ["liba"] # Name of the library for the 'LibA' component
  3. self.cpp_info.components["LibA"].requires = ["LibB"] # Requires point to the name of the component
  4. self.cpp_info.components["LibB"].libs = ["libb"]
  5. self.cpp_info.components["LibC"].libs = ["libc"]
  6. self.cpp_info.components["LibC"].requires = ["LibA"]
  7. self.cpp_info.components["LibD"].libs = ["libD"]
  8. self.cpp_info.components["LibD"].requires = ["LibA"]
  9. self.cpp_info.components["LibE"].libs = ["libe"]
  10. self.cpp_info.components["LibE"].requires = ["LibB"]
  11. self.cpp_info.components["LibF"].libs = ["libf"]
  12. self.cpp_info.components["LibF"].requires = ["LibD", "LibE"]

对于使用者和生成器,此组件图中的库顺序为:

  1. self.deps_cpp_info.libs == ["libf", "libe", "libd", "libc", "liba", "libb"]

还允许从其他包中声明要求:

  1. class MyConan(ConanFile):
  2. ...
  3. requires = "zlib/1.2.11", "openssl/1.1.1g"
  4. def package_info(self):
  5. self.cpp_info.components["comp1"].requires = ["zlib::zlib"] # Depends on all components in zlib package
  6. self.cpp_info.components["comp2"].requires = ["comp1", "openssl::ssl"] # Depends on ssl component in openssl package

默认情况下,组件不会链接到配方所需的任何其他软件包。 必须使用要使用的其他软件包中的组件列表来显式填充require列表:它可以是完整需求(zlib::zlib)或单个组件(openssl::ssl)。

:::info Important
组件的信息汇总到全局cpp_info范围,并且组件的使用应透明。 :::

消费者可以照常通过self.deps_cpp_info获取此信息,并将其用于任何依赖配方的build()方法中:

  1. class PocoTimerConan(ConanFile):
  2. ...
  3. requires = "zlib/1.2.11", "openssl/1.0.2u"
  4. ...
  5. def build(self):
  6. # Get the include directories of the SSL component of openssl package
  7. self.deps_cpp_info["openssl"].components["ssl"].include_paths