bitbake手册

前言

  • 本文是 bitbake 官方文档的翻译。 https://docs.yoctoproject.org/bitbake/2.6/index.html
  • 一些地方我觉得没必要翻译,以省略号代替。
  • 一部分内容用了机器翻译,遇到无法理解处,请参考原始文档。
  • 在一些地方插入了我个人的理解。标有“注”的内容是我加的。

1 Overview

见 https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-intro.html

2 Execution

在local.conf中设置 BB_NUMBER_THREADS ,指定并行任务线程数。
可以用 grep processor /proc/cpuinfoncpus 命令获得cpu数量。

2.1 Parsing the Base Configuration Metadata

BitBake做的第一件事是解析基本配置元数据。基本配置元数据包括项目的bblayers.conf文件,用于确定BitBake需要识别的层,所有必要的layer.conf文件(每个层一个),以及bitbake.conf。数据本身有各种类型

注:
bblayers.conf 在 build/conf/ 目录中。
bitbake.conf 和 layer.conf 在 meta 及 meta-xxx 目录中。

  • Recipes:关于特定软件的详细信息。
  • Class Data:通用构建信息的抽象(例如,如何构建Linux内核)。
  • Configuration Data:机器特定的设置、策略决策等。配置数据是将所有内容绑定在一起的粘合剂。

layer.conf 文件用于构建 BBPATH 和 BBFILES 等关键变量。 BBPATH 用于分别在 conf 和 classes 目录下搜索配置和类文件。 BBFILES 用于定位配方和配方附加文件(.bb 和 .bbappend)。如果没有 bblayers.conf 文件,则假设用户已经在环境中直接设置了 BBPATH 和 BBFILES。

接下来,使用刚刚构造的BBPATH变量查找bitbake.conf文件。bitbake.conf文件还可能包含使用include或require指令的其他配置文件。

在解析配置文件之前,BitBake会查看某些变量,包括

  • BB_ENV_PASSTHROUGH
  • BB_ENV_PASSTHROUGH_ADDITIONS
  • BB_PRESERVE_ENV
  • BB_ORIGENV
  • BITBAKE_UI

基本配置元数据是全局的,因此会影响所有执行的配方和任务。

BitBake 首先在当前工作目录中搜索可选的 conf/bblayers.conf 配置文件。该文件应包含一个 BBLAYERS 变量,该变量是一个以空格分隔的“layer”目录列表。回想一下,如果 BitBake 找不到 bblayers.conf 文件,则假设用户已直接在环境中设置了 BBPATH 和 BBFILES 变量。

对于此列表中的每个目录(层),都有一个conf/layer.conf文件,并且解析了LAYERDIR变量,该变量被设置为找到该层的目录。其想法是这些文件自动为给定的构建目录正确设置BBPATH和其他变量。

然后,BitBake 会在用户指定的 BBPATH 中的某个位置找到 conf/bitbake.conf 文件。该配置文件通常包含 include 指令,用于引入任何其他元数据,例如特定于体系结构、机器、本地环境等的文件。

BitBake .conf 文件中只允许使用变量定义和 include 指令。一些变量直接影响 BitBake 的行为。这些变量可能已根据之前提到的环境变量或配置文件中的设置从环境中设置。 “变量词汇表”一章提供了完整的变量列表。

注:
看起来是这样的流程:
首先解析 build/conf/bblayers.conf
然后沿着 bblayers.conf 中指定的 LAYERDIR 变量找到每个 layer 中的 conf/layer.conf 文件。
layer 中的 conf/layer.conf 文件配置 BBPATH 和 BBFILES 。
接下来按照 BBPATH 寻找 bitbake.conf 文件

在解析配置文件后,BitBake使用其基本的继承机制(通过类文件)来继承一些标准类。当遇到负责获取该类的继承指令时,BitBake会解析一个类。

base.bbclass文件始终包含在内。使用INHERIT变量在配置中指定的其他类也包含在内。BitBake以与配置文件相同的方式在BBPATH中的路径下的classes子目录中搜索类文件。


base.bbclass 会自动被包含,不需要显式指定。

了解执行环境中使用的配置文件和类文件的一个好方法是运行以下 BitBake 命令

$ bitbake -e > mybb.log

查看mybb.log的顶部,可以显示在执行环境中使用的许多配置文件和类文件。

您需要了解 BitBake 如何解析花括号。如果配方在函数中使用一个结束花括号,并且该字符没有前导空格,BitBake 会产生解析错误。如果您在 shell 函数中使用一对花括号,则结束花括号不得位于没有前导空格的行首。

2.2 Locating and Parsing Recipes

在配置阶段,BitBake将设置BBFILES。BitBake现在使用它来构建要解析的配方列表,以及要应用的任何附加文件(.bbappend)。BBFILES是一个以空格分隔的可用文件列表,支持通配符。例如

BBFILES = "/path/to/bbfiles/*.bb /path/to/appends/*.bbappend"

BitBake解析每个配方并附加BBFILES中的文件,并将各种变量的值存储到数据存储中。

Append files are applied in the order they are encountered in BBFILES.

对于每个文件,都会生成一份基础配置的副本,然后逐行解析配方。任何继承语句都会导致 BitBake 使用 BBPATH 作为搜索路径来查找并解析类文件(.bbclass)。最后,BitBake 会按顺序解析在 BBFILES 中找到的任何附加文件。

一个常见的惯例是使用配方文件名来定义元数据。例如,在bitbake.conf中,使用配方名称和版本来设置变量PN和PV

PN = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
PV = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"

在这个例子中,一个名为“something_1.2.3.bb”的配方会将PN设置为“something”,将PV设置为“1.2.3”。

注:
解析配方时会重新解析 .bbclass 文件。 这样可以针对不同的配方生成不同的 PN PV 以及其他变量。

当一个配方解析完成时,BitBake会得到一个配方定义的任务列表,以及一组由键值和任务依赖信息组成的数据。

BitBake不需要所有这些信息。它只需要一小部分信息来决定配方。因此,BitBake缓存了它感兴趣的值,而没有存储其余的信息。经验表明,重新解析元数据比尝试将其写入磁盘然后重新加载更快。

在可能的情况下,后续的 BitBake 命令会重用此配方信息的缓存。此缓存的有效性取决于首先计算基本配置数据的校验和(请参阅 BB_HASHCONFIG_ignore_VARS),然后检查校验和是否匹配。如果校验和与缓存中的内容匹配,并且配方和类文件没有更改,则 BitBake 能够使用该缓存。然后,BitBake 会重新加载缓存的配方信息,而不是从头开始重新解析。

配方文件集合的存在是为了允许用户拥有多个包含相同确切软件包的 .bb 文件存储库。例如,人们可以很容易地使用它们来制作上游存储库的本地副本,但可以进行上游不想要的自定义修改。 下面是一个例子:

BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
BBFILE_COLLECTIONS = "upstream local"
BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
BBFILE_PRIORITY_upstream = "5"
BBFILE_PRIORITY_local = "10"

分层机制现在是收集代码的首选方法。虽然收集代码仍然存在,但其主要用途是设置层优先级和处理层之间的重叠(冲突)。

2.3 Providers

假设 BitBake 已指示执行目标,并且已解析所有配方文件,BitBake 开始研究如何构建目标。 BitBake 浏览每个配方的 PROVIDES 列表。 PROVIDES 列表是配方的名称列表。每个配方的 PROVIDES 列表可以通过配方的 PN 变量隐式创建,也可以通过配方的 PROVIDES 变量显式创建,该变量是可选的。

当配方使用 PROVIDES 时,可以在隐式 PN 名称以外的其他名称下找到该配方的功能。例如,假设名为 keyboard_1.0.bb 的配方包含以下内容:

PROVIDES += "fullkeyboard"

此配方的 PROVIDES 列表变为“keyboard”,这是隐式的,而“fullkeyboard”是显式的。因此,在 keyboard_1.0.bb 中的功能用这两个名称都可以找到。

2.4 Preferences (偏爱)

PROVIDES 列表只是确定目标配方解决方案的一部分。由于目标可能拥有多个提供者,BitBake 需要通过确定提供者首选项来区分提供者的优先级。

目标具有多个提供者的常见示例是“virtual/kernel”,它在每个内核配方的PROVIDES列表中。每台机器通常通过在机器配置文件中使用类似于以下行来选择最佳内核提供者

PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"

默认的 PREFERRED_PROVIDER 是与目标同名的提供者。BitBake 会迭代它需要构建的每个目标,并使用此过程解析它们及其依赖关系。

由于给定提供商可能存在多个版本,因此了解如何选择提供商变得复杂。BitBake默认为提供商的最高版本。版本比较使用与Debian相同的方法进行。您可以使用preferred_version变量指定特定版本。您可以使用default_preference变量影响顺序。

默认情况下,文件的首选为“0”。将DEFAULT_Preference设置为“-1”将使该配方不太可能被使用,除非它被明确引用。将DEFAULT_Preference设置为“1”将使该配方更有可能被使用。preferred_version会覆盖任何DEFAULT_Preference设置。DEFAULT_Preference通常用于标记更新和更实验性的配方版本,直到它们经过充分测试被认为稳定为止。

当给定配方有多个“版本”时,BitBake 默认选择最新版本,除非另有说明。如果所讨论的配方将 DEFAULT_PREFERENCE 设置为低于其他配方的值(默认值为 0),则不会选择该版本。这允许维护配方文件库的人员指定他们对默认选定版本的偏好。此外,用户可以指定他们的首选版本。

如果第一个配方命名为 a_1.1.bb,则 PN 变量将设置为“a”,PV 变量将设置为 1.1。

因此,如果名为 a_1.2.bb 的配方存在,BitBake 默认会选择 1.2。但是,如果您在 BitBake 解析的 .conf 文件中定义了以下变量,则可以更改该首选项

PREFERRED_VERSION_a = "1.1"

一个配方通常有两个版本——一个稳定的、编号的(也是首选的)版本,以及一个从源代码库中自动检出的版本,该版本被认为更“bleeding edge” ,但只能明确选择。

例如,在 OpenEmbedded 代码库中,BusyBox 有一个标准的、版本化的配方文件,即 busybox_1.22.1.bb,但还有一个基于 Git 的版本,即 busybox_git.bb,其中明确包含了以下行

DEFAULT_PREFERENCE = "-1"

除非开发人员另有选择,否则应始终首选编号的稳定版本。

2.5 Dependencies

每个目标 BitBake 构建都由多个任务组成,例如 fetch、 unpack、 patch、 configure 和 compile。为了在多核系统中获得最佳性能,BitBake 将每个任务视为具有自己依赖关系的独立实体。

依赖关系是通过几个变量定义的。您可以在本手册末尾附近的变量术语表中找到有关BitBake使用的变量的信息。在基本层面上,知道BitBake在计算依赖关系时使用 DEPENDS 和 RDEPENDS 变量就足够了。

注:
https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-ref-variables.html#term-DEPENDS
https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-ref-variables.html#term-RDEPENDS

有关 BitBake 如何处理依赖关系的更多信息,请参阅依赖关系部分。

注:
https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-metadata.html#dependencies

2.6 The Task List

基于生成的提供者列表和依赖关系信息,BitBake 现在可以准确计算出需要运行哪些任务以及需要按什么顺序运行它们。 Executing Tasks 章节提供了有关 BitBake 如何选择接下来执行哪个任务的更多信息。

BitBake创建线程执行构建任务,直到 BB_NUMBER_THREADS 变量中设置的限制。 只要任务已准备好运行,这些任务的所有依赖关系都得到满足,并且未超过线程阈值,BitBake 就会继续fork线程。

值得注意的是,通过正确设置 BB_NUMBER_THREADS 变量,可以大大加快构建时间。

当每个任务完成时,一个时间戳被写入由 STAMP 变量指定的目录。 在后续运行中,BitBake会在 tmp/stamps 中的构建目录中查找,除非发现时间戳无效,否则不会重新运行已经完成的任务。目前,仅在每个配方文件的基础上考虑无效的时间戳。因此,例如,如果配置时间戳的时间戳大于给定目标的编译时间戳,则编译任务将重新运行。然而,再次运行编译任务对依赖于该目标的其他提供者没有影响。

时间戳的确切格式是部分可配置的。 在 BitBake 的现代版本中,时间戳附加了哈希值,因此如果配置更改,时间戳将变为无效,任务将自动重新运行。 所使用的哈希值或签名受配置的签名策略的约束(有关信息,请参阅 Checksums (Signatures)章节)。 还可以使用 [stamp-extra-info] 任务标记在戳记中附加额外的元数据。 例如,OpenEmbedded 使用此标记使某些特定于机器的任务。

一些任务被标记为“nostamp”任务。运行这些任务时不会创建时间戳文件。因此,“nostamp”任务总是会重新运行。

有关任务的更多信息,请参阅 Task 章节。

2.7 Executing Tasks

任务可以是 shell 任务或 Python 任务。对于 shell 任务,BitBake 会将 shell 脚本写入 ${T}/run.do_taskname.pid,然后执行该脚本。生成的shell脚本包含所有导出的变量,以及所有变量展开的shell函数。shell脚本的输出将保存到文件${T}/log.do_taskname.pid。一种 debug 技巧是,在 run 文件中查看 shell 函数,在 log 文件中查看输出。

对于 Python 任务,BitBake 在内部执行任务并将信息记录到控制终端。 BitBake 的未来版本将把函数写入文件,类似于处理 shell 任务的方式。日志记录也将以类似于 shell 任务的方式处理。

BitBake运行任务的顺序由其任务调度器控制。可以配置调度器并为特定用例定义自定义实现。有关更多信息,请参阅控制行为的以下变量:

  • BB_SCHEDULER
  • BB_SCHEDULERS

可以在任务的主函数之前和之后运行函数。这是通过使用任务的[prefuncs]和[postfuncs]标志来完成的,该标志列出了要运行的函数。

2.8 Checksums (Signatures)

checksum 是任务输入的唯一签名。任务的签名可用于确定任务是否需要运行。因为触发任务运行的是任务输入的更改,所以 BitBake 需要检测给定任务的所有输入。对于 shell 任务,这很容易实现,因为 BitBake 为每个任务生成一个“run”shell 脚本,并且可以创建一个校验和,让您很好地了解任务数据何时更改。

有些东西不应该包含在校验和中,这使问题复杂化。首先,给定任务的工作目录。工作目录是否更改并不重要,因为它不应该影响目标包的输出。排除工作目录的简单方法是将它设置为某个固定值,并为“run”脚本创建校验和。BitBake更进一步,使用 BB_BASEHASH_IGNORE_VARS 变量来定义一个在生成签名时永远不应包含的变量列表。

另一个问题是由包含可能被调用或可能不被调用的函数的“run”脚本引起的。增量构建解决方案包含用于确定shell函数之间依赖关系的代码。该代码用于将“run”脚本精简到最小集合,从而缓解了此问题,并使“run”脚本更具可读性。

到目前为止,我们已经有了 shell 脚本的解决方案。那么 Python 任务呢?即使这些任务更困难,同样的方法也适用。该过程需要弄清楚 Python 函数访问哪些变量以及它调用哪些函数。同样,增量构建解决方案包含的代码首先会找出变量和函数依赖关系,然后为用作任务输入的数据创建校验和。

与工作目录的情况一样,也存在应该忽略依赖关系的情况。对于这些情况,您可以使用以下行指示构建过程忽略依赖关系

PACKAGE_ARCHS[vardepsexclude] = "MACHINE"

此示例确保 PACKAGE_ARCHS 变量不依赖于 MACHINE 的值,即使它确实引用它。

同样,在某些情况下,我们需要添加 BitBake 无法找到的依赖项。您可以使用以下行来完成此操作

PACKAGE_ARCHS[vardeps] = "MACHINE"

此示例显式添加了 MACHINE 变量作为 PACKAGE_ARCHS 的依赖项。

考虑一个使用内联Python的案例,例如,BitBake无法确定依赖关系。在调试模式下运行时(即使用-DDD),BitBake在发现无法确定依赖关系的内容时会产生输出。

到目前为止,本节仅限于讨论任务的直接输入。基于直接输入的信息在代码中被称为“basehash”。然而,任务间接输入的问题仍然存在——那些已经构建并存在于构建目录中的东西。特定任务的校验和(或签名)需要添加特定任务所依赖的所有任务的哈希值。选择添加哪些依赖项是一个政策决定。然而,其效果是生成一个主校验和,将基础哈希和任务依赖项的哈希组合在一起。

在代码层面,有各种方法可以影响基础哈希和依赖任务哈希。在 BitBake 配置文件中,我们可以给 BitBake 一些额外信息来帮助它构建基础哈希。以下语句有效地生成了一个全局变量依赖排除列表——这些变量从不包含在任何校验和中。这个例子使用 OpenEmbedded 中的变量来帮助说明这个概念

BB_BASEHASH_IGNORE_VARS ?= "TMPDIR FILE PATH PWD BB_TASKHASH BBPATH DL_DIR \
    SSTATE_DIR THISDIR FILESEXTRAPATHS FILE_DIRNAME HOME LOGNAME SHELL \
    USER FILESPATH STAGING_DIR_HOST STAGING_DIR_TARGET COREBASE PRSERV_HOST \
    PRSERV_DUMPDIR PRSERV_DUMPFILE PRSERV_LOCKDOWN PARALLEL_MAKE \
    CCACHE_DIR EXTERNAL_TOOLCHAIN CCACHE CCACHE_DISABLE LICENSE_PATH SDKPKGSUFFIX"

前面的例子排除了工作目录,该目录是 TMPDIR 的一部分。

通过依赖链决定包含哪些依赖任务的哈希的规则更复杂,通常是通过Python函数完成的。 meta/lib/oe/sstatesig.py中的代码显示了两个例子,并说明了如何将您自己的策略插入到系统中(如果需要的话)。 这个文件定义了OpenEmbedded-Core使用的基本签名生成器:“OEBasicHash”。默认情况下,BitBake中启用了一个虚拟的“noop”签名处理程序。这意味着行为与以前版本没有变化。OE-Core默认通过bitbake.conf文件中的设置使用“OEBasicHash”签名处理程序。

BB_SIGNATURE_HANDLER ?= "OEBasicHash"

“OEBasicHash” BB_ SIGNATURE_ HANDLER 的主要特征是它将任务哈希添加到戳文件中。因此,任何元数据更改都会改变任务哈希,自动导致任务再次运行。这消除了需要调整 PR 值,并且元数据更改会自动波及整个构建。

同样值得注意的是,签名生成器的最终结果是为构建提供一些依赖关系和哈希信息。这些信息包括

  • BB_BASEHASH_task-taskname: The base hashes for each task in the recipe.
  • BB_BASEHASH_filename:taskname: The base hashes for each dependent task.
  • BB_TASKHASH: The hash of the currently running task.

值得注意的是, BitBake 的 “-S” 选项允许您调试 BitBake 的签名处理。传递给 -S 的选项允许使用不同的调试模式,可以使用 BitBake 自己的调试功能,也可以使用元数据/签名处理程序本身中定义的调试功能。传递的最简单的参数是“none”,它会导致一组签名信息被写入与指定目标对应的STAMPS_DIR。目前可用的另一个参数是“printdiff”,它会导致 BitBake 尝试建立最接近的签名匹配(例如在 sstate 缓存中),然后在匹配的基础上运行 bitbake-diffsigs,以确定这两个 stamp 树分歧的 stamp 和 delta。

未来版本的 BitBake 可能会提供通过其他“-S”参数触发的其他签名处理程序。

2.9 Setscene

设置场景过程使 BitBake 能够处理“预构建”工件。处理和重用这些工件的能力使 BitBake 无需每次都从头开始构建。相反,BitBake 可以在可能的情况下使用现有的构建工件。

BitBake 需要有可靠的数据来指示一个工件是否兼容。前一节中描述的签名提供了一种表示工件是否兼容的理想方法。如果签名相同,则可以重用对象。

如果一个对象可以重复使用,那么问题就变成了如何用预先构建的工件替换给定的任务或任务集。BitBake通过“setscene”过程解决了这个问题。

当 BitBake 被要求构建给定的目标时,在构建任何东西之前,它首先询问缓存的信息是否可用于正在构建的某个目标或某个中间目标。如果缓存的信息可用,BitBake 会使用此信息而不是运行主要任务。

BitBake 首先调用由 BB_HASHCHECK_FUNCTION 变量定义的功能,该变量包含它想要构建的任务列表和相应的哈希值。该函数旨在快速返回它认为可以获得工件的任务列表。

接下来,对于作为可能性返回的每个任务,BitBake 执行可能工件所涵盖的任务的 setscene 版本。任务的 setscene 版本在任务名称后附加字符串“_setscene”。因此,例如,名为 xxx 的任务有一个名为 xxx_setscene 的 setscene 任务。任务的 setscene 版本执行并提供必要的工件,返回成功或失败。

如前所述,一个工件可以覆盖多个任务。例如,如果你已经有了编译好的二进制文件,那么获取编译器是没有意义的。为了处理这个问题,BitBake为每个成功的setscene任务调用BB_SETSCENE_DEPVALID函数,以了解是否需要获取该任务的依赖关系。

您可以在“任务校验和”和“场景设置”部分找到有关场景设置元数据的更多信息。

2.10 Logging

除了标准的命令行选项来控制执行时的详细程度外,bitbake还支持通过 BB_LOGCONFIG 变量对Python日志记录工具进行用户定义配置。该变量定义了一个 JSON 或 YAML 日志记录配置,该配置将被智能地合并到默认配置中。日志记录配置使用以下规则合并:

  • 如果将顶层键 bitbake_merge 设置为值 False,则用户定义的配置将完全替换默认配置。在这种情况下,所有其他规则都将被忽略。
  • 用户配置必须有一个顶级版本,该版本必须与默认配置的值匹配。
  • 在处理程序、格式化程序或过滤器中定义的任何键都将被合并到默认配置中的同一部分,如果存在冲突,则用户指定的键将替换默认键。在实践中,这意味着如果默认配置和用户配置都指定了一个名为 myhandler 的处理程序,则用户定义的处理程序将替换默认处理程序。为了防止用户无意中替换默认处理程序、格式化程序或过滤器,所有默认处理程序都以“BitBake”作为前缀命名。
  • 如果用户将 key bitbake_merge 设置为 False 来定义一个记录器,则该记录器将被用户配置完全替换。在这种情况下,其他规则将不适用于该记录器。
  • 给定记录器的所有用户定义的过滤器和处理程序属性将与默认记录器的相应属性合并。例如,如果用户配置将名为 myFilter 的过滤器添加到 BitBake.SigGen,而默认配置添加名为 BitBake.defaultFilter 的过滤器,则这两个过滤器都将应用于记录器

作为第一个示例,您可以创建一个hashequiv.json用户日志配置文件,将所有与哈希等价相关的 VERBOSE 或更高优先级的消息记录到一个名为hashequiv.log的文件中

{
    "version": 1,
    "handlers": {
        "autobuilderlog": {
            "class": "logging.FileHandler",
            "formatter": "logfileFormatter",
            "level": "DEBUG",
            "filename": "hashequiv.log",
            "mode": "w"
        }
    },
    "formatters": {
            "logfileFormatter": {
                "format": "%(name)s: %(levelname)s: %(message)s"
            }
    },
    "loggers": {
        "BitBake.SigGen.HashEquiv": {
            "level": "VERBOSE",
            "handlers": ["autobuilderlog"]
        },
        "BitBake.RunQueue.HashEquiv": {
            "level": "VERBOSE",
            "handlers": ["autobuilderlog"]
        }
    }
}

然后在 conf/local.conf 中设置 BB_LOGCONFIG 变量:

BB_LOGCONFIG = "hashequiv.json"

另一个例子是 warn.json 文件,它将所有警告和更高优先级的消息记录到 warn.log 文件中

{
    "version": 1,
    "formatters": {
        "warnlogFormatter": {
            "()": "bb.msg.BBLogFormatter",
            "format": "%(levelname)s: %(message)s"
        }
    },

    "handlers": {
        "warnlog": {
            "class": "logging.FileHandler",
            "formatter": "warnlogFormatter",
            "level": "WARNING",
            "filename": "warn.log"
        }
    },

    "loggers": {
        "BitBake": {
            "handlers": ["warnlog"]
        }
    },

    "@disable_existing_loggers": false
}

请注意,BitBake 的结构化日志辅助类是在 lib/bb/msg.py 中实现的。

3 Syntax and Operators

BitBake文件有自己的语法。该语法与其他几种语言有相似之处,但也有一些独特的功能。本节介绍了可用的语法和运算符,并提供了示例。

3.1 Basic Syntax

3.1.1 Basic Variable Setting

"hard"赋值。语句解析时立即生效。

VARIABLE = "value"

如果赋值的字符串前面或后面有空格,这空格会被保留。

VARIABLE = " value"
VARIABLE = "value "

设置空字符串,设置空格,是不同的值。

VARIABLE = ""
VARIABLE = " "

用单引号设置一个包含双引号的字符串。

VARIABLE = 'I have a " in my value'

与 Bourne shell 不同,单引号在所有其他方面与双引号的工作方式相同。它们不会抑制变量扩展。

3.1.2 Modifying Existing Variables

以下情况可能需要修改变量。

  • 定制使用变量的配方。
  • 更改在 *.bbclass 文件中使用的变量的默认值。
  • 更改 *.bbappend 文件中的变量以覆盖原始配方中的变量。
  • 更改配置文件中的变量,以便该值覆盖现有配置。

如果你更改了变量的值,并且发生了无法解释的情况,你可以使用 BitBake 检查可疑变量的实际值。你可以对配置和配方级别的更改进行这些检查

  • 对于配置更改,请使用以下命令:

$ bitbake -e

此命令在解析配置文件(即local.conf、bblayers.conf、bitbake.conf等)后显示变量值。

在命令输出中,导出到环境的变量前面会加上字符串“export”。

  • 要查找特定配方中给定变量的更改,请使用以下内容:

$ bitbake recipename -e | grep VARIABLENAME=\"

此命令检查变量是否实际进入特定配方。

3.1.3 Line Joining

在函数外部, 行尾的“\”会使bitbake合并行。

FOO = "bar \
       baz \
       qaz"

“” 和换行符一起被移除。 赋值完成后,FOO 不包含换行符。

下面这两条语句效果相同。

FOO = "barbaz"
FOO = "bar\
baz"

BitBake 不会解释变量值中的转义序列,如“\n”。要使这些序列生效,必须将值传递给解释转义序列的实用程序,如 printf 或 echo -n。

3.1.4 Variable Expansion

一个变量中可以引用另一个变量的值。

A = "aval"
B = "pre${A}post"

引用变量时,花括号必须要有。 这一点与 Bourne shells 不同。

“=”运算符不会立即展开右侧的变量引用。相反,展开被推迟到分配给变量的值被实际使用时。结果取决于所引用变量的当前值。以下示例应阐明此行为

A = "${B} baz"
B = "${C} bar"
C = "foo"
*At this point, ${A} equals "foo bar baz"*
C = "qux"
*At this point, ${A} equals "qux bar baz"*
B = "norf"
*At this point, ${A} equals "norf baz"*

变量立即展开的运算符是:

:=

如果变量不存在,则将赋值内容当做原始字符串处理。

BAR = "${FOO}"

BAR展开为${FOO}。

3.1.5 Setting a default value (?=)

A ?= "aval"

如果A没有定义,则赋值为 aval ,否则保持其原来的值。

?= 的作用是立即的。 如果多条 ?= 赋值语句存在,则第一条发生作用。

3.1.6 Setting a weak default value (??=)

变量的弱默认值是指,如果未通过任何其他赋值运算符为其赋值,则该变量将扩展到的值。 “??=”运算符立即生效,替换任何以前定义的弱默认值。 示例如下

W ??= "x"
A := "${W}" # Immediate variable expansion
W ??= "y"
B := "${W}" # Immediate variable expansion
W ??= "z"
C = "${W}"
W ?= "i"

解析结果为:

A = "x"
B = "y"
C = "i"
W = "i"

附加和前置非覆盖样式不会替换弱的默认值,这意味着在解析后

W ??= "x"
W += "y"
W = " y"

注意前面有个空格。

另一方面,重写风格的 append/prepend/remove 是在替换任何活动的弱默认值之后应用的

W ??= "x"
W:append = "y"

解析之后如下:

W = "xy"

3.1.7 Immediate variable expansion (:=)

T = "123"
A := "test ${T}"
T = "456"
B := "${T} ${C}"
C = "cval"
C := "${C}append"

A contains “test 123”

B “456 cvalappend”

C “cvalappend”

3.1.8 Appending (+=) and prepending (=+) With Spaces

插入空格。

是立即生效的。

B = "bval"
B += "additionaldata"
C = "cval"
C =+ "test"

B “bval additionaldata”

C “test cval”

3.1.9 Appending (.=) and Prepending (=.) Without Spaces

不插入空格。

B = "bval"
B .= "additionaldata"
C = "cval"
C =. "test"

B “bvaladditionaldata”

C “testcval”

3.1.10 Appending and Prepending (Override Style Syntax)

B = "bval"
B:append = " additional data"
C = "cval"
C:prepend = "additional data "
D = "dval"
D:append = "additional data"

B becomes “bval additional data”

C becomes “additional data cval”

D becomes “dvaladditional data”

不会自动插入空格。

生效顺序是 “:append”, “:prepend”, “:remove”.

3.1.11 Removal (Override Style Syntax)

FOO = "123 456 789 123456 123 456 123 456"
FOO:remove = "123"
FOO:remove = "456"
FOO2 = " abc def ghi abcdef abc def abc def def"
FOO2:remove = "\
    def \
    abc \
    ghi \
    "

FOO becomes “ 789 123456 “

FOO2 becomes “ abcdef “

注:
只能移除空格分隔的字符串。

生效顺序是 “:append”, “:prepend”, “:remove”

FOOREMOVE = "123 456 789"
FOO:remove = "${FOOREMOVE}"
...
FOOREMOVE = "123 789"

结果是

FOO:remove = "123 789"

覆盖应用程序顺序可能与变量解析历史不匹配,即 bitbake -e 的输出可能在“:append”之前包含“:remove”,但结果将是删除字符串,因为“:remove”是最后处理的。

3.1.12 Override Style Operation Advantages

与“+=”和“=+”运算符相比,覆盖样式操作“:append”、“: prepend”和“:remove”的一个优点是,覆盖样式运算符提供了有保证的操作。例如,考虑一个需要将值“val”添加到变量FOO的类foo.bbclass,以及使用foo.bbclass的如下配方

inherit foo
FOO = "initial"

如果foo.bbclass使用“+=”运算符,如下所示,则FOO的最终值将是“initial”,这不是我们想要的

FOO += "val"

因为 = 不是立即生效的 ??

另一方面,如果foo.bbclass使用“:append”运算符,则FOO的最终值将是“initial val”,正如预期的那样

FOO:append = " val"

同时使用“+=”和“:append”是完全没有必要的。以下赋值序列将“barbaz”附加到FOO中:

FOO:append = "bar"
FOO:append = "baz"

将前一个示例中的第二个赋值更改为使用“+=”的唯一效果是在附加值中的“baz”之前添加一个空格(由于“+=”运算符的工作方式)。

覆盖样式操作的另一个优点是,您可以将其与其他覆盖结合使用,如“条件语法(覆盖)”一节所述。

3.1.13 Variable Flag Syntax

变量标志是 BitBake 对变量属性或特征的实现。它是一种在变量上标记额外信息的方法。您可以在“变量标志”部分找到更多关于变量标志的一般信息。

你可以定义、附加和预置变量标志的值。除了覆盖样式语法(即“: prepend”、“: append”和“: remove”)之外,前面提到的所有标准语法操作都适用于变量标志。

下面是一些显示如何设置变量标志的示例

FOO[a] = "abc"
FOO[b] = "123"
FOO[a] += "456"

变量 FOO 有两个标志:[a] 和 [b]。这两个标志分别立即设置为“abc”和“123”。[a] 标志变为“abc 456”。

无需预先定义变量标志。您可以直接开始使用它们。一个非常常见的应用是将一些简短的文档附加到BitBake变量,如下所示

注:
虽然方括号中的 flag 不需要预先定义。但有一些预定义的 flag 是有特殊作用的。
见 https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-metadata.html#variable-flags

CACHE[doc] = "The directory holding the cache of the metadata."

允许使用以下划线 (_) 字符开头的变量标志名称,但 Python 代码中的 d.getVarFlags(“VAR”) 会忽略这些名称。此类标志名称由 BitBake 在内部使用。

3.1.14 Inline Python Variable Expansion

您可以使用内联Python变量扩展来设置变量。以下是一个示例:

DATE = "${@time.strftime('%Y%m%d',time.gmtime())}"

这个示例的结果是将DATE变量设置为当前日期。

此功能最常见的用途可能是从BitBake的内部数据字典d中提取变量的值。以下几行分别选择软件包名称及其版本号:

PN = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
PV = "${@bb.parse.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"

就“=”和“:=”运算符而言,内联Python表达式的工作方式与变量扩展类似。 给出以下赋值,每次扩展FOO时都会调用foo():

FOO = "${@foo()}"

与下面的立即赋值相比,foo() 只被调用了一次,而赋值被解析了:

FOO := "${@foo()}"

有关在解析期间使用Python代码设置变量的不同方法,请参阅“匿名Python函数”一节。

3.1.15 Unsetting variables

unset DATE
unset do_fetch[noexec]

3.1.16 Providing Pathnames

在指定与 BitBake 一起使用的路径名时,不要使用波浪号 (“~”) 字符作为主目录的快捷方式。这样做可能会导致 BitBake 无法识别路径,因为 BitBake 不会像 shell 那样扩展此字符。

相反,如下面的例子所示,提供更完整的路径

BBLAYERS ?= " \
    /home/scott-lenovo/LayerA \
"

3.2 Exporting Variables to the Environment

export ENV_VARIABLE
ENV_VARIABLE = "value from the environment"

do_foo() {
    bbplain "$ENV_VARIABLE"
}

在这种情况下,BitBake不会扩展ENV_VARIABLE,因为它缺少必需的{}。相反,ENV_VARIABLE由shell扩展。

输出 ENV_VARIABLE 出现在 ENV_VARIABLE 赋值之前还是之后都无关紧要。

也可以将导出与设置变量值相结合。 下面是一个例子:

export ENV_VARIABLE = "variable-value"

在 bitbake -e 的输出中,导出到环境的变量前面有“export”。

通常导出到环境中的变量包括CC和CFLAGS,许多构建系统都会使用它们。

注:
貌似也可以这样用 bitbake <receip_name> -e

3.3 Conditional Syntax (Overrides)

BitBake使用 OVERRIDES 来控制BitBake解析配方和配置文件后覆盖哪些变量。本节介绍如何将 OVERRIDES 用作条件元数据,讨论与 OVERRIDES 相关的密钥扩展,并提供一些示例以帮助理解。

3.3.1 Conditional Metadata

您可以使用 OVERRIDES 有条件地选择变量的特定版本,并有条件地附加或预置变量的值。

OVERRIDES 只能使用小写字符、数字和破折号。特别地,OVERRIDES 名称中不允许使用冒号,因为冒号用于将 OVERRIDES 彼此分开,并与变量名称分开。

  • Selecting a Variable:

OVERWRITE 变量是一个以冒号分隔的列表,其中包含您想要满足条件的项目。因此,如果您有一个以“arm”为条件的变量,并且“arm”在OVERWRITE中,那么将使用“arm”特定版本的变量,而不是非条件版本的变量。 下面是一个例子:

OVERRIDES = "architecture:os:machine"
TEST = "default"
TEST:os = "osspecific"
TEST:nooverride = "othercondvalue"

在这个例子中,OVERWRITE 变量列出了三个覆盖:“architecture”、“os”和“machine”。变量 TEST 本身有一个默认值“default”。您可以通过将“os”覆盖附加到变量上来选择特定于 os 的 TEST 变量版本(即 TEST:os)。

注:
TEST:os 中的 “os” 在 OVERRIDES 定义的列表中,则赋值语句生效。 nooverride 不在 OVERRIDES 定义的列表中,则对应的赋值语句无效。
实际使用时,我们控制 OVERRIDES 列表的内容,即可控制赋值给类似上面例子中 TEST 的变量的值。

为了更好地理解这一点,考虑一个假设 OpenEmbedded 基于元数据的 Linux 内核配方文件的实际示例。 配方文件中的以下行首先将内核分支变量 KBRANCH 设置为默认值,然后根据构建的体系结构有条件地覆盖该值

KBRANCH = "standard/base"
KBRANCH:qemuarm = "standard/arm-versatile-926ejs"
KBRANCH:qemumips = "standard/mti-malta32"
KBRANCH:qemuppc = "standard/qemuppc"
KBRANCH:qemux86 = "standard/common-pc/base"
KBRANCH:qemux86-64 = "standard/common-pc-64/base"
KBRANCH:qemumips64 = "standard/mti-malta64"
  • Appending and Prepending:

BitBake 还支持根据特定项是否在 OVERRIDES 中列出,对变量值进行追加和预置操作。 下面是一个例子

DEPENDS = "glibc ncurses"
OVERRIDES = "machine:local"
DEPENDS:append:machine = "libmad"

在这个例子中,DEPENDS 变成了“glibc ncurses libmad”。

再次以基于OpenEmbedded metadata-based kernel recipe文件为例,以下行将根据架构有条件地附加到 KERNEL_FEATURES 变量

KERNEL_FEATURES:append = " ${KERNEL_EXTRA_FEATURES}"
KERNEL_FEATURES:append:qemux86=" cfg/sound.scc cfg/paravirt_kvm.scc"
KERNEL_FEATURES:append:qemux86-64=" cfg/sound.scc cfg/paravirt_kvm.scc"
  • Setting a Variable for a Single Task:

BitBake 支持仅在单个任务期间设置变量。 这是一个例子

FOO:task-configure = "val 1"
FOO:task-compile = "val 2"

在前面的例子中,当执行 do_configure 任务时,FOO 的值为“val 1”,而当执行 do_compile 任务时,FOO 的值为“val 2”。

在内部,这是通过将任务(例如“task-compile:”)附加到do_compile任务的本地数据存储的 OVERRIDES值来实现的。

您还可以将此语法与其他组合(例如“:prepend”)一起使用,如下例所示

EXTRA_OEMAKE:prepend:task-compile = "${PARALLEL_MAKE} "

在 BitBake 1.52(Honister 3.4)之前,OVERLOADS 的语法使用 _ 而不是 :,因此您仍然会发现许多使用 _append、_prepend 和 _remove 的文档。

3.3.2 Key Expansion

当 BitBake 数据存储完成时,会发生密钥扩展。为了更好地理解这一点,请考虑以下示例:

A${B} = "X"
B = "2"
A2 = "Y"

在这种情况下,在完成所有解析后,BitBake 会将 ${B} 扩展为“2”。这一扩展导致在扩展之前设置为“Y”的 A2 变为“X”。

3.3.3 Examples

尽管之前的解释显示了变量定义的不同形式,但很难准确计算出当变量运算符、条件覆盖和无条件覆盖组合时会发生什么。本节介绍了一些常见的情况,以及对通常会混淆用户的变量交互的解释。

关于覆盖和各种“append”运算符生效的顺序,通常存在混淆。回想一下,使用“:append”和“:PREpend”的append或PREpend操作不会像“+=”、“.=”、“=+”或“=.”那样立即赋值。考虑以下示例

OVERRIDES = "foo"
A = "Z"
A:foo:append = "X"

在这种情况下,A 被无条件地设置为“Z”,而“X”被无条件地立即附加到变量 A:foo。由于尚未应用覆盖,A:foo 由于附加而被设置为“X”,而 A 简单地等于“Z”。

然而,应用覆盖会改变情况。由于“foo”列在 OVERRIDES中,条件变量A被替换为“foo”版本,它等于“X”。因此,实际上,A:foo替换了A。

下一个例子更改了覆盖和附加的顺序

OVERRIDES = "foo"
A = "Z"
A:append:foo = "X"

在这种情况下,在处理覆盖之前,A被设置为“Z”,而A:append:foo被设置为“X”。然而,一旦应用了“foo”的覆盖,A就会被附加“X”。因此,A变成了“ZX”。请注意,空格不会被附加。

下一个例子中,附加和覆盖的顺序与第一个例子相反

OVERRIDES = "foo"
A = "Y"
A:foo:append = "Z"
A:foo:append = "X"

在这种情况下,在任何覆盖被解析之前,使用立即赋值将 A 设置为“Y”。在此立即赋值之后,A:foo 被设置为“Z”,然后进一步附加“X”,将变量设置为“ZX”。最后,对“foo”应用覆盖导致条件变量 A 变为“ZX”(即 A 被替换为 A:foo)。

最后一个例子混合了一些不同的运算符

A = "1"
A:append = "2"
A:append = "3"
A += "4"
A .= "5"

在这种情况下,由于 BitBake 多次传递代码,附加运算符的类型会影响赋值顺序。最初,由于使用了三个立即运算符的语句,A 被设置为“1 45”。在这些赋值完成之后,BitBake 应用了“:append”操作。这些操作导致 A 变为“1 4523”。

3.4 Sharing Functionality

BitBake允许通过包含文件(.inc)和类文件(.bbclass)共享元数据。例如,假设您有一个通用功能,例如任务定义,您希望在多个配方之间共享。在这种情况下,创建一个包含通用功能的.bbclass文件,然后在你的配方中使用继承指令来继承这个类,将是共享任务的常见方法。

本节介绍BitBake提供的机制,允许您在配方之间共享功能。具体而言,这些机制包括 include 、inherit 、INHERIT 和 require 指令。

3.4.1 Locating Include and Class Files

BitBake使用BBPATH变量来定位所需的include和类文件。此外,BitBake还会在当前目录中搜索include和require指令。

提示
BBPATH 变量类似于环境变量 PATH。

为了让 BitBake 找到 include 和 class 文件,它们需要位于 BBPATH 中可以找到的“classes”子目录中。

3.4.2 inherit Directive

在编写配方或类文件时,您可以使用 inherit 指令继承类(.bbclass)的功能。BitBake 仅在配方和类文件(即 .bb 和 .bbclass)中使用时支持此指令。

继承指令是一种基本手段,用于指定您的配方所需的类文件中包含的功能。例如,您可以轻松地抽象出构建使用Autoconf和Automake的软件包所涉及的任务,并将这些任务放入一个类文件中,然后让您的配方继承该类文件。

例如,您的菜谱可以使用以下指令继承一个autotools.bbclass文件。该类文件将包含使用Autotools的通用功能,这些功能可以在菜谱之间共享

inherit autotools

在这种情况下,BitBake将在BBPATH中搜索目录classes/autotools.bbclass。

提示
通过在“inherit”语句之后这样做,可以在配方中覆盖继承类的任何值和函数。

如果你想使用指令继承多个类,请用空格分隔它们。以下示例显示了如何继承 buildhistory 和 rm_work 类

inherit buildhistory rm_work

与 include 和 require 指令相比, inherit 指令的一个优点是你可以有条件地继承类文件。你可以通过在 inherit 语句后使用变量表达式来实现这一点。 这是一个例子

inherit ${VARNAME}

如果要设置VARNAME,需要在解析继承语句之前设置。在这种情况下实现条件继承的一种方法是使用重写

VARIABLE = ""
VARIABLE:someoverride = "myclass"

另一种方法是利用 anonymous Python 。这有一个例子:

python () {
    if condition == value:
        d.setVar('VARIABLE', 'myclass')
    else:
        d.setVar('VARIABLE', '')
}

或者,您可以使用以下形式的内联Python表达式:

inherit ${@'classname' if condition else ''}
inherit ${@functionname(params)}

在所有情况下,如果表达式计算结果为空字符串,则语句不会触发语法错误,因为它变成了一个无操作。

3.4.3 include Directive

BitBake理解include指令。该指令使BitBake解析您指定的任何文件,并将该文件插入该位置。该指令与Make中的等效指令非常相似,除非在include行中指定的路径是相对路径,否则BitBake会定位它在BBPATH中可以找到的第一个文件。

与继承指令相比,include指令是一种更通用的包含功能的方法,继承指令仅限于类(即.bbclass)文件。 include指令适用于任何其他类型的共享或封装功能或配置,而不适合.bbclass文件。

例如,假设您需要一个包含一些自测定义的配方

include test_defs.inc

当找不到文件时,include 指令不会产生错误。因此,建议如果包含的文件预计存在,则应使用 require 而不是 include。这样做可以确保在找不到文件时产生错误。

3.4.4 require Directive

BitBake理解require指令。该指令的行为与include指令类似,但如果在要包含的文件找不到时,BitBake会引发解析错误。因此,您需要的任何文件都会被插入到正在解析的文件中的指令位置。

与前面描述的 include 指令一样,require 指令是一种更通用的方法,与 inherit 指令相比,继承指令仅限于类(即 .bbclass)文件。 require 指令适用于任何其他类型的共享或封装的功能或配置,而不适合 .bbclass 文件。

与BitBake处理include的方式类似,如果require行中指定的路径是相对路径,BitBake会在BBPATH中查找它能够找到的第一个文件。

例如,假设你有两个版本的食谱(例如foo_1.2.2.bb和foo_2.0.0.bb),其中每个版本都包含一些可以共享的相同功能。您可以创建一个名为foo.inc的包含文件,其中包含构建“foo”所需的公共定义。您需要确保foo.inc与您的两个配方文件位于同一目录中。一旦设置了这些条件,您就可以使用每个配方中的require指令来共享功能

require foo.inc

3.4.5 INHERIT Configuration Directive

在创建配置文件(.conf)时,您可以使用INHERIT配置指令继承类。BitBake仅在配置文件中使用时支持此指令。

例如,假设您需要从配置文件继承名为abc.bbclass的类文件,如下所示

INHERIT += "abc"

此配置指令导致在解析期间在指令点继承指定的类。与 inherit 指令一样,.bbclass 文件必须位于 BBPATH 中指定的目录之一的“classes”子目录中。

因为在 BitBake 执行过程中会首先解析 .conf 文件,因此使用 INHERIT 继承类可以有效地全局继承该类(即对所有配方)。

如果你想使用该指令继承多个类,你可以在local.conf文件的同一行上提供它们。使用空格分隔类。以下示例显示了如何继承autotools和pkgconfig类

INHERIT += "autotools pkgconfig"

3.5 Functions

  • Shell Functions:
  • BitBake-Style Python Functions:
  • Python Functions:
  • Anonymous Python Functions:

无论函数类型如何,都只能在类(.bbclass)和配方(.bb或.inc)文件中定义它们。

3.5.1 Shell Functions

用shell脚本编写的函数可以直接作为函数、任务或两者执行。它们也可以被其他shell函数调用。以下是shell函数定义示例

some_function () {
    echo "Hello World"
}

当你在你的配方或类文件中创建这些类型的函数时,你需要遵循 shell 编程规则。脚本由 /bin/sh 执行,它可能不是 bash shell,但可能是 dash 等。你不应该使用 Bash 特有的脚本(bashisms)。

覆盖和覆盖样式的运算符,如:append和 prepend,也可以应用于shell函数。最常见的是,这种应用将用于.bbappend文件中,以修改主配方中的函数。它也可以用于修改从类继承的函数。

例如,考虑以下情况

do_foo() {
    bbplain first
    fn
}

fn:prepend() {
    bbplain second
}

fn() {
    bbplain third
}

do_foo:append() {
    bbplain fourth
}

运行 do_foo 打印如下:

recipename do_foo: first
recipename do_foo: second
recipename do_foo: third
recipename do_foo: fourth

覆盖和覆盖样式的运算符可以应用于任何shell函数,而不仅仅是任务。

您可以使用bitbake -e recipename命令查看应用所有覆盖后的最终组装函数。

3.5.2 BitBake-Style Python Functions

这些函数是用Python编写的,由BitBake或其他Python函数使用bb.build.exec_func()执行。

例子:

python some_python_function () {
    d.setVar("TEXT", "Hello World")
    print d.getVar("TEXT")
}

因为Python的“bb”和“os”模块已经导入,所以不需要导入这些模块。此外,在这些类型的函数中,数据存储(“d”)是一个全局变量,并且始终是自动可用的。

变量表达式(例如 ${X} )在 Python 函数中不再展开。这种行为是有意的,以便允许您自由设置可扩展表达式的变量值,而不会过早展开它们。如果您确实希望在 Python 函数中展开一个变量,请使用 d.getVar(“X”)。或者,对于更复杂的表达式,请使用 d.expand()。

与shell函数类似,您也可以将重写和重写风格的运算符应用于BitBake风格的Python函数。

例如

python do_foo:prepend() {
    bb.plain("first")
}

python do_foo() {
    bb.plain("second")
}

python do_foo:append() {
    bb.plain("third")
}

运行 fo_foo 打印:

recipename do_foo: first
recipename do_foo: second
recipename do_foo: third

您可以使用bitbake -e recipename命令查看应用所有覆盖后的最终组装函数。

3.5.3 Python Functions

这些函数是用Python编写的,由其他Python代码执行。Python函数的示例是您打算从内联Python或其他Python函数中调用的实用函数。 示例如下

def get_depends(d):
    if d.getVar('SOMECONDITION'):
        return "dependencywithcond"
    else:
        return "dependency"

SOMECONDITION = "1"
DEPENDS = "${@get_depends(d)}"

结果是 DEPENDS 包含 dependencywithcond

以下是关于Python函数的一些知识:

  • Python 函数可以接受参数。
  • BitBake数据存储不是自动可用的。因此,您必须将其作为参数传递给函数。
  • “bb”和“os”Python模块是自动可用的。您不需要导入它们。

3.5.4 BitBake-Style Python Functions Versus Python Functions

  • 只有BitBake风格的Python函数才能作为任务。

  • 覆盖和覆盖风格的运算符只能应用于BitBake风格的Python函数。

  • 只有常规的Python函数可以接受参数并返回值。

  • 在BitBake风格的Python函数上可以使用[dirs], [cleandirs], [lockfiles]等变量标志,但不能在常规Python函数上使用。

  • BitBake 风格的 Python 函数会生成一个单独的 ${T}/run.function-name.pid 脚本,该脚本用于运行函数,如果作为任务执行,还会生成 {T}/log.function-name.pid 日志文件。 常规 pyton 函数 inline 方式执行,不产生 ${T} 文件。

  • 常规Python函数使用通常的Python语法调用。BitBake风格的Python函数通常是任务,由BitBake直接调用,但也可以使用bb.build.exec_func()函数从Python代码中手动调用。

bb.build.exec_func("my_bitbake_style_function", d)

bb.build.exec_func() 也可以用于从 Python 代码运行 shell 函数。 如果您想在同一任务中的 Python 函数之前运行 shell 函数,那么您可以使用父辅助 Python 函数,该函数首先使用 bb.build.exec_func() 运行 shell 函数,然后运行 Python 代码。

要检测使用bb.build.exec_func()执行函数时出现的错误,可以捕获bb.build.FuncFailed异常。

元数据中的函数(配方和类)本身不应引发bb.build.FuncFailed。相反,bb.build.FuncFailed应被视为一个通用指示器,指示所调用的函数因引发异常而失败。例如,bb.fatal()引发的异常将在bb.build.exec_func()内被捕获,并引发bb.build.FuncFailed作为响应。

由于它们的简单性,你应该更喜欢常规的Python函数而不是BitBake风格的Python函数,除非你需要BitBake风格的Python函数特有的功能。元数据中的常规Python函数是比BitBake风格的Python函数更新的发明,而较旧的代码往往更频繁地使用bb.build.exec_func()。

3.5.5 Anonymous Python Functions

有时在解析过程中以编程方式设置变量或执行其他操作是有用的。为此,您可以定义特殊的Python函数,称为匿名Python函数,它在解析结束时运行。例如,以下根据另一个变量的值有条件地设置一个变量

python () {
    if d.getVar('SOMEVAR') == 'value':
        d.setVar('ANOTHERVAR', 'value2')
}

另一种指定匿名python函数的方法是明明为 __anonymous 。

总是在parsing结束时运行, 无论是在哪里定义的。 如果定义了多个匿名 python 函数,按照它们定义的顺序运行。

python () {
    d.setVar('FOO', 'foo 2')
}

FOO = "foo 1"

python () {
    d.appendVar('BAR',' bar 2')
}

BAR = "bar 1"

等同于

FOO = "foo 1"
BAR = "bar 1"
FOO = "foo 2"
BAR += "bar 2"

重写和重写样式的运算符(如“:append”)在匿名函数运行之前应用。在下面的例子中,FOO最终得到值“foo from anonymous”

FOO = "foo"
FOO:append = " from outside"

python () {
    d.setVar("FOO", "foo from anonymous")
}

3.5.6 Flexible Inheritance for Class Functions

BitBake支持从类中导出函数,使类函数显示为函数的默认实现,但如果继承类的配方需要定义自己的函数版本,则仍可以调用该函数。

要理解此功能的好处,请考虑一个基本场景,其中类定义了任务函数,而您的配方继承了该类。 在这个基本场景中,您的配方继承了类中定义的任务函数。 如果需要,您的配方可以通过分别使用“:prepend”或“:append”操作来添加到函数的开始和结束,或者它可以完全重定义函数。 然而,如果它重定义了函数,则没有办法调用该函数的类版本。 EXPORT_FUNCTIONS提供了一种机制,使该函数的配方版本能够调用该函数的原始版本。

要使用此技术,您需要准备好以下内容:

  • 类需要将函数定义如下

classname_functionname

例如,如果你有一个类文件bar.bbclass和一个名为do_foo的函数,则该类必须按如下方式定义该函数

bar_do_foo

  • class 需要包含 EXPORT_FUNCTIONS 语句

EXPORT_FUNCTIONS functionname

例如 bar.bbclass 中如下语句

EXPORT_FUNCTIONS do_foo

  • 您需要在配方中适当地调用函数。继续使用相同的例子,如果您的配方需要调用函数的类版本,则应调用 bar_do_foo。假设 do_foo 是一个 shell 函数,并且 EXPORT_FUNCTIONS 如上所述被使用,则配方的函数可以有条件地调用函数的类版本,如下所示:
do_foo() {
    if [ somecondition ] ; then
        bar_do_foo
    else
        # Do something else
    fi
}

要调用你在菜谱中定义的函数的修改版本,请将其称为 do_foo。

满足这些条件后,您的单个配方可以在类文件中定义的原始函数和配方中的修改函数之间自由选择。如果您没有设置这些条件,则仅限于使用一个函数或另一个函数。

注:
类函数定义时带前缀(以类名为前缀),导出时不带前缀。 在配方中调用类函数时,要加上类名前缀。

3.6 Tasks

任务是 BitBake 执行单元,它们构成了 BitBake 可以为给定配方运行的步骤。任务仅在配方和类中受支持(即,在 .bb 文件和包含或继承自 .bb 文件的文件中)。按照惯例,任务的名称以“do_”开头。

3.6.1 Promoting a Function to a Task

任务是shell函数或BitBake风格的Python函数,它们通过使用addtask命令被提升为任务。addtask命令还可以选择性地描述任务与其他任务之间的依赖关系。下面是一个示例,展示了如何定义任务并声明一些依赖关系

python do_printdate () {
    import time
    print time.strftime('%Y%m%d', time.gmtime())
}
addtask printdate after do_fetch before do_build

addtask 的第一个参数是要提升为任务的函数的名称。如果该名称不以“do_”开头,则隐式添加“do_”,这强制执行所有任务名称都以“do_”开头的约定。

在前面的例子中,do_printdate任务成为do_build任务的依赖项,do_build任务是默认任务(即,除非明确指定其他任务,否则由bitbake命令运行的任务)。此外,do_printdate任务成为do_fetch任务的依赖项。运行do_build任务会导致do_printdate任务首先运行。

如果你尝试了前面的例子,你可能会看到 do_printdate 任务只在第一次使用 bitbake 命令构建配方时运行。这是因为 BitBake 在初始运行后认为该任务是“最新的”。如果你想强制任务总是重新运行以进行实验,你可以使用 [nostamp] 变量标记,使 BitBake 始终认为该任务是“过时的”,如下所示

do_printdate[nostamp] = "1"

您还可以明确地运行任务并提供 -f 选项,如下所示:

$ bitbake recipe -c printdate -f

当使用 bitbake recipe -c task 命令手动选择要运行的任务时,可以省略“do_”前缀作为任务名称的一部分。

您可能会对使用addtask而不指定任何依赖关系的实际效果感到疑惑,如下例所示:

addtask printdate

在这个例子中,假设没有通过其他方式添加依赖关系,运行任务的唯一方法是通过 bitbake 配方 -c printdate 显式选择它。您可以使用 do_listtasks 任务列出配方中定义的所有任务,如下例所示

$ bitbake recipe -c listtasks

虽然这种情况很少见,但在调用 addtask 时可以将多个任务定义为依赖关系。例如,这是 OpenEmbedded 类文件 package_tar.bbclass 中的一个片段

addtask package_write_tar before do_build after do_packagedata do_package

3.6.2 Deleting a Task

除了能够添加任务外,您还可以删除它们。只需使用deltask命令删除任务即可。例如,要删除前面部分中使用的示例任务,您可以使用:

deltask printdate

如果使用deltask命令删除任务,并且该任务具有依赖关系,则依赖关系不会被重新连接。例如,假设您有三个名为do_a、do_b和do_c的任务。此外,do_c依赖于do_b,而do_b又依赖于do_a。在这种情况下,如果使用deltask删除do_b,则do_c和do_a之间通过do_b的隐式依赖关系将不再存在,并且do_c的依赖关系将不会更新为包括do_a。因此,do_c可以在do_a之前自由运行。

如果要保留这些依赖关系,请使用 [noexec] varflag 禁用该任务,而不是使用 deltask 命令删除它

do_b[noexec] = "1"

3.6.3 Passing Information Into the Build Task Environment

在运行任务时,BitBake严格控制构建任务的shell执行环境,以确保构建机器的不必要污染不会影响构建。

默认情况下,BitBake 会清理环境,仅保留其传递列表中导出或列出的内容,以确保构建环境可重现且一致。您可以通过设置 BB_PRESERVE_ENV 变量来阻止这种“清理”。

因此,如果你确实想让某些东西进入构建任务环境,你必须采取以下两个步骤

  1. 告诉 BitBake 从环境中加载您想要的内容到数据存储中。您可以通过 BB_ENV_PASSTHROUGH 和 BB_ENV_PASSTHROUGH_ADDITIONS 变量来实现。例如,假设您想阻止构建系统访问您的 $HOME/.ccache 目录。以下命令将环境变量 CCACHE_DIR 添加到 BitBake 的 passthrough 列表中,以允许该变量进入数据存储:

export BB_ENV_PASSTHROUGH_ADDITIONS="$BB_ENV_PASSTHROUGH_ADDITIONS CCACHE_DIR"

  1. 告诉 BitBake 将您加载到数据存储中的内容导出到每个正在运行的任务的任务环境中。从环境加载内容到数据存储(上一步)只会使其在数据存储中可用。要将它导出到每个正在运行的任务的任务环境中,请在本地配置文件 local.conf 或发行版配置文件中使用类似于以下内容的命令

export CCACHE_DIR

上述步骤的副作用是,BitBake将变量记录为构建过程的依赖项,如setscene校验和。如果这样做会导致不必要的任务重建,您还可以标记该变量,以便setscene代码在创建校验和时忽略该依赖项。

有时,能够从原始执行环境中获取信息是有用的。BitBake 将原始环境的副本保存在名为 BB_ORIGENV 的特殊变量中。

BB_ORIGENV 变量返回一个数据存储对象,可以使用标准数据存储运算符(如 getVar(, False))对其进行查询。数据存储对象非常有用,例如,可用于查找原始的 DISPLAY 变量。以下是一个示例:

origenv = d.getVar("BB_ORIGENV", False)
bar = origenv.getVar("BAR", False)

前面的例子从原始执行环境中返回BAR。

3.7 Variable Flags

变量标志(varflags)有助于控制任务的功能和依赖关系。BitBake使用以下命令形式读取和写入varflags到数据存储

variable = d.getVarFlags("variable")
self.d.setVarFlags("FOO", {"func": True})

使用varflags时,除了重写之外,其他语法都适用。换句话说,你可以像设置变量一样设置、附加和预置varflags。有关详细信息,请参阅“变量标志语法”一节。

BitBake为配方和类定义了一组可用的varflags。任务支持许多这些标志,这些标志控制着任务的各种功能

见原始文档: https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-metadata.html#variable-flags

3.8 Events

BitBake允许在配方和类文件中安装事件处理程序。事件在操作过程中的某些点触发,例如对给定配方(即*.bb)的操作开始、给定任务的开始、任务失败、任务成功等等。其目的是使构建失败时发送电子邮件通知等操作变得容易。

以下是一个示例事件处理程序,它打印事件名称和FILE变量的内容

addhandler myclass_eventhandler
python myclass_eventhandler() {
    from bb.event import getName
    print("The name of the Event is %s" % getName(e))
    print("The file we run for is %s" % d.getVar('FILE'))
}
myclass_eventhandler[eventmask] = "bb.event.BuildStarted
bb.event.BuildCompleted"

在前面的例子中,已经设置了一个事件掩码,这样处理程序只能看到“BuildStarted”和“BuildCompleted”事件。每次触发与事件掩码匹配的事件时,都会调用此事件处理程序。定义了一个全局变量“e”,表示当前事件。使用getName(e)方法,可以获取触发事件的名称。全局数据存储可用作“d”。在旧代码中,您可能会看到使用“e.data”来获取数据存储。但是,请注意,“e.data”已弃用,您应该使用“d”来继续使用。

数据存储的上下文与所讨论的事件相适应。例如,“BuildStarted”和“BuildCompleted”事件在执行任何任务之前运行,因此将位于全局配置数据存储命名空间中。该命名空间中不存在特定于配方的元数据。“BuildStarted”和“BuildCompleted”事件也在主炊具/服务器进程中运行,而不是在任何工作上下文中运行。因此,对数据存储所做的任何更改都会在当前构建中的其他炊具/服务器事件中看到,但在该构建之外或任何工作上下文中看不到。因此,在实际任务中运行的任务事件具有特定于配方和任务的内容。这些事件在任务执行结束时被丢弃。

在标准生成期间,可能会发生以下常见事件。以下事件是大多数元数据可能感兴趣查看的最常见事件类型

  • bb.event.ConfigParsed(): 当基础配置被解析时触发,基础配置包括bitbake.conf、base.bbclass和任何全局INHERIT语句。当每个工作进程解析基础配置或者服务器更改配置并重新解析时,您可以看到多个这样的事件。然而,任何给定的数据存储只对其中一个事件执行。如果在数据存储中由事件处理程序设置了BB_INVALIDCONF,则配置将被重新解析并触发新的事件,允许元数据更新配置。

  • bb.event.HeartbeatEvent(): 每隔一秒定期触发一次。您可以使用BB_HEARTBEAT_EVENT变量配置间隔时间。事件的“time”属性是事件被触发时的time.time()值。此事件对于系统状态监控等活动非常有用。

  • bb.event.ParseStarted(): 当BitBake即将开始解析食谱时触发。此事件的“total”属性表示BitBake计划解析的食谱数量。

  • bb.event.ParseProgress(): 随着解析的进行而触发。此事件的“current”属性表示已解析的食谱数量以及“total”属性。

  • bb.event.ParseCompleted(): 当解析完成时触发。此事件的“cached”、“parsed”、“skipped”、“virtuals”、“masked”和“errors”属性提供了解析结果的统计信息。

  • bb.event.BuildStarted(): 当新的构建开始时触发。当启用多个配置(multiconfig)时,BitBake会触发多个“BuildStarted”事件(每个配置一个)。

  • bb.build.TaskStarted(): 当任务开始时触发。此事件的“taskfile”属性指向任务来源的食谱。包含do_前缀的“taskname”属性是任务名称,而“logfile”属性指向任务输出存储的位置。最后,“time”属性是任务的执行开始时间。

  • bb.build.TaskInvalid(): 如果BitBake尝试执行不存在的任务,则会触发此事件。

  • bb.build.TaskFailedSilent(): 对于失败且不应向用户大声显示的setscene任务触发。

  • bb.build.TaskFailed(): 对于失败的正常任务触发。

  • bb.build.TaskSucceeded(): 当任务成功完成时触发。

  • bb.event.BuildCompleted(): 当构建完成时触发。

  • bb.cooker.CookerExit(): 当BitBake服务器/烹饪器关闭时触发。此事件通常仅在用户界面上看到,表示它们也应该关闭。

接下来的一组示例事件基于对服务器的特定请求而发生。这些事件通常用于将较大的信息从BitBake服务器通信到BitBake的其他部分,例如用户界面:

  • bb.event.TreeDataPreparationStarted()

  • bb.event.TreeDataPreparationProgress()

  • bb.event.TreeDataPreparationCompleted()

  • bb.event.DepTreeGenerated()

  • bb.event.CoreBaseFilesFound()

  • bb.event.ConfigFilePathFound()

  • bb.event.FilesMatchingFound()

  • bb.event.ConfigFilesFound()

  • bb.event.TargetsTreeGenerated()

3.9 Variants — Class Extension Mechanism

BitBake通过BBCLASSEXTEND变量支持配方文件的多个化身。

BBCLASSEXTEND 变量是一个以空格分隔的类列表,用于“扩展”每个变体的配方。这里有一个例子,它导致了当前配方的第二个化身可用。这个第二个化身将继承“原生”类。

BBCLASSEXTEND = "native"

此类扩展的机制对于实现来说非常具体。通常,扩展类需要修改配方的PROVIDES、PN和DEPENDS变量。有关具体示例,请参阅OE-Core native、nativesdk和multilib类。

3.10 Dependencies

为了实现高效的并行处理,BitBake在任务级别处理依赖关系。依赖关系可以存在于单个配方中的任务之间,也可以存在于不同配方中的任务之间。以下为每个例子的示例:

  • 对于单个配方中的任务,在运行其do_compile任务之前,可能需要先完成配方的do_configure任务。

  • 对于不同配方中的任务,一个配方的 do_configure 任务可能需要另一个配方的 do_populate_sysroot 任务先完成,以便其他配方提供的库和头文件可用。

本节介绍了几种声明依赖关系的方法。请记住,即使依赖关系以不同的方式声明,它们也仅仅是任务之间的依赖关系。

3.10.1 Dependencies Internal to the .bb File

BitBake使用addtask指令来管理给定配方文件内部的依赖关系。您可以使用addtask指令来指示任务何时依赖于其他任务,或者何时其他任务依赖于该配方。以下是一个示例

addtask printdate after do_fetch before do_build

3.10.2 Build Dependencies

BitBake使用DEPENDS变量来管理构建时间依赖关系。任务的[deptask] varflag表示DEPENDS中列出的每个项目的任务,这些任务必须在执行该任务之前完成。 以下是一个示例:

do_configure[deptask] = "do_populate_sysroot"

在本例中,必须在执行do_configure之前完成DEPENDS中每个项目的do_populate_sysroot任务。

3.10.3 Runtime Dependencies

BitBake使用Packages、Rdepend和Rrecommend变量来管理运行时依赖关系。

PACKAGES变量列出了运行时包。这些包中的每个包都可以有RDEPENDS和RRECOMMENDS运行时依赖关系。任务的[rdeptask]标志用于表示每个项目运行时依赖关系的任务,这些任务必须在执行该任务之前完成。

do_package_qa[rdeptask] = "do_packagedata"

在前面的例子中,在执行 do_package_qa 之前,RDEPENDS 中每个项目的 do_packagedata 任务都必须完成。 虽然 RDEPENDS 包含来自运行时依赖性名称空间的条目,但 BitBake 知道如何将它们映射回定义任务的构建时依赖性名称空间。

3.10.4 Recursive Dependencies

BitBake使用[recrdeptask]标志来管理递归任务依赖关系。BitBake查看当前配方的构建时和运行时依赖关系,查看任务的内部任务依赖关系,然后添加所列任务的依赖关系。一旦BitBake完成此操作,它就会递归地处理这些任务的依赖关系。迭代传递继续进行,直到发现并添加所有依赖关系为止。

[recrdeptask]标志最常用于需要等待某些任务“全局”完成的高级配方。例如,image.bbclass具有以下内容:

do_rootfs[recrdeptask] += "do_packagedata"

此声明表示,在运行 do_rootfs 任务之前,必须先运行当前配方和从映像配方(通过依赖关系)可访问的所有配方的 do_packagedata 任务。

BitBake允许任务通过在任务列表中引用自身来递归地依赖于自身:

do_a[recrdeptask] = "do_a do_b"

与之前一样,这意味着当前配方和所有配方(通过依赖关系)可到达的do_a和do_b任务必须在do_a任务运行之前运行。在这种情况下,BitBake将忽略当前配方的do_a任务对自身的循环依赖。

3.10.5 Inter-Task Dependencies

BitBake 以更通用的形式使用 [depends] 标记来管理任务间的依赖关系。这种更通用的形式允许对特定任务进行相互依赖检查,而不是对 DEPENDS 中的数据进行检查。 示例如下:

do_patch[depends] = "quilt-native:do_populate_sysroot"

在此示例中,目标 quilt-native 的 do_populate_sysroot 任务必须在执行 do_patch 任务之前完成。

[rdepends]标志以类似的方式工作,但使用运行时命名空间中的目标,而不是构建时依赖命名空间。

3.11 Functions You Can Call From Within Python

3.11.1 Functions for Accessing Datastore Variables

https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-metadata.html#functions-for-accessing-datastore-variables

3.11.2 Other Functions

通过查看bb模块的源代码,您可以找到许多可以从Python调用的其他函数,该模块位于bitbake/lib/bb中。例如,bitbake/lib/bb/utils.py包含常用的函数bb.utils.contains()和bb.utils.mkdirhier(),它们带有文档字符串。

3.11.3 Extending Python Library Code

如果你想添加你自己的Python库代码(例如,在元数据中提供可以从Python函数中使用的函数/类),可以使用addpylib指令在任何层上添加。该指令通常添加到你的层配置(conf/layer.conf)中,尽管它可以在任何.conf文件中处理。

使用形式为:

addpylib <directory> <namespace>

其中 指定要添加到库路径的目录。指定的 会自动导入,如果导入的模块指定了名为 BBIMPORTS 的属性,则子模块列表也会被迭代并导入。

3.11.4 Testing and Debugging BitBake Python code

OpenEmbedded构建系统实现了一个方便的pydevshell目标,您可以使用它访问BitBake数据存储并尝试使用您自己的Python代码。有关详细信息,请参阅Yocto项目手册中的使用Python开发Shell。

3.12 Task Checksums and Setscene

BitBake使用校验和(或签名)以及setscene来确定是否需要运行任务。本节描述了该过程。为了帮助理解BitBake是如何做到这一点的,本节假设了一个基于OpenEmbedded元数据的示例。

这些校验和存储在STAMP中。您可以使用以下BitBake命令检查校验和

$ bitbake-dumpsigs

此命令以可读的格式返回签名数据,使您可以检查 OpenEmbedded 构建系统生成签名时使用的输入。例如,使用 bitbake-dumpigs 可以检查 C 应用程序(例如 bash)的 do_compile 任务的“sigdata”。运行此命令还可以显示“CC”变量是已散列的输入的一部分。对此变量进行的任何更改都会使戳无效并导致 do_compile 任务运行。

以下列表描述了相关变量:

BB_HASHCHECK_FUNCTION:指定在任务执行的“setscene”部分调用函数的名称,以验证任务哈希列表。

BB_SETSCENE_DEPVALID:指定一个BitBake调用的函数,该函数确定BitBake是否需要满足setscene依赖性。

BB_TASKHASH:在执行中的任务中,该变量保存当前启用的签名生成器返回的任务哈希值。

STAMP:创建戳记文件的基准路径。

STAMPCLEAN:再次,创建戳文件的基本路径,但可以使用通配符来匹配一系列文件以进行清理操作。

3.13 Wildcard Support in Variables

对变量中使用通配符的支持因使用环境而异。例如,一些变量和文件名允许通过“%”和“*”字符有限制地使用通配符。其他变量或名称支持Python的glob语法、fnmatch语法或正则表达式(re)语法。

对于支持通配符的变量,文档描述了通配符的格式、使用和限制。

4 File Download Support

BitBake的fetch模块是一个独立的库代码,用于处理从远程系统下载源代码和文件的复杂性。获取源代码是构建软件的基石之一。因此,该模块是BitBake的重要组成部分。

当前的fetch模块称为“fetch2”,指的是它是API的第二个主要版本。原始版本已过时,已从代码库中删除。因此,在所有情况下,本手册中的“fetch”均指“fetch2”。

4.1 The Download (Fetch)

BitBake在获取源代码或文件时需要几个步骤。获取器代码库按顺序处理两个不同的过程:从某个地方(缓存或其他)获取文件,然后将这些文件解压缩到特定位置,可能以特定方式进行。获取和解压缩文件后,通常可以选择进行修补。然而,该模块不包括修补。

执行此过程第一部分(取数据)的代码看起来如下

src_uri = (d.getVar('SRC_URI') or "").split()
fetcher = bb.fetch2.Fetch(src_uri, d)
fetcher.download()

此代码设置了一个 fetch 类的实例。该实例使用来自 SRC_URI 变量的以空格分隔的 URL 列表,然后调用 download 方法下载文件。

Fetch 类的实例化通常遵循以下步骤:

rootdir = l.getVar('WORKDIR')
fetcher.unpack(rootdir)

此代码将下载的文件解压缩到WORKDIR指定的位置。

为了方便起见,这些示例中的命名与 OpenEmbedded 使用的变量相匹配。如果您想查看上面的代码,请检查 OpenEmbedded 类文件 base.bbclass 。

SRC_URI 和 WORKDIR 变量没有硬编码到获取器中,因为这些获取器方法可以用不同的变量名称调用。例如,在 OpenEmbedded 中,共享状态 (sstate) 代码使用 fetch 模块来获取 sstate 文件。

当调用 download() 方法时,BitBake 会尝试通过按特定搜索顺序查找源文件来解析 URL:

  • Pre-mirror Sites: BitBake 首先使用预镜像来尝试查找源文件。这些位置使用 PREMIRRORS 变量定义。

  • Source URI: 如果预镜像失败,BitBake 将使用原始 URL(例如来自 SRC_URI)。

  • Mirror Sites: 如果发生提取失败,BitBake接下来将使用MIRRORS变量定义的镜像位置。

对于传递给 fetcher 的每个 URL,fetcher 都会调用处理该特定 URL 类型的子模块。当您为 SRC_URI 变量提供 URL 时,这种行为可能会造成一些混淆。考虑以下两个 URL

https://git.yoctoproject.org/git/poky;protocol=git
git://git.yoctoproject.org/git/poky;protocol=http

在前一种情况下,URL 会传递给 wget 抓取器,而它并不理解“git”。因此,后一种情况是正确的形式,因为 Git 抓取器确实知道如何使用 HTTP 作为传输方式。

下面是一些显示常用镜像定义的示例

PREMIRRORS ?= "\
   bzr://.*/.\*  http://somemirror.org/sources/ \
   cvs://.*/.\*  http://somemirror.org/sources/ \
   git://.*/.\*  http://somemirror.org/sources/ \
   hg://.*/.\*   http://somemirror.org/sources/ \
   osc://.*/.\*  http://somemirror.org/sources/ \
   p4://.*/.\*   http://somemirror.org/sources/ \
  svn://.*/.\*   http://somemirror.org/sources/"

MIRRORS =+ "\
   ftp://.*/.\*   http://somemirror.org/sources/ \
   http://.*/.\*  http://somemirror.org/sources/ \
   https://.*/.\* http://somemirror.org/sources/"

值得注意的是,BitBake支持跨URL。可以将HTTP服务器上的Git存储库镜像为tarball。这就是前面示例中的git://映射所做的。

由于网络访问速度较慢,BitBake 会保留从网络下载的文件缓存。任何非本地(即从互联网下载的)源文件都会被放入下载目录,该目录由 DL_DIR 变量指定。

文件完整性对于复制构建至关重要。对于非本地存档下载,获取器代码可以验证SHA-256和MD5校验和,以确保存档已正确下载。您可以使用具有相应varflags的SRC_URI变量指定这些校验和,如下所示

SRC_URI[md5sum] = "value"
SRC_URI[sha256sum] = "value"

您还可以将校验和指定为SRC_URI上的参数,如下所示

SRC_URI = "http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d"

如果存在多个URI,您可以直接指定校验和,如前例所示,也可以指定URL的名称。以下语法显示了如何命名URI:

SRC_URI = "http://example.com/foobar.tar.bz2;name=foo"
SRC_URI[foo.md5sum] = 4a8e0f237e961fd7785d19d07fdb994d

下载文件并检查其校验和后,会在 DL_DIR 中放置一个“.done”戳。BitBake 在后续构建中使用此戳,以避免再次下载或比较文件的校验和。

假设本地存储是安全的,不会发生数据损坏。如果不是这样,就会产生更大的问题。

如果设置了 BB_STRICT_CHECKSUM,则任何没有校验和的下载都会触发错误消息。 BB_NO_NETWORK 变量可用于使任何尝试的网络访问成为致命错误,这对于检查镜像是否完整以及其他事情很有用。

如果 BB_CHECK_SSL_CERTS 设置为 0,则将禁用 SSL 证书检查。此变量默认为 1,因此通常会检查 SSL 证书。

4.2 The Unpack

解压缩过程通常在下载后立即进行。对于除 Git URL 之外的所有 URL,BitBake 都使用常见的解压缩方法。

在 URL 中可以指定多个参数来控制解包阶段的行为:

  • unpack:控制是否解压缩URL组件。如果设置为默认值“1”,则解压缩组件。如果设置为“0”,则解压缩阶段将文件保留。当您希望复制存档而不解压缩时,此参数非常有用。

  • dos:适用于.zip和.jar文件,并指定是否对文本文件使用DOS行尾转换。

  • striplevel:从提取的文件名中删除指定数量的前导组件(级别)

  • subdir:将特定网址解压到根目录中的指定子目录。

解压缩调用会自动解压和提取带有“.Z”、“.z”、“.gz”、“.xz”、“.zip”、“.jar”、“.ipk”、“.rpm”、“.srpm”、“.deb”和“.bz2”扩展名的文件,以及tarball扩展名的各种组合。

如前所述,Git fetcher 拥有自己的 unpack 方法,该方法经过优化,可与 Git 树一起使用。基本上,该方法通过将树克隆到最终目录中来工作。该过程使用引用完成,因此只需要一个 Git 元数据的中心副本。

4.3 Fetchers

4.3.1 Local file fetcher (file://)

此子模块处理以file://开头的URL。您在URL中指定的文件名可以是文件的绝对路径或相对路径。如果文件名是相对的,则使用FILESPATH变量的内容,就像PATH用于查找可执行文件一样。如果找不到文件,则假定在调用download()方法时,该文件在DL_DIR中可用。

如果指定目录,则解压缩整个目录。

这里有两个示例网址,第一个是相对网址,第二个是绝对网址

SRC_URI = "file://relativefile.patch"
SRC_URI = "file:///Users/ich/very_important_software"

4.3.2 HTTP/FTP wget fetcher (http://, ftp://, https://)

此抓取器从Web和FTP服务器获取文件。在内部,抓取器使用wget实用程序。

所使用的可执行文件和参数由FETCHCMD_wget变量指定,默认值为合理值。抓取器支持参数“downloadfilename”,允许指定下载文件的名称。指定下载文件的名称对于处理多个同名文件时避免DL_DIR中的冲突很有用。

如果在 SRC_URI 中指定了用户名和密码,则每个请求(包括跨重定向)都将添加一个 Basic Authorization 标头。要限制第一个请求的 Authorization 标头,请在参数列表中添加“redirectauth=0”。

一些示例URL如下

SRC_URI = "http://oe.handhelds.org/not_there.aac"
SRC_URI = "ftp://oe.handhelds.org/not_there_as_well.aac"
SRC_URI = "ftp://you@oe.handhelds.org/home/you/secret.plan"

因为URL参数由分号分隔,所以在解析也包含分号的URL时,这可能会造成歧义,例如

SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git;a=snapshot;h=a5dd47"

此类网址应通过将分号替换为“&”字符进行修改:

SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47"

在大多数情况下,这应该可行。万维网联盟 (W3C) 建议在查询中以相同的方式处理分号和“&”。请注意,由于 URL 的性质,您可能还需要指定下载文件的名称

SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47;downloadfilename=myfile.bz2"

4.3.3 CVS fetcher ((cvs://)

4.3.4 Subversion (SVN) Fetcher (svn://)

4.3.5 Git Fetcher (git://)

这个获取子模块从 Git 源代码控制系统中获取代码。获取器通过在 GITDIR 中创建远程的裸克隆来工作,该 GITDIR 通常是 DL_DIR/git2。然后在解包阶段,当特定树被检出时,该裸克隆被克隆到工作目录中。这是通过使用替代和引用来完成的,以最小化磁盘上的重复数据量,并使解包过程快速。使用的可执行文件可以用 FETCHCMD_git 设置。

支持如下参数:

  • “protocol”: 用于获取文件的协议。如果设置了主机名,则默认值为“git”。如果没有设置主机名,则 Git 协议为“file”。您还可以使用“http”、“https”、“ssh”和“rsync”。

当协议为“ssh”时,SRC_URI中期望的URL与通常传递给git clone命令并由Git服务器提供以进行提取的URL不同。例如,GitLab服务器在通过SSH克隆时为mesa返回的URL为git@gitlab.freedesktop.org:mesa/mesa.git,但是SRC_URI中期望的URL如下:

SRC_URI = "git://git@gitlab.freedesktop.org/mesa/mesa.git;branch=main;protocol=ssh;..."

请注意,项目路径前的 : 字符已更改为 /。

  • “nocheckout” : 当设置为“1”时,告诉提取器在解包时不要签出源代码。为有自定义例程来签出代码的 URL 设置此选项。默认值为“0”。

  • “rebaseable” : 表示上游 Git 仓库可以重写。如果修订版可以从分支中分离出来,则应将此参数设置为“1”。在这种情况下,源镜像 tarball 是按修订版完成的,这会降低效率。重写上游 Git 仓库可能会导致当前修订版从上游仓库中消失。此选项提醒抓取器谨慎保留本地缓存以备将来使用。此参数的默认值为“0”。

  • “nobranch” : 当设置为“1”时,告诉提取器不要检查分支的SHA验证。默认值为“0”。为引用对任何命名空间(分支、标记等)有效的提交的配方设置此选项,而不是分支。

  • “bareclone” : 告诉提取器将裸克隆克隆到目标目录中,而不检查正在工作的树。仅提供原始的 Git 元数据。此参数也隐含了“nocheckout”参数。

  • “branch” : 要克隆的 Git 树的分支。除非将“nobranch”设置为“1”,否则这是一个强制参数。分支参数的数量必须与名称参数的数量匹配。

  • “rev” : 用于签出的修订版本。默认值是“master”。

  • “tag” : 指定用于签出的标签。为了正确解析标签,BitBake必须访问网络。因此,通常不使用标签。就Git而言,“tag”参数的行为与“rev”参数完全相同。

  • “subpath” : 将签出限制到树的一个特定子路径。默认情况下,整个树都会被签出。

  • “destsuffix” : 放置签出文件的路径名称。默认路径为 git/.

  • “usehead”:启用本地git:// URL,将当前分支HEAD用作AUTOREV使用的版本。 “usehead”参数表示没有分支,仅在传输协议为file://时才有效。

下面是一些示例网址

SRC_URI = "git://github.com/fronteed/icheck.git;protocol=https;branch=${PV};tag=${PV}"
SRC_URI = "git://github.com/asciidoc/asciidoc-py;protocol=https;branch=main"
SRC_URI = "git://git@gitlab.freedesktop.org/mesa/mesa.git;branch=main;protocol=ssh;..."

When using git as the fetcher of the main source code of your software, S should be set accordingly:

S = "${WORKDIR}/git"

不支持直接在 git:// url 中指定密码。有几个原因:SRC_URI 通常会写到日志和其他地方,这很容易泄露密码;在不删除密码的情况下,也很容易共享元数据。可以使用 SSH 密钥、~/.netrc 和 ~/.ssh/config 文件作为替代方案。

使用带有 git fetcher 的标签可能会导致令人惊讶的行为。 Bitbake 需要将标签解析为特定的修订版,为此,它必须连接到上游存储库并使用它。这是因为标签指向的修订版可能会发生变化,我们已经在众所周知的公共存储库中看到过这种情况。这可能意味着比预期更多的网络连接,并且在每次构建时可能会重新解析配方。由于上游存储库是准确解析修订版的唯一真实来源,因此将绕过源镜像。由于这些原因,虽然 fetcher 可以支持标签,但我们建议在配方中明确修订版。

4.3.6 Git Submodule Fetcher (gitsm://)

4.3.7 ClearCase Fetcher (ccrc://)

4.3.8 Perforce Fetcher (p4://)

4.3.9 Repo Fetcher (repo://)

此抓取器子模块从谷歌存储库源代码控制系统中抓取代码。抓取器的工作原理是启动存储库的源代码并将其同步到REPODIR中,该目录通常是${DL_DIR}/repo。

此抓取器支持以下参数:

  • “protocol” : 获取仓库清单的协议(默认值:git)。

  • “branch” : 要获取的仓库分支或标签(默认值:master)。

  • “manifest” : 清单文件的名称(默认值:default.xml)。

这里是一些示例网址

SRC_URI = "repo://REPOROOT;protocol=git;branch=some_branch;manifest=my_manifest.xml"
SRC_URI = "repo://REPOROOT;protocol=file;branch=some_branch;manifest=my_manifest.xml"

4.3.10 Az Fetcher (az://)

4.3.11 GCP Fetcher (gs://)

4.3.12 Crate Fetcher (crate://)

4.3.13 NPM Fetcher (npm://)

4.3.14 NPM shrinkwrap Fetcher (npmsw://)

4.3.15 Other Fetchers

5 Variables Glossary

见 https://docs.yoctoproject.org/bitbake/2.6/bitbake-user-manual/bitbake-user-manual-ref-variables.html#variables-glossary

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Bitbake是一个用于构建Linux发行版的工具。它可以自动化构建过程,从源代码到二进制软件包的构建和安装。Bitbake中文手册是一个详细的指南,介绍了如何使用Bitbake来搭建自己的Linux发行版。 Bitbake中文手册包括了Bitbake的基础知识、配置文件、任务和模块等功能,同时也提供了一些基本的例子和命令说明。手册中除了说明文档外,也配有图片、表格以及代码实现。 Bitbake中文手册适合新手学习使用,也可以作为一个参考手册用于日常的工作中。 Bitbake的使用需要有一定的Linux系统知识,并且有一定的编程经验,但是通过Bitbake中文手册,学习曲线会更加陡峭一些。这也让广大Linux爱好者们可以更方便地学习和使用Bitbake。 总的来说,Bitbake中文手册是一个非常有用的资源,可以帮助用户更好地学习使用Bitbake,同时也可以帮助开源社区用户更好地开发和维护自己的Linux发行版。 ### 回答2: Bitbake是一款自动化构建工具,主要用于嵌入式Linux系统的构建和打包。它可以通过一系列的配置文件和动作脚本来自动化地构建和打包软件包,并提供了众多功能,如依赖关系管理、版本控制、跨平台构建等。Bitbake支持包括ARM、PowerPC、x86等在内的多种处理器架构,可以适用于各种不同的嵌入式系统。 Bitbake中文手册主要介绍了Bitbake的基本概念、配置方法、构建和打包流程、常用命令以及各种扩展功能的使用方法。手册中还包括了实际的示例和详细的说明,可以帮助开发者更快地掌握Bitbake的使用方法。 Bitbake的使用需要具备一定的Linux系统和命令行操作的基础,同时需要了解OpenEmbedded框架的相关知识。通过仔细阅读Bitbake中文手册,开发者可以了解到Bitbake的工作原理和使用方法,进而能够快速地构建和打包自己的嵌入式Linux系统和应用程序。 总之,Bitbake中文手册是很有价值的一份文档,对于嵌入式Linux系统的开发者来说是一本必备的参考书。它可以帮助开发者节省时间和精力,提高开发效率,让嵌入式系统的开发更加顺畅和高效。 ### 回答3: Bitbake是一款强大的开源构建工具,它可以帮助开发者自动化构建和管理Linux软件包。Bitbake有一份详细的中文手册,方便初学者入门。 Bitbake中文手册从介绍Bitbake的概念和基本操作开始,然后详细介绍Bitbake各种命令的使用方法和参数。手册中还介绍了Bitbake的一些高级特性,如Bitbake的配置文件,自定义简单的软件包,软件包的依赖管理等等。 在手册的最后,还对Bitbake的一些常见问题进行了解答,方便用户在遇到问题时快速解决。总之,Bitbake中文手册是一份非常完整的参考文档,对于想要了解Bitbake的开发者和运维人员来说,是一个必不可少的工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值