本文档翻译自:https://docs.conan.io/en/latest/reference/conanfile/attributes.html

name

这是一个字符串,至少2个字符,最多50个字符(尽管建议使用较短的名称),用于定义程序包名称。 这将是 <PkgName>/version@user/channel。 它应与以下正则表达式 ^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{1,50}$ 匹配,因此以字母数字或下划线开头,然后是字母数字,下划线,+,。,- 字符。

如果未在命令行中定义配方,则仅将配方export到本地缓存(exportcreate命令)时才需要该名称。 它可能从环境变量甚至是定义它的任何python代码中获取其值(例如,从磁盘读取环境变量的函数或文件)。 但是,最常见和建议的方法是以纯文本形式将其定义为常量,或将其提供为命令行参数。

version

版本属性将定义包引用的版本部分:PkgName/<version>@user/channel 这是一个字符串,可以采用任何值,与name属性匹配相同的约束。如果版本遵循 X.Y.Z-pre1+build2 形式的语义版本控制,则该值可用于通过版本范围而不是确切版本来要求此软件包。

如果未在命令行中定义配方,则仅对于将配方export到本地缓存(exportcreate命令)严格来说是必需的。它可能从环境变量甚至是定义它的任何python代码中获取其值(例如,从磁盘读取环境变量的函数或文件)。请注意,此值可能在其他地方的配方中使用(如在source()方法中从其他位置检索代码的方法),使该值不恒定意味着它可能在不同的上下文中(例如,在不同的机器上或针对不同的用户)导致不可重复或不可预测的结果。最常见和建议的方法是以纯文本形式将其定义为常量,或将其提供为命令行参数。

description

这是一个可选的但强烈建议使用的文本字段,其中包含包装的说明以及可能对消费者有用的任何信息。 第一行可能用作包装的简短说明。

  1. class HelloConan(ConanFile):
  2. name = "hello"
  3. version = "0.1"
  4. description = """This is a Hello World library.
  5. A fully featured, portable, C++ library to say Hello World in the stdout,
  6. with incredible iostreams performance"""

homepage

使用此属性指示要打包的库的主页。 这对于将配方链接到库本身的进一步说明(例如其功能概述,文档,常见问题以及其他相关信息)很有用。

  1. class EigenConan(ConanFile):
  2. name = "eigen"
  3. version = "3.3.4"
  4. homepage = "http://eigen.tuxfamily.org"

url

如果要打包第三方库,则即使是典型的情况,也可能只是开发打包代码。 此类代码通常也会通过协作进行更改,因此应将其存储在git之类的VCS中,并可能放在GitHub或类似服务上。 如果确实要维护这样的存储库,请在url属性中指出它,以便可以轻松找到它。

  1. class HelloConan(ConanFile):
  2. name = "hello"
  3. version = "0.1"
  4. url = "https://github.com/conan-io/hello.git"

网址是软件包存储库的网址,即不一定是原始源代码。 它是可选的,但强烈建议它指向GitHub,Bitbucket或您首选的代码协作平台。 当然,如果库源代码中包含conanfile,则可以指向它,然后在source()方法中使用url
这是推荐属性,但不是必需属性。

license

此字段用于目标源代码和二进制文件(即正在打包的代码)的许可证,而不是conanfile.py本身的许可证。 此信息通常由conan info命令以及其他搜索和报告工具显示。

  1. class HelloConan(ConanFile):
  2. name = "hello"
  3. version = "0.1"
  4. license = "MIT"

此属性可以包含多个逗号分隔的许可证。 它是一个文本字符串,因此可以包含任何文本,包括指向其他地方的许可证文件的超链接。
但是,我们强烈建议开源项目的打包人员使用SPDX许可证列表)中的SPDX)标识符,而不要使用 free-formed 的文本。 这将帮助希望自动进行许可证兼容性检查的人员,例如您的软件包的使用者,或者您的软件包具有开放源代码依赖项。
这是推荐属性,但不是必需属性。

author

旨在添加有关作者的信息,以防与conan用户不同。 conan用户可能是组织,项目,公司或组的名称,并且许多用户对该帐户具有权限。 在这种情况下,作者信息可以明确定义谁是包的创建者/维护者。

  1. class HelloConan(ConanFile):
  2. name = "hello"
  3. version = "0.1"
  4. author = "John J. Smith (john.smith@company.com)"

这是一个可选属性。

topics

主题提供了一种有用的方式来将相关标签分组在一起,并快速告诉开发人员软件包的含义。 主题还使客户更容易找到您的配方。 按主题过滤软件包或在Bintray软件包页面中重用它们可能很有用。
topic属性应该是一个包含所需主题的元组。

  1. class ProtocInstallerConan(ConanFile):
  2. name = "protoc_installer"
  3. version = "0.1"
  4. topics = ("protocol-buffers", "protocol-compiler", "serialization", "rpc")

这是一个可选属性。

user, channel

这些字段在conan中是可选的,它们对于从社区中识别出针对您公司的更改的分支配方很有用。 使用这些字段,您可以保持相同的名称和版本,并使用用户/渠道来消除配方的歧义。
这些字段的值可以在conanfile.py中访问:

  1. from conans import ConanFile
  2. class HelloConan(ConanFile):
  3. name = "hello"
  4. version = "0.1"
  5. def requirements(self):
  6. self.requires("common-lib/version")
  7. if self.user and self.channel:
  8. # If the recipe is using them, I want to consume my fork.
  9. self.requires("say/0.1@%s/%s" % (self.user, self.channel))
  10. else:
  11. # otherwise, I'll consume the community one
  12. self.requires("say/0.1")

只有已经导出的软件包(本地缓存或远程服务器中的软件包)才能分配 user/channel 。 对于在用户空间中工作的软件包配方,默认情况下没有当前user/channel ,尽管可以在**conan install**时使用以下命令定义它们:

  1. $ conan install <path to conanfile.py> user/channel

:::success Warning
现在已弃用了用于为这些字段分配值的环境变量CONAN_USERNAME和CONAN_CHANNEL,并将在Conan 2.0中将其删除。 不要使用它们来填充self.user和self.channel的值。 :::

default_user, default_channel

对于在用户空间中工作的软件包配方,请使用本地方法如 conan install .conan build .,没有当前的user/channel。如果要在配方中访问self.userself.channel,则需要声明环境变量CONAN_USERNAMECONAN_CHANNEL,或者可以设置属性default_userdefault_channel。 您也可以使用python @property:

  1. from conans import ConanFile
  2. class HelloConan(ConanFile):
  3. name = "hello"
  4. version = "0.1"
  5. default_user = "myuser"
  6. @property
  7. def default_channel(self):
  8. return "mydefaultchannel"
  9. def requirements(self):
  10. self.requires("pkg/0.1@%s/%s" % (self.user, self.channel))

settings

有几件事可能会影响正在创建的程序包,即如果某些输入不同,则最终程序包也会有所不同(例如,不同的二进制文件)。
开发项目范围的变量,例如编译器,其版本或OS本身。 必须定义这些变量,并且它们不能在conanfile中列出默认值,因为这没有意义。
很明显,在大多数情况下,更改操作系统会生成不同的二进制文件。 更改编译器或编译器版本也会更改二进制文件,二进制文件可能具有兼容的ABI,但在任何情况下软件包都将有所不同。
由于这些原因,conan配方中最常见的约定是通过以下四个设置来区分二进制文件,这反映在柯南新命令中使用的conanfile.py模板中:

  1. settings = "os", "compiler", "build_type", "arch"

当conan为具有上述设置的给定组合的软件包生成已编译的二进制文件时,它会通过散列这些设置的当前值来为该二进制文件生成唯一的ID。
但是,例如仅标头库会发生什么呢? 这种库的最终软件包不是二进制的,并且在大多数情况下,它们是相同的,除非它是自动生成代码的。 我们可以在conanfile中指出:

  1. from conans import ConanFile
  2. class HelloConan(ConanFile):
  3. name = "hello"
  4. version = "0.1"
  5. # We can just omit the settings attribute too
  6. settings = None
  7. def build(self):
  8. #empty too, nothing to build in header only

您还可以通过重新声明settings属性来限制现有设置和可接受的值:

  1. class HelloConan(ConanFile):
  2. settings = {"os": ["Windows"],
  3. "compiler": {"Visual Studio": {"version": [11, 12]}},
  4. "arch": None}

在此示例中,我们刚刚定义了该程序包仅在Windows 10,VS 10和11下运行。尝试在具有其他设置的其他平台上构建该程序包将引发错误。 我们还定义了运行时(VS的MD和MT标志)与我们无关(也许我们使用的是通用的?)。 使用无作为值表示保持原始值,以避免重新键入它们。 然后,” arch”:None完全等同于” arch”:[“ x86”,” x86_64”,” arm”]检查引用或您的〜/ .conan / settings.yml文件。

由于重新定义整个设置属性可能很乏味,因此有时在configure()方法中删除或调整特定字段要简单得多。 例如,如果我们的程序包在VS中与运行时无关,则可以删除该设置字段:

  1. settings = "os", "compiler", "build_type", "arch"
  2. def configure(self):
  3. self.settings.compiler["Visual Studio"].remove("runtime")

可以使用属性语法检查设置以实现条件逻辑:

  1. def build(self):
  2. if self.settings.os == "Windows" and self.settings.compiler.version == "15":
  3. # do some special build commands
  4. elif self.settings.arch == "x86_64":
  5. # Other different commands

这些比较会进行内容检查,例如,如果您输入self.settings.os =="Windos"这样的错字,Conan将会失败并告诉您这不是有效的settings.os值,以及可能的值范围。

同样,如果您尝试访问不存在的某些设置(例如Visual Studio设置的self.settings.compiler.libcxx),则conan 将无法告知该编译器不存在libcxx

如果要对设置值进行安全检查,可以使用get_safe()方法:

  1. def build(self):
  2. # Will be None if doesn't exist
  3. arch = self.settings.get_safe("arch")
  4. # Will be None if doesn't exist
  5. compiler_version = self.settings.get_safe("compiler.version")
  6. # Will be the default version if the return is None
  7. build_type = self.settings.get_safe("build_type", default="Release")

如果该设置或子设置不存在并且未分配默认值,则get_safe()方法将返回None

options

当使用不同的设置时,conan软件包的配方可以生成不同的二进制软件包,但也可以自定义每个软件包的配置,从而生成不同的二进制文件。

一个特定的库通常是共享的或静态的。 请注意,这是可选的,不同的软件包可以具有此选项,也可以不具有(例如,仅标头的软件包),并且不同的软件包可以对此选项具有不同的值,而设置则通常与所有安装的软件包具有相同的值 (尽管也可以控制,为特定的程序包定义不同的设置)

选项在软件包配方中定义为名称和允许值的字典:

  1. class MyPkg(ConanFile):
  2. ...
  3. options = {"shared": [True, False]}

选项被定义为ConanFile内的python字典,其中每个键必须是带有选项标识符的字符串,并且值是包含所有可能选项值的列表:

  1. class MyPkg(ConanFile):
  2. ...
  3. options = {"shared": [True, False],
  4. "option1": ["value1", "value2"],}

可以输入每个选项的值或纯字符串,对于可以采用任何值的选项,都有一个特殊值ANY。

如果使用者(通过命令行使用配方,项目,配置文件或用户)未定义选项,则属性default_options的目的是定义选项的默认值。 值得注意的是,未初始化的选项将获得值None,并且如果其包含在有效值列表中,则它将是有效值。 该属性也应定义为python字典,尽管由于遗留原因其他定义也可能有效。

  1. class MyPkg(ConanFile):
  2. ...
  3. options = {"shared": [True, False],
  4. "option1": ["value1", "value2"],
  5. "option2": "ANY"}
  6. default_options = {"shared": True,
  7. "option1": "value1",
  8. "option2": 42}
  9. def build(self):
  10. shared = "-DBUILD_SHARED_LIBS=ON" if self.options.shared else ""
  11. cmake = CMake(self)
  12. self.run("cmake . %s %s" % (cmake.command_line, shared))
  13. ...

如前所述,可以使用不同的方式来定义配方中选项的值,让我们遍历上面定义的示例配方mypkg的所有选项:

  • 在配方本身中使用属性default_options。
  • 在需要使用此配方的配方的default_options中:此处定义的值将覆盖配方中的默认值。
    1. class OtherPkg(ConanFile):
    2. requires = "mypkg/0.1@user/channel"
    3. default_options = {"mypkg:shared": False}
    当然,这将与使用conanfile.txt的方式相同: ```python [requires] mypkg/0.1@user/channel

[options] mypkg:shared=False

  1. - 也可以使用配置文件为配方的选项定义默认值。 只要使用该配方,它们就会适用:
  2. ```python
  3. # file "myprofile"
  4. # use it as $ conan install -pr=myprofile
  5. [settings]
  6. setting=value
  7. [options]
  8. MyPkg:shared=False

定义选项值(所有选项的优先级最高)的最后一种方法是在命令行中使用命令参数-o传递这些值:

  1. $ conan install . -o MyPkg:shared=True -o OtherPkg:option=value

options的值也可以在configure()config_options()方法中有条件地赋值(甚至删除),相应的部分有记录这些用例的示例。 但是,有条件地将值分配给选项可能会有其缺点,如母版部分中所述。

一个重要的注意事项是如何评估这些选项的值以及我们可以在Python中实现的不同条件的行为。 如前所述,可以在Python代码中(将字典分配给default_options)或通过字符串(使用conanfile.txt,配置文件或通过命令行)来定义选项的值。 为了提供一致的实施,请考虑以下注意事项:

  • 类型值和字符串的求值相同,因此所有这些输入的行为都相同:

    • default_options = {"shared": True, "option": None}
    • default_options = {"shared": "True", "option": "None"}
    • mypkg:shared=Truemypkg:option = None在配置文件,命令行或conanfile.txt上均不存在
  • 隐式转换为boolean不区分大小写,因此表达式bool(self.options.option):

    • 对于值True,” True”和” true”以及在Python代码中将以相同方式求值的任何其他值,等于True。
    • 对于值False,” False”和” false”,空字符串以及预期的0和” 0”,等于False。
  • 使用is进行比较始终等于False,因为选项类型封装在Conan类中时,类型会有所不同。

  • 与==符号的显式比较区分大小写,因此:
    • self.options.option = "False"满足assert self.options.option == Falseassert self.options.option == "False",但 assert self.options.option != "false"
  • 不同的行为具有self.options.option = None,因为assert self.options.option!= None

如果要对选项值进行安全检查,则可以使用get_safe()方法:

  1. def build(self):
  2. # Will be None if doesn't exist
  3. fpic = self.options.get_safe("fPIC")
  4. # Will be the default version if the return is None
  5. shared = self.options.get_safe("shared", default=False)

如果该选项不存在并且未分配默认值,则get_safe()方法将返回None