当前位置: 首页 > news >正文

Yocto - 使用Yocto开发嵌入式Linux系统_09 深入了解BitBake元数据

Diving into BitBake Metadata
在本书的这一部分,我们已经知道了如何生成图像和软件包,以及如何使用软件包源--基本上,这就是我们简单使用 Poky 所必须知道的一切。接下来,我们将学习如何控制 Poky 的行为,以实现我们的目标,并从整个 Yocto 项目中获取最大利益。
At this point in this book, we know how to generate images and packages and how to use package feeds – basically, everything we must know for the simple usage of Poky. Hereafter, we will learn how to control the behavior of Poky to accomplish our goals and achieve maximum benefit from the Yocto Project as a whole.
本章将帮助我们加深对 BitBake 元数据语法的理解。我们将学习使用 BitBake 运算符来更改变量内容、变量扩展等。这些都是我们可以用来制作配方和进行定制的关键概念,我们将在接下来的章节中学习这些内容。
This chapter will help enhance our understanding of the BitBake metadata syntax. We will learn to use the BitBake operators to alter the content of variables, variable expansions, and so on. These are the key concepts we can use to make our recipes and the customization that we will learn about in the following chapters.
1, Understanding BitBake’s metadata
BitBake 使用的元数据量非常大。因此,要想从 Poky 中获得最大收益,我们必须掌握它。正如我们在第 4 章 “认识 BitBake 工具 ”中所了解到的,元数据包括三个主要方面:
The amount of metadata used by BitBake is enormous. Therefore, to get the maximum benefit from Poky, we must master it. As we learned in Chapter 4, Meeting the BitBake Tool, metadata covers three major areas:
* 配置(.conf 文件): 配置文件定义了配置类和配方工作方式的全局内容。
* 类(.bbclass 文件): 类可以继承,以便于维护,促进代码重用,避免代码重复。
* 配方(.bb 或 .bbappend 文件): 配方描述要运行的任务,并提供所需的信息,以便 BitBake 生成所需的任务链。它们是最常用的元数据,因为它们为配方定义了变量和任务。最常见的配方类型是生成软件包和图像。
* Configuration (the .conf files): The configuration files define the global content that configures how the classes and recipes will work.
* Classes (the .bbclass files): Classes can be inherited for easier maintenance and to promote code reuse and avoid code duplication.
* Recipes (the .bb or .bbappend files): The recipes describe the tasks to be run and provide the required information to allow BitBake to generate the required task chain. They are the most commonly used metadata, as they define the variables and tasks for the recipes. The most common types of recipes generate packages and images.
这些类和配方混合使用了 Python 和 Shell Script 代码,BitBake 在解析这些代码时会生成大量任务和本地状态,这些任务和状态在解析后仍需执行。
The classes and recipes use a mix of Python and Shell Script code, which is parsed by BitBake, generating a massive number of tasks and local states that must still be executed after being parsed.
我们还将学习建立配方所需的运算符和基本概念。
We will also learn about the operators and essential concepts we need to build our recipes.
Working with metadata
BitBake 元数据使用的语法可能会引起误解,有时甚至难以追踪。不过,我们可以使用 bitbake 选项(-e 或 --environment)检查 BitBake 生成的预处理配方数据中每个变量的值,如下所示:
The syntax used by BitBake metadata can be misleading and sometimes hard to trace. However, we can check the value of each variable in BitBake-generated, pre-processed recipe data by using the bitbake option ( -e or --environment), as follows:
[ Figure 8.1 – How to display the BitBake environment ]
要了解 BitBake 如何工作,请参阅《BitBake 用户手册》 ( BitBake User Manual — Bitbake dev documentation )。下文将介绍配方中常用的大部分语法。
To understand how BitBake works, please refer to BitBake User Manual ( BitBake User Manual — Bitbake dev documentation ). The following sections will show most of the syntax commonly used in recipes.
The basic variable assignment
变量的赋值过程如下所示:
The assignment of a variable can be done as shown here:
[ Figure 8.2 – An example of a variable assignment ]
在上例中,FOO 变量的值被分配给了 bar。变量赋值是 BitBake 元数据语法的核心,因为大多数示例都使用了变量。
In the preceding example, the value of the FOO variable is assigned to bar. Variable assignment is core to the BitBake metadata syntax, as most examples use variables.
The variable expansion
BitBake 支持变量引用。其语法与 Shell 脚本十分相似,例如以下语法:
BitBake supports variable referencing. The syntax closely resembles Shell Script, such as the following:
[ Figure 8.3 – An example of variable expansion ]
上例的结果是 A 包含 aValue,B 包含 before-aValue-after。需要注意的是,变量只有在使用时才会展开,如图所示:
The preceding example results in A containing aValue and B containing before-aValue-after. An important thing to bear in mind is that the variable only expands when it is used, as shown here:
[ Figure 8.4 – The variables are only expanded when used ]
图 8.4 展示了 BitBake 评估使用的懒惰评估。B 变量的值为 before-${A}-after,直到有任务需要该变量值。在第 3 行中,A 变量已被赋值给 aNewValue;因此,B 的值为 before-aNewValue-after。
Figure 8.4 illustrates the lazy evaluation used by BitBake evaluation. The B variable value is before-${A}-after until a task requires the variable value. The A variable has been assigned to aNewValue in line 3; consequently, B evaluates before-aNewValue-after.
Assigning a value if the variable is unassigned, using ?=
当需要为一个变量赋值时,如果该变量仍未被赋值,则可以使用 ?= 操作符。下面的代码展示了它的用法:
When there is a need to assign a variable only if the variable is still unassigned, the ?= operator can be used. The following code shows its use:
[ Figure 8.5 – An example of value ]
如果一个变量有多个 ?= 赋值,也会出现同样的情况。第一个使用 ?= 操作符的变量负责赋值。让我们看看下面的例子:
The same behavior happens if there are multiple ?= assignments to a single variable. The first use of the ?= operator is responsible for assigning the variable. Let’s look at the following example:
[ Figure 8.6 – An example of a second assignment being ignored ]
第 2 行的 ignoredAsAlreadyAssigned 赋值被忽略,在其之前,A 变量已在第 1 行被赋值。
The A variable has been assigned to value on line 1, before the assignment of ignoredAsAlreadyAssigned on line 2, which is ignored.
我们需要考虑 = 运算符比 ?= 运算符更强,因为它的赋值与之前的变量状态无关,如图所示:
We need to consider that the = operator is stronger than the ?= operator, as it assigns the value independently of the previous variable state, as shown here:
[ Figure 8.7 – An example showing that the ?= operator is weaker than the = operator ]
因此,A 变量被赋值为 changeValue。
Hence, the A variable is assigned as changeValue.
Assigning a default value using ??=
使用 ??= 操作符的目的是为变量提供默认值,是 ?= 操作符的弱化版本。
Using the ??= operator is intended to provide a default value for a variable and is a weaker version of the ?= operator.
请查看以下代码:
Check out the following code:
[ Figure 8.8 – An example of how default values are assigned ]
在第 1 行中,A 默认值被赋值给 firstValue,然后在第 2 行中,A 默认值被改为 secondValue。由于没有对 A 变量进行其他赋值,最终值为 secondValue。
In line 1, the A default value is assigned to firstValue, and then in line 2, the A default value is changed to secondValue. As no other assignment is made to the A variable, the final value is secondValue.
?= 是赋值运算符,如前所述,优先于 ??= 运算符,如下例所示:
?= is an assignment operator, as seen before, and takes precedence over the ??= operator, as can be seen in the following example:
[ Figure 8.9 – An example of the ??= operator being weaker than the ?= operator ]
A 变量的最终值是 thirdValue,因为直到第 3 行才进行赋值。
The final value of A variable is thirdValue, as no assignment has been made until line 3.
The immediate variable expansion
:= 操作符用于需要强制立即展开变量时。它的结果是变量的内容立即展开,而不是在使用变量时展开,如下所示:
The := operator is used when there is a need to force the immediate expansion of a variable. It results in the variable’s contents being expanded immediately rather than when the variable is used, as follows:
[ Figure 8.10 – An example of immediate variable expansion ]
第 2 行立即分配了 B 的值,并将其扩展为 aValue-after。但是,C 的值只有在使用时才赋值,然后设置为 newValue,因为 A 的值已在第 3 行设置。
The value for B is assigned immediately, in line 2, and expands to aValue-after. However, the value for C is only assigned when used and then set to newValue, as A value has been set in line 3.
The list appending and prepending
+= 操作符被称为列表追加,它在原始值后面添加一个新值,并用空格分隔,如图所示:
The += operator, known as list appending, adds a new value after the original one, separated with a space, as shown here:
[ Figure 8.11 – An example of list appending ]
在本例中,A 的最终值为 originalValue appendedValue。
In this example, the final value for A is originalValue appendedValue.
=+ 操作符被称为列表前置,它在原始值之前添加一个新值,并用空格隔开,如图所示:
The =+ operator, known as list prepending, adds a new value before the original one, separated with a space, as shown here:
[ Figure 8.12 – An example of list prepending ]
在本例中,A 的最终值为 prependedValue originalValue。
In this example, the final value for A is prependedValue originalValue.
The string appending and prepending
.= 操作符被称为字符串追加,它在原始值后面添加一个新值,没有多余的空格,如图所示:
The .= operator, known as string appending, adds a new value after the original one, with no extra space, as shown here:
[ Figure 8.13 – An example of string appending ]
在本例中,A 的最终值为 originalValueAppendedValue。
In this example, the final value for A is originalValueAppendedValue.
操作符 =. 被称为字符串前置,它将新值添加到原始值之前,没有额外的空格,如图所示:
The =. operator, known as string prepending, adds the new value before the original one with no extra space, as shown here:
[ Figure 8.14 – An example of string prepending ]
在本例中,A 的最终值是 prependedValueOriginalValue。
In this example, the final value for A is prependedValueOriginalValue.
The :append and :prepend operators
如图所示,:append 操作符在原始值后面添加一个新值,没有额外的空格:
The :append operator adds a new value after the original with no extra space, as shown here:
[ Figure 8.15 – An example of how to use the :append operator ]
在本例中,A 的最终值为 originalValueAppendedValue。
In this example, the final value for A is originalValueAppendedValue.
如图所示,:prepend 操作符将新值添加到原始值之前,没有额外的空格:
The :prepend operator adds the new value before the original with no extra space, as shown here:
[ Figure 8.16 – An example of how to use the :prepend operator ]
在本例中,A 的最终值是 prependedValueOriginalValue。
In this example, the final value for A is prependedValueOriginalValue.
您可能已经注意到 :append 和 :prepend 操作符类似于字符串追加(.=)和预追加(=.)操作符。不过,:append 和 :prepend 操作符与字符串追加和字符串预置操作符的解析方式还是有细微差别的,如下所示:
You may have noticed that the :append and :prepend operators resemble the string appending ( .=) and prepending ( =.) operators. Still, there is a subtle difference between how the :append and :prepend operators and the string appending and string prepending operators are parsed, as shown here:
[ Figure 8.17 – An example of the difference between :append and the .= operator ]
Using the :append operator queues the operation for execution, which happens after the line 2 assignment, resulting in A becoming valueAppendedValue. The .= operator is immediate, so the assignment of line 4 replaces the value set on line 3, resulting in B becoming value.
The list item removal
:remove 操作符会从原始内容中删除一个列表项。例如,请参阅下文:
The :remove operator drops a list item from the original content. For example, see the following:
[ Figure 8.18 – An example of how to use the :remove operator ]
在本例中,A 现在是 value1 value3。:remove 操作符将变量值视为由空格分隔的字符串列表,因此操作符可以从列表中删除一个或多个项目。请注意,在执行 :remove 时,所有追加和预追加操作都已完成。
In this example, A is now value1 value3. The :remove operator considers the variable value as a list of strings separated by spaces so that the operator can remove one or more items from the list. Note that every appending and prepending operation has already finished when :remove is executed.
Conditional metadata sets
BitBake 提供了一种非常简单易用的方法,可以通过一种称为覆盖的机制来编写有条件的元数据。
BitBake provides a very easy-to-use way to write conditional metadata through a mechanism called overrides.
OVERRIDES 变量包含用冒号(:)分隔的值,并从左到右进行评估。每个值都是我们希望有条件元数据的项目。
The OVERRIDES variable contains values separated by colons ( :) and evaluated from left to right. Each value is an item that we want to have conditional metadata.
让我们来看看下一个例子:
Let’s consider the next example:
[ Figure 8.19 – An example of the OVERRIDES variable ]
与 arm 和 mymachine 相比,linux 的覆盖没有那么具体。下面的示例展示了如何使用 OVERRIDES 有条件地设置 A 变量:
The linux override is less specific than arm and mymachine. The following example shows how we can use OVERRIDES to set the A variable conditionally:
[ Figure 8.20 – An example of using OVERRIDES conditional setting ]
在本例中,由于 linux 位于 OVERRIDES 中,因此 A 将是 linuxSpecificValue。
In this example, A will be linuxSpecificValue, due to the condition of linux being in OVERRIDES.
Conditional appending
BitBake 还支持根据变量是否在 OVERRIDES 中进行追加和预追加,如下例所示:
BitBake also supports appending and prepending variables, based on whether something is in OVERRIDES, as shown in the following example:
[ Figure 8.21 – An example of using OVERRIDES conditional appending ]
在上例中,A 被设置为 armValue 值。
In the preceding example, A is set to value armValue.
File inclusion
BitBake 提供了两种用于包含文件的指令--include 和 require。
BitBake provides two directives for file inclusion – include and require.
使用 include 关键字时,BitBake 会尝试在关键字位置插入文件,因此它是可选的。假设在 include 行中指定的路径是相对路径,那么 BitBake 会在 BBPATH 中找到它能找到的第一个实例。相比之下,如果找不到所需的文件,require 关键字就会引发 ParseError。
With the include keyword, BitBake attempts to insert the file at the keyword location, so it is optional. Let’s suppose the path specified on the include line is relative; then, BitBake locates the first instance it can find within BBPATH. By contrast, the require keyword raises ParseError if the required file cannot be found.
Tip
Yocto 项目通常使用 .inc 文件来共享两个或多个配方文件之间的共同代码。
The convention generally adopted in the Yocto Project is to use a .inc file to share the common code between two or more recipe files.
Python variable expansion
通过以下语法,BitBake 可以轻松地在变量扩展中使用 Python 代码:
BitBake makes it easy to use Python code in variable expansion with the following syntax:
这为用户提供了极大的灵活性。我们可以在下面的示例中看到一个 Python 函数调用:
This gives enormous flexibility to a user. We can see a Python function call in the following example:
[ Figure 8.23 – An example of a Python command to print the current date ]
这样,A 变量就包含了今天的日期。
This results in the A variable containing today’s date.
Defining executable metadata
元数据配方(.bb)和类文件(.bbclass)可以使用 Shell 脚本代码,如下所示:
Metadata recipes (.bb) and class files (.bbclass) can use Shell Script code, as follows:
[ Figure 8.24 – An example of a task definition ]
任务定义与设置变量完全相同,只不过这个变量是一个可执行的 Shell 脚本代码。在编写任务代码时,我们不应使用 Bash 或 Zsh 特有的功能,因为任务只能依赖与 POSIX 兼容的功能。如果有疑问,使用 Dash shell 试试看是测试代码是否安全的绝佳方法。
The task definition is identical to setting a variable, except that this variable happens to be an executable Shell Script code. When writing the task code, we should not use Bash or Zsh-specific features, as the tasks can only rely on POSIX-compatible features. When in doubt, an excellent way to test whether your code is safe is to use the Dash shell to try it out.
另一种注入代码的方法是使用 Python 代码,如图所示:
Another way to inject code is by using Python code, as shown here:
[ Figure 8.25 – An example of a Python task definition ]
任务定义方式类似,但它将任务标记为 Python,以便 BitBake 知道如何相应地运行它。
The task definition is similar, but it flags the task as Python so that BitBake knows how to run it accordingly.
Defining Python functions in a global namespace
当我们需要为变量或其他用途生成一个值时,可以在配方(.bb)和类(.bbclass)中使用类似下面的代码快速完成:
When we need to generate a value for a variable or some other use, this can be quickly done in recipes (.bb) and classes (.bbclass) using code similar to the following:
[ Figure 8.26 – A code example to handle variable values in Python code ]
通常,我们需要在编写 Python 函数时访问 BitBake 数据存储。因此,所有元数据的一个惯例是使用一个名为 d 的参数来指向 BitBake 的数据存储。它通常位于函数的最后一个参数中。
Usually, we need to access the BitBake datastore when writing a Python function. Therefore, a convention among all metadata is the use of an argument called d to point to BitBake’s datastore. It is usually in the last parameter of the function.
在图 8.26 中,我们在第 2 行向数据存储请求 SOMECONDITION 变量的值,并返回一个与之相关的值。
In Figure 8.26, we ask the datastore for the value of the SOMECONDITION variable in line 2 and return a value depending on it.
示例的结果是 DEPENDS 变量的值包含 dependencyWithConditon。
The example results in the value for the DEPENDS variable containing dependencyWithConditon.
The inheritance system
继承指令指定我们的配方(.bb)为哪些功能类提供了基本的继承机制,例如面向对象的编程语言。例如,我们可以抽象出使用 Autoconf 和 Automake 构建工具所涉及的任务,并将其放入类中供我们的配方重复使用。在 BBPATH 中搜索 classes/filename.bbclass 即可找到指定的 .bbclass。因此,在使用 Autoconf 或 Automake 的配方中,我们可以使用以下代码:
The inherit directive specifies which classes of functionality our recipe ( .bb) offers a rudimentary inheritance mechanism, such as object-oriented programming languages. For example, we can abstract the tasks involved in using the Autoconf and Automake building tools and put them into the class for our recipes to reuse. A given .bbclass is located by searching for classes/filename.bbclass in BBPATH. So, in a recipe that uses Autoconf or Automake, we can use the following:
[ Figure 8.27 – An example of how to inherit a class ]
图 8.27 中的第 1 行指示 BitBake 使用 inherit autotools.bbclass,提供了默认任务,这些任务在大多数基于 Autoconf- 或 Automake 的项目中运行良好。
Line 1 from Figure 8.27 instructs BitBake to use inherit autotools.bbclass, providing the default tasks that work fine for most Autoconf- or Automake-based projects.
2, Summary
在本章中,我们详细了解了 BitBake 元数据语法、操作变量内容的运算符和变量扩展,包括一些使用示例。
In this chapter, we learned in detail about the BitBake metadata syntax, its operators to manipulate variable contents, and variable expansions, including some usage examples.
在下一章中,我们将学习如何使用 Poky 创建外部编译工具,并生成适合目标开发的根文件系统。
In the next chapter, we will learn how to use Poky to create external compilation tools and produce a root filesystem suitable for target development.

http://www.mrgr.cn/news/49425.html

相关文章:

  • 用SAM2和Cutie模型目标追踪
  • 程序地址空间 -- 详解
  • Download Vmware Fusion (free for person)
  • Dev-Cpp 5.11 安装教程【保姆级】
  • vue3之生命周期钩子
  • 2024-10-13 NO.1 Quest3 激活教程
  • 千万级的大表,是如何产生的?
  • 【数据脱敏方案】不使用 AOP + 注解,使用 SpringBoot+YAML 实现
  • Mysql—高可用集群故障迁移
  • 【python入门到精通专题】8.装饰器
  • DVWA CSRF 漏洞实践报告
  • HL7协议简介及其在STM32上的解析实现
  • QT开发--QT SQL模块
  • Maven项目打包为jar的几种方式
  • 代码随想录 | Day32 | 回溯算法:排列问题
  • 电子电气架构---软件定义汽车,产业变革
  • iOS_图片加载优化
  • 考研C语言程序设计_语法相关(持续更新)
  • 2024系统架构师---试题二论软件维护方法及其应用
  • HTML(七)表格