实时嵌入式Linux设备基准测试快速入门2嵌入式系统和Linux

第2章:嵌入式系统和Linux

将在ICS中使用SBC等一体化设备。这些嵌入式系统的功能越来越多,需要操作系统(OS)来处理这种复杂性。在这种情况下,选择嵌入式 Linux 作为操作系统似乎是最明智的选择。

因此,本章将介绍作为嵌入式操作系统的Linux,并分析其相对于其他操作系统的主要优势。然后,将介绍Linux嵌入式系统的基本结构和主要组件,概述其与桌面环境Linux的主要区别。最后,由于创建定制的Linux发行版可能是一个艰难的过程,因此将介绍Yocto项目,这是一套用于处理这种复杂性的工具。

2.1 为什么选择 Linux?

一旦了解到ICS正朝着使用集成多种功能的嵌入式设备的方向发展,在选定硬件平台后,主要的问题仍然是使用哪种操作系统。

多年来,电子设备的性能和功能不断提高,计算机行业就是这种演变的最直接例子。当然,随着计算机的发展,嵌入式世界也在不断进步,为微型嵌入式系统提供了更多的功能。
这些嵌入式系统越来越需要新的功能,如:与网络连接、多任务处理能力和其他复杂功能。因此,这些系统往往需要网络堆栈和/或服务,从而增加了必须提供这些功能的操作系统的复杂性。

在这种情况下,许多操作系统应运而生,它们各有不同的特点和功能。如今,为嵌入式世界选择合适的操作系统的范围非常广泛,即使是开源系统也是大势所趋。作出这种选择的主要原因是,与封闭系统相比,开放源码系统具有许多优势。

在开放式系统所具有的众多优势中,最明显的一点就是在使用开放式源代码解决方案时,可以对系统进行完全控制。事实上,特别是对于因资源有限而需要定制的设备来说,开源操作系统提供了完美的环境。作为开源操作系统,Linux因其安全、稳定、可靠和可移植性等特点而堪称完美。虽然它最初是在PC平台上运行,但如今它已适用于嵌入式系统,而且在这些设备上的使用与日俱增。

由于Linux内核的多功能性,它基本上随处可见,常见的使用Linux作为操作系统的嵌入式设备包括:智能电视、车载信息娱乐系统、网络设备(路由器、交换机、接入点)、机器控制、工业自动化、医疗仪器等。人们最熟悉的Linux应用可能是智能手机和平板电脑等移动设备,Linux系统还支持触摸屏显示器和网络模块,从而扩大了对不同硬件设备的支持。
下图中的例子证明,Linux确实应用于许多嵌入式系统,这些系统基本上无处不在。

正如预期的那样,Linux 系统具有许多优势:

  • 强大的功能

Linux 提供了多线程、多功能的操作系统。它还提供了许多功能,如:图形和通信支持等等。

  • 可扩展性

Linux既可以在内存容量巨大的大型系统上运行,也可以在内存容量较小的嵌入式设备上运行。这种灵活性使得Linux系统可以根据其运行平台进行调整。事实上,得益于 Linux 提供的模块化和可扩展性,它在嵌入式系统中被广泛采用。

  • 广泛使用

得益于开放源代码社区,Linux多年来不断发展壮大,成为最常用的操作系统之一,并为程序员和开发人员所熟知,他们多年来开发了大量应用程序,涵盖了许多有用的领域。

  • 低成本

其他操作系统比Linux昂贵得多,而Linux几乎都是免费的。

  • 易于定制

Linux 易于定制,可根据开发人员的需要添加或删除功能。
图片

  • 支持

当发现新问题时,Linux开发人员会提供支持。此外,Linux是开放源代码,其文档资料也很容易获得,没有任何限制。

在工业领域,工业应用所需的主要参数是:高性能、高灵活性、低成本和缩短上市时间。
所有这些要求都在 Linux 中得到了很好的支持,多年来,Linux获得了前面所述的开放源码社区提供的所有好处。

尽管Linux似乎也非常适合ICS,但在使用时必须考虑到它的一些缺点。事实上,特别是当要开发的系统需要实时功能时,由于Linux 本身的复杂性,可能会出现一些问题。有关这些问题的更多详情将在第 3.1 节中介绍。
图片

参考资料

  • 软件测试精品书籍文档下载持续更新 https://github.com/china-testing/python-testing-examples 请点赞,谢谢!
  • 本文涉及的python测试开发库 谢谢点赞! https://github.com/china-testing/python_cn_resouce
  • python精品书籍下载 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
  • Linux精品书籍下载 https://www.cnblogs.com/testing-/p/17438558.html

2.2 Linux嵌入式系统的主要组件

如前所述,由于其自身的特点,Linux也是嵌入式领域使用最多的操作系统之一。本节将介绍和分析Linux嵌入式系统的典型架构及其主要组件。

此外,还将概述在嵌入式系统中使用Linux与在桌面环境中使用Linux的主要区别。
事实上,由于嵌入式系统的功能通常有限,在这些小型设备上使用Linux与在台式电脑上使用Linux有细微差别。

图片

图 2.3 显示了 Linux 嵌入式系统开发环境的通用架构。从中可以很容易地识别出两个主要设备:

  • 目标设备:它是嵌入式设备,Linux 和应用软件将在上面运行。
  • 主机:它是所有开发工具所在的计算机器,通常具有良好的计算能力,因为它要应对嵌入式目标所提供的有限性能。

通常,在开发主机上运行的软件工具组成所谓的工具链,而工具链又由不同的软件组件组成,例如

  • 编译器
  • 调试器
  • 二进制工具

而另一方面,目标设备(以Linux为例)则由其他不同的软件组件组成:

  • boot-loader
  • Linux 内核。
  • 根文件系统,其主要元素包括:C 库、系统库和用户应用程序。

由于所有这些组件对于理解Linux系统如何工作都非常重要,因此将逐一进行分析。

2.2.1 工具链

工具链是处理Linux嵌入式系统所需的第一个要素,基本上由开发必须在目标设备上运行的软件所需的所有工具组成。
事实上,获取可运行工具链的方法有很多种,可以从源代码中编译,也可以直接下载并安装,在大多数情况下,还可以使用构建管理系统(如YP)来创建,详情请参见 2.3.1。

嵌入式工具链中最常见的工具如图 2.4 所示,由于对这些工具的分析很有趣,本节下文将对每种工具进行简要说明。
图片

2.2.1.1 编译器

编译器可能是工具链中最基本的部分之一。在大多数情况下,Linux的编译器都是GCC,因为它是编译Linux内核的唯一实用方法。

当需要为嵌入式系统编译某些代码时,通常使用交叉编译,因为:编译器在x86机器上运行,但它用于编译将在另一种架构(如ARM平台)上运行的软件。简而言之,交叉编译可以被视为一个直接的过程,它在主机上运行,从源文件开始生成目标硬件可以理解的指令。

在图2.5中,连续线段表示交叉编译过程,虚线段表示交叉编译过程的一些变体。事实上,也有可能在目标硬件上运行编译器。

不过,这一过程对嵌入式硬件的性能要求较高,几乎无人使用。此外,即使在这种情况下,在嵌入式硬件上运行的编译器也很可能是通过交叉编译过程获得的。

当然,也可以编译程序,以便在开发主机上运行。事实上,先在开发PC上运行某个程序,然后再编译到目标硬件上,这样做可能会很有用。
图片

2.2.1.2 调试器

由于嵌入式系统的调试比较困难,因此需要使用通常集成在工具链中的特殊工具。通常,GDB是最常用的调试工具。它由两个不同的软件组件组成:第一个在主机上运行,第二个在目标硬件上执行,通常称为GDB服务器。

这两个软件组件通过以太网或串行连接相互通信,以便调试在嵌入式硬件上运行的应用程序。

图2.6显示了使用GNU调试器(GDB)调试嵌入式系统的一般架构。Linux内核调试也有类似的工具。不过,在这种情况下,建议使用JTAG调试器。JTAG调试器能提供最佳的调试功能,因为它们能保证直接访问CPU,以非侵入方式检查执行的指令和内存区域。

图 2.6:内核调试的调试过程称为 KGDB。它允许使用串行或网络连接调试内核,只需启用相应的内核功能即可。

图片

2.2.1.3 二进制实用程序

二进制实用程序,简称Binutils,是一套用于创建和管理二进制文件和源文件(如对象文件、库和汇编源文件)的工具。
Binutils是一套有不同用途的实用程序:其中一些在编译过程中使用,如链接器和汇编器,而其他工具则用于管理二进制文件。
例如,”剥离”(strip)用于剥离编译应用程序中的符号,使其更小,或者,”addr2line”等工具用于将应用程序中的地址转换为相应的源代码行。

2.2.1.4 跟踪和剖析工具

Linux 最大的优点之一是它提供了一系列软件,例如,有一些跟踪和剖析Linux内核进程的工具。这些工具可用于调试目的,也可用于研究奇怪的行为和性能分析,详情将在第 3.3 节中介绍。

2.2.1.5 内核头文件

内核头文件是工具链的另一个重要组成部分。如图2.7所示,内核头定义了应用程序和c库之间的接口,因此非常有用。

图片

因此,c库和访问内核应用程序编程接口(API)的应用程序需要根据内核头进行编译,以便使用适当的调用接口。
因此,通常在嵌入式Linux工具链中,内核头必须与嵌入式硬件上运行的内核版本保持同步。

2.2.1.6 C库

C库提供了应用程序与 Linux 内核之间的主要接口,如图 2.7 所示。

当然,有很多不同的C库可以选择。例如glibc是标准的LinuxC库,几乎每个Linux桌面都在使用。它设计得非常快,而且符合各种 C 语言标准。

不过,glibc并没有针对大小进行优化,因此,如果因为嵌入式系统的闪存存储空间有限而对大小有要求,那么还有其他选择,例如 uclibc,它是一个设计得更小的轻量级C库。

当然,选择使用哪种C库,就像嵌入式系统中的任何东西一样,必须根据系统的要求和功能进行权衡。

2.2.2 目标嵌入式系统

到目前为止,我们已经介绍了工具链的概念及其主要组成部分。总而言之,工具链允许创建和管理将在实际目标设备上运行的所有软件。

一旦掌握了这些工具,就必须了解 Linux 嵌入式系统的软件组件是如何构成的(见图 2.8)。

因此,本节将介绍和分析必须在Linux目标设备上运行的主要软件组件。

图片

2.2.2.1 启动阶段和U-boot

当处理器接通电源时,它开始在内存中的给定地址上获取指令,通常,位于该地址上的代码被命名为引导加载程序。

基本上,在Linux系统中,引导程序负责在系统启动时加载和运行Linux内核。具体来说,当系统启动时,引导加载器会进行一些基本的硬件初始化,然后从某个地方(SD卡、内部闪存、网络)将内核映像加载到主内存中,最后开始执行。

有许多引导加载程序可用,但在处理嵌入式系统和Linux时,最常用的引导加载程序是U-boot,如今它已被视为事实上的标准。虽然U-boot用于加载和运行Linux,但它并不是Linux本身的一部分,而是以开源许可证发布的,多年来已获得了许多有用的特性和功能,可根据需要启用。

U-boot具有很强的可配置性,支持从多种存储设备加载内核映像。此外,U-boot还提供了通过完全交互式shell处理内存和其他内容的工具,实际上,从某种意义上说,它就像一个操作系统。它可以用来验证新设备,因为它是运行Linux系统的第一步。因此,它有助于测试基本的硬件功能,如通用串行总线(USB)连接、网络接口、内存等。

此外,由于U-boot的多功能性,某些版本的U-boot甚至可以安装在小容量的内存中,为存储能力较小的设备提供支持。
U-boot提供的主要功能概述如下:

  • TCP/IP 协议栈
  • 文件系统管理(ext、fat32、jffs2、ubifs)
  • USB 堆栈
  • 串行/网络控制台
  • NAND、NOR、EEPROM、SD 管理
  • 高清多媒体接口(HDMI)管理和闪屏
  • 命令行脚本

通常,U-boot 软件架构分为两部分:前半部分主要用汇编编写,从片上存储器(如片上 SRAM 或 FLASH)运行,并初始化存储器控制器。

然后将控制权传递给后半部分,后半部分初始化其他外设,并与Linux内核一起加载设备树Blob,同时提供命令行界面,用户可以在内核运行前与引导加载程序交互。

图2.9展示典型的启动过程,u-boot 作为引导程序参与其中。

图片

2.2.2.2 设备树

为了管理组成嵌入式设备的特定硬件资源,Linux内核必须知道哪些外围设备可用,即必须知道与所连接和使用的硬件相关的信息,如输入/输出(I/O)设备、存储器等。

要让Linux内核获得与系统硬件相关的信息,有两种主要的解决方案:

  • 不使用”设备树”:

硬件信息被硬编码到内核二进制代码中,因此每次修改硬件定义都意味着重建整个内核。引导加载程序会加载内核映像,并在准备好通过CPU寄存器传递给内核的一些附加信息后执行。

  • 使用设备树:

硬件信息由引导加载程序提供给内核,特别是使用名为”设备树 Blob”的二进制文件。这样,硬件定义和配置的更改并不意味着内核需要重新编译,因为只需修改 DTB 文件即可。当然,使用这种方法可以减少编译过程所需的时间和精力。

更详细地说,DTB文件通常是通过编译过程从设备树源代码(DTS)开始生成的。后者是一种树形数据结构,其节点描述系统中的物理设备。

图 2.10 显示了使用和不使用设备树的启动过程,从中可以看到主内存的内容。

图片

2.2.2.3 Linux内核

Linux内核,顾名思义,代表操作系统的核心,虽然有时名称会混淆,但在谈论Linux时,实际系统就是 Linux内核本身。Linux内核负责执行操作系统必须执行的所有操作。基本上,主内核的目标是管理系统资源,让程序在共享这些硬件资源的同时运行。通常,Linux 内核管理的主要资源是

  • CPU 资源

作为负责运行程序的 CPU,内核必须决定哪个进程必须运行、何时运行以及在哪个处理器中执行。

  • 内存资源

内核负责管理内存区域,决定何时允许新的分配请求,以及如何管理可用内存。

  • 输入/输出资源

内核负责管理需要执行输入/输出操作的应用程序的请求,并提供使用各种设备的方法。

在管理资源的同时,Linux 内核还管理着系统中运行的所有进程,并提供以下功能

  • 任务之间的通信机制。
  • 设备驱动程序。
  • 允许应用程序与硬件交互的 API(如以太网连接或显示器)。
  • 电源管理策略。

得益于开源社区,Linux源代码更新频繁,大约每三个月就会更换一次版本。当然,从一个版本的内核到另一个版本的内核,源代码都会发生变化,但不同版本的源代码布局几乎保持一致。

源代码下载后,Linux 内核的目录和文件布局如图 2.11 所示。

图片

多数内核目录的名称不言自明,例如:fs代表文件系统,mm指内存管理源代码,等等。更有趣的目录可能是arch,因为它包含了用于处理Linux所支持的不同CPU架构的所有特定架构源代码。就Linux内核而言,特定架构源代码约占整个内核源代码的20%,考虑到其中80%与CPU无关,这个比例并不算高。除了arch目录,包含大量不同设备驱动程序的drivers文件夹也包含特定架构的源代码。

在所示的内核源代码布局中,另一个有趣的文件是makefile。它可以控制需要编译的内容和编译方式。事实上,如果要开始构建Linux内核,第一步就是设置所有环境变量,这些变量将被makefile用来为所需的设备和架构编译代码。

图片

图2.12显示了典型Linux系统的顶层视图,其中最直观的就是用户模式与内核模式的区别,事实上,Linux 提供了这两种模式的分离。用户模式下运行的应用程序无法直接访问任何硬件,只能通过系统调用接口拦截的c库函数(如 open)请求内核访问设备功能。

因此,在用户模式或用户空间中运行的代码实际上是在系统中以最低权限运行的,它只能要求内核完成一些事情。相反,在内核空间运行的代码则拥有对整个系统的完全访问权限,可以查看和访问与系统相连的所有内存和硬件。

当然,这种分离的主要原因是,运行在内核空间的代码很容易破坏系统,产生不必要的结果,而由于内核和用户空间的分离,可以建立更可靠的系统。

由于Linux内核非常灵活,因此还可以对内核进行配置,即使内核已经构建完成,也可以动态添加新的内核部分。具体来说,可以添加到运行系统中的内核部分就是所谓的内核模块,可以动态加载和卸载。这种机制具有很高的灵活性,能将内核装入极小量的内存中,并能快速加载。然后,内核就可以在运行时添加所需的功能。

图片

2.2.2.4 Linux根文件系统

通用Linux嵌入式系统的最后一个组件是文件系统。文件系统通常包含许多库和应用程序,但要定义一个包含一定数量文件系统的标准并不容易,因为这取决于最终设备的功能和需求。

要分析一个通用文件系统,也许可以先看看系统启动的最低要求是什么。然后,所有希望的额外功能都可以添加到该基本系统中。因此,考虑到一个最小的 Linux 文件系统,它应该包含

  • 初始化程序

一旦Linux内核加载了文件系统,它首先要寻找的就是初始化程序。它是第一个执行的用户空间进程,也是系统中所有其他用户空间进程的父进程或祖先进程。

  • shell和工具

通常情况下,在开发或维护过程中需要shell和它通常提供的工具。大多数情况下,为了在系统中实现这些功能,会使用Busybox等项目在shell环境中提供所有需要的工具。

  • C 库

C 库是最基本的,因为应用程序将使用它。

  • 设备文件

在 Linux 系统中,表示硬件设备的主要方法是使用文件。因此,众所周知的/dev目录是让用户空间应用程序访问设备的基础。

  • 虚拟文件系统

虚拟文件系统并不真实存在,因此它们并不存在于实际的存储设备上,而是由内核在内存中维护,这样就可以像真实目录和真实文件一样与它们进行交互。

虚拟文件系统的例子有:proc目录提供进程信息,允许对执行中的任务进行管理;sys目录提供系统硬件信息。

总之,大多数文件系统都有前面描述的组件,根据最终的应用要求,还有更多的组件。文件系统准备就绪后,Linux 必须对其进行读取,而在项目的生命周期内,Linux 必须应对不同的情况。事实上,由于 Linux 内核的多功能性,它允许从网络、板载闪存和可移动媒体(USB Key、SD 卡)等不同位置加载文件系统。

图片

2.3 如何构建定制的 Linux发行版

一旦分析了Linux嵌入式系统的所有主要组件,就可以开始考虑从哪里下载、配置和编译所有这些源代码,从而获得一个可运行的定制Linux发行版。

图片

如图2.15所示,由于采用了开放源码许可证,几乎整个Linux系统都有源代码,获取Linux发行版的途径也很多。

总结图2.15的内容:作为第一种选择,可以获取Linux系统的所有不同部分,如内核、引导加载程序和所有其他组件,手工构建一个Linux发行版。或者,也可以决定使用桌面Linux发行版,或者按照SoC或电路板供应商的要求,使用软件供应商发布的商业组件。最后,也可以使用发行版构建系统,如图所示,这种方法也得到 SoC/板卡和软件供应商的支持。

第一种介绍的方法,即从源代码构建Linux发行版,可能是非常有趣的学术练习。也许,内核和引导加载器是系统中最容易获得源代码并为目标设备构建的两个部分。相反,如前所述,工具链和可运行的Linux文件系统就不那么容易从头开始构建了,而且可能是棘手而耗时的操作。

造成这种复杂性的主要原因是,有很多组件需要解决,有很多依赖关系需要解决,有很多配置需要设置。
例如,有一个名为”Linux从头开始”的项目。基本上,它提供了一个长达334页的指南,最后,获得的系统会启动,但不会做任何其他事情,这表明要从头开始获得一个工作系统需要做大量的工作。

许多桌面Linux发行版可用于嵌入式设备,SoC/板卡供应商也提供SD卡可启动映像,其中包含Ubuntu或Debian等桌面发行版。

当然,这可能是一种简单快捷的入门方式,但必须考虑到缺乏对文件系统配置的控制能力,因为映像中可能包含大量对实际嵌入式项目无用的软件

总之,Linux允许高度的灵活性和定制化,但为特定设备手工创建定制发行版可能是一项棘手的工作。另一方面,使用已构建好的桌面发行版可能是一个不错的选择,因为它可以快速、方便地使用,但这种选择所失去的是对 Linux 系统的长期控制。

因此,多年来,人们开发了许多工具来帮助开发者创建定制的Linux发行版。如今,这些工具被称为发行版构建工具或发行版管理系统,主要有两种选择。

第一种可能更简单,更容易上手,叫做Buildroot。它支持多种架构和C语言库,基本上提供了可以放入最终文件系统的软件包。它以一组makefile为基础,这些makefile提供了列表,用户可以在列表中选择需要放入最终系统的软件包。Buildroot非常简单易用,但功能并不强大,因此主要用于小型或业余项目。

就发行版管理系统而言,Buildroot的替代品是Yocto项目。它由Linux基金会组织管理,基本上代表了Linux 的行业机构,其主要目的是提供模板、工具和方法,为嵌入式产品创建基于Linux的定制系统。

Yocto比Buildroot更复杂,但它提供了更大的灵活性,能够将所有需要的软件添加到预定义的Linux发行版中,也就是说,使用YP不仅可以构建工具链、引导加载程序、内核和文件系统,还可以创建和管理二进制包,以便在运行时安装到 Linux 发行版中。

因此,它为商业环境中的真正Linux产品提供了所需的长期支持。此外,由于使用广泛,大多数SoC/板卡供应商都为其设备提供Yocto支持。

2.3.1 Yocto 项目

如前所述,Yocto是一个开源项目,可帮助开发人员为嵌入式产品创建基于Linux的定制系统。它是开源社区与工业公司合作的产物,允许以硬件无关的方式创建定制的发行版,即开发人员无需考虑他们想要使用的硬件平台。

Yocto提供了为嵌入式设备创建定制Linux发行版所需的所有工具,并得到了社区的肯定:正如社区所确认的:”Yocto 项目不是一个嵌入式 Linux 发行版,而是为你创建定制的发行版”。

Yocto项目致力于改进软件开发流程,帮助开发者为任何类型的计算设备构建定制的Linux操作系统,事实上,由于与工业界的合作,Yocto允许为所有主要硬件架构创建Linux映像。

此外,它还让定制Linux发行版的创建变得更快、更简单、更便宜。Yocto允许创建定制的发行版,从而实现高度的灵活性和定制化,这在开发嵌入式产品时是至关重要的,因为在嵌入式产品中,控制包含哪些软件是一个关键方面。

“该项目提供了一套灵活的工具和一个空间,世界各地的嵌入式开发人员可在此分享技术、软件栈、配置和最佳实践,从而为嵌入式和物联网设备创建量身定制的 Linux 映像”。

基本上,YP主要是一组用python和shell脚本编写的配方,由名为Bitbake的任务调度程序管理。后者负责生成已配置到各种配方中的内容。

Yocto 项目经过多年发展,已拥有多个项目,如

  • OpenEmbedded core:它提供元数据,用于创建二进制包,即使在运行时也能安装到目标上。
  • Bitbake:它是实际构建镜像的任务调度程序。
  • Poky:代表参考发行版。
  • Devtool:命令行工具,可帮助构建、测试和打包软件。
  • OPKG:轻量级软件包管理系统。
  • CROPS:跨平台开发框架。
  • Autobuilder:自动构建测试和质量保证的项目。

总之Yocto项目由许多其他子项目组成,提供了一个基础,还可以使用新的元层进行扩展。许多 SoC 供应商也对它提供了良好的支持,而且Yocto这个名字是由10-24的SI前缀演变而来的,表示它可以构建非常小的 Linux 系统。

2.3.1.1 组件和工具

OpenEmbedded core

如前所述,Linux 系统通常由不同的组件组成,为了自动构建每个 Linux 组件,可以确定三个主要步骤:

  • 第一阶段包括:获取、解压缩和修补组件源代码。
  • 然后,必须对源代码进行配置、编译和打包。
  • 最后,生成的软件包必须捆绑在一个根文件系统上。

Yocto项目使用OpenEmbedded构建系统来处理Linux组件,该系统将这些不同的步骤分解成不同的操作,称为任务。具体来说,在构建过程的每个不同层次,都有一些任务需要按照特定的配置选项来完成,如图 2.16 所示。

图片

因此,在OpenEmbedded项目中定义了:获取、解压缩和修补软件的任务,配置和构建二进制文件的任务,创建软件包的任务,以及生成最终文件系统的任务。

用于调整任务的配置选项通常由一组变量组成,这些变量可以向构建系统提供以下信息:镜像地址、构建的架构类型等。

任务和配置选项构成了所谓的元数据,在处理开放式嵌入式时,可以确定三种类型的元数据:配方、类和配置选项。
在介绍完Bitbake之后,我们将详细分析不同类型的元数据,因为在详细介绍之前,了解元数据是如何使用的是非常有用的。

总而言之,OpenEmbedded(OE-Core)是一套元数据层,最初由 OpenEmbedded 系统使用,也被 Yocto 项目采用。

Bitbake

在介绍了元数据的基本概念后,Yocto的另一个主要组件就是Bitbake。它首先解析元数据,然后解析依赖关系,最后根据需要序列化的内容或因相互依赖而瘫痪的内容来安排任务。

因此Bitbake可被视为一个任务执行引擎,如图2.17所示,它将元数据(即配方、类和配置文件)作为输入,然后分析依赖关系,最后按照给定的顺序运行不同的任务。

图片

2.3.1.2 主要概念

Recipes

Recipes是元数据的主要组成部分之一,可视为按特定方式执行的任务列表。

例如,如图2.18所示,用于创建软件包的recipe将包含一定数量的任务:其中一些任务涉及获取源代码,另一些任务涉及修补和构建二进制文件,最后还有一些任务将创建软件包。

图片

一旦recipe准备就绪,Bitbake就可以调用它来解决所有依赖关系,并执行定义的任务,最终生成想要的软件包。

除了用于创建软件包的recipe,还可以创建用于创建镜像的recipe,从二进制软件包开始,按照一系列明确定义的操作生成根文件系统。

要执行一个recipe,最简单的命令是在初始化 Yocto 环境后执行以下命令

bitbake recipe-name

命令执行后,Bitbake会查找名为recipe-name且扩展名为.bb的recipe文件,解析方后,执行配方定义的任务。

SRC_URI = "git:// github.com/example.git"
inherit autotools

2.2中显示了一个基本recipe(example.bb)的内容。它能从指定的git仓库下载源代码、编译并创建安装到根文件系统的软件包。在这种特定情况下,一旦运行 bitbake 示例命令,就会执行以下任务:

  • do_fetch:下载源代码
  • do_unpack:提取源代码
  • do_patch:修补源代码
  • do_configure:配置源代码
  • do_compile:编译源代码
  • do_install:安装二进制输出
  • do_package:将二进制文件与文档、调试符号等分离
  • do_package_write:创建软件包(RPM、DEB 等)

看到recipe内容后,我们可能会产生一个主要问题:所有这些任务的定义在哪里?
“inherit autotools”一行就是上一个问题的答案。事实上,recipe可以从所谓的基类继承,这些基类包含一定数量的预定义任务。
当然,基类任务定义并非总能满足特定用例的需要:例如,当运行do_compile任务时,它会查找makefile,但如果下载的源代码中没有makefile呢?
对此,YP也提供了答案,事实上,recipe可以覆盖基类中定义的默认任务,这样就可以根据用例要求调整预定义任务。

Classes

如前所述,recipe通常使用基类来继承基本任务定义。在Yocto项目中,有许多不同的基类用于创建各种用途的配方。类使用 .bbclass 文件扩展名,常见的例子有

  • autotools.bbclass:用于构建基于 autotools 的项目
  • image.bbclass:用于构建根文件系统映像
  • module.bbclass:用于编译内核模块
  • kernel.bbclass:用于构建内核
配置文件

Bitbake和recipe一样,也会解析所谓的配置文件。它们的扩展名为.conf,定义了控制项目构建过程的配置变量。这些文件涵盖不同的配置领域,如:机器配置选项、发行版配置选项、编译器选项和其他常规选项。
第 2.3.2 节将介绍一些主要的配置文件。

分层

通常情况下,元数据都是分层组织的,这样可以将不同类型的定制分离到不同的容器中,也就是以模块化的方式组织元数据,便于将来的更改和扩展。

使用分层方法有很多好处:例如,由于采用了分层架构,因此可以轻松处理不同机器所需的定制。事实上,为满足不同设备的定制要求,通常会在特殊的层中进行,这些层的名称是电路板支持包(BSP)层。
因此,使用这种方法可以隔离支持不同内容的配方和元数据,例如,很容易将图形用户界面和BSP元数据分开。

附加文件

recipe包含在层中,例如,板卡供应商可以BSP层的形式发布配方,但如果要修改现有配方该怎么办?
在Yocto环境中,这种用例也是众所周知的,因此可以创建所谓的附加文件。因此,附加文件中的信息很容易扩展或覆盖配方文件的内容。
附加文件使用 .bbappend 扩展名,其文件命名必须与要扩展的相应配方相同。

2.3.2 开始使用Yocto

在图 2.19 中显示了 Yocto 项目及其主要组件,以概括构建系统的构成及其工作原理。

图片

本节将从实用角度介绍如何下载并开始使用Yocto平台。要开始使用,首先要从git代码库中下载平台源代码。
这可以通过 Linux shell 轻松完成:

git clone git :// git.yoctoproject.org/poky.git 清单 2.3:Y

构建系统目录

默认情况下,Yocto附带的BSP层数很少,源代码目录的结构如图2.20所示。
由于下载的源代码中只集成了少数几个层,因此很可能需要下载并手动添加特定板卡的BSP层以及所有其他希望添加的层。

环境设置

作为开始使用Yocto的第一步,必须运行oe-init-build-env脚本。然后,将自动创建构建目录,目录布局如图 2.20 所示:运行初始化脚本前的 Yocto 目录布局如图 2.21 所示。

图片
图片

配置文件

第一次运行oe-init-build-env脚本后,conf目录中会出现bblayers.conf和local.conf这两个配置文件。
更详细地说,第一个要分析的文件是bblayers.conf。它包含了构建系统要使用的所有图层路径。因此,每次下载新的有用图层时,都必须将其添加到 bblayers.conf 文件中,以便 Bitbake 识别。图 2.22 显示了 bblayers.conf 文件的工作原理及其默认内容。
许多BSP和其他Yocto层可以在http://layers.openembedded.org/layerindex/branch/master/layers/ 上找到。
另一方面,local.conf文件包含特定构建的所有本地配置,例如,在local.conf文件中定义了要使用的目标机器,以及下载、暂存和编译源代码的所有路径。文件还允许自定义系统构建的映像,如添加软件包、选择希望的内核版本、修改软件包管理系统等。

图片

构建镜像

在初始化Yocto环境、下载BSP层并在local.conf文件中设置正确的机器后,只需执行以下操作即可开始构建Linux镜像:

bitbake image -name

当然,OpenEmbedded 还提供了许多可能的映像。最常见的默认映像有

  • core-image-minimal:基于控制台的小型系统,用于测试目的,因为它是自定义映像的基础。
  • core-full-cmdline:基于控制台的映像,带有全功能的 Linux 系统。
  • core-image-weston:基于 Wayland 的基本镜像,带有一个终端。
  • core-image-x11:基于 x11 的基本镜像,带有终端。

当然,也可以定义自定义镜像,创建集成所有所需特性和功能的新配方。
编译过程结束后,默认情况下,可轻松部署到目标设备的镜像文件会出现在tmp/deploy/images…. 中。

虽然只需执行几条命令就能完成所有工作,但在幕后却发生着不同的事情,如图 2.23 所示,图中总结了从下载 Yocto 项目到获得最终映像的所有主要宏步骤。

图片

SDK创建

除了生成可运行的Linux发行版映像,Yocto还允许生成相应的软件开发工具包(SDK),以便为嵌入式目标设备开发其他软件。要启动SDK创建过程,需要执行以下命令:

bitbake image -namel -c populate_sdk

注意,-c 选项用于执行配方中定义的指定任务。

一旦进程结束,就会创建一个包含目标根文件系统的工具链安装程序。通过这种方式,还可以将工具链安装到其他机器上。

创建新层和新recipe

对于创建新层和新recipe,Yocto 项目提供的工具旨在减少所需的工作量。
具体来说,在初始化Yocto环境后,可以使用开放嵌入式工具中的一些脚本来创建包含示例配方的新图层,从而轻松创建自定义图层。
基本上,图层是由目录、配方和配置文件组成的,因此可以手工创建这些目录和元数据文件。不过,使用所提供的脚本创建包含自定义配置和配方的所需结构更为简单。
更详细地说,可以有效地使用 poky/scripts/yocto-layer 脚本,如 2.6 所述。

./poky/scripts/yocto -layer create NEW_LAYER_NAME

在运行前一条命令后,会要求指定层优先级。默认值为6,但根据所需层的功能,可以选择更高或更低的优先级。一旦选择了优先级值,就可以根据脚本输出创建一个示例配方,然后根据需要进行定制。

图层优先级 更好地理解图层优先级的工作原理可能会很有趣:每个图层都有一个定义的优先级,当多个图层中有相同名称的配方文件时,Bitbake 会使用该优先级来决定哪个图层优先。

更详细地说,数值越大,优先级越高。例如,与BSP和SDK层相比,poky层和开放嵌入式层的优先级较低,事实上,后者位于模板层之上,总体布局如图 2.24 所示。
当某一recipe存在多个附加文件时,层优先级也起着关键作用,在这种情况下,它们将以相反的优先级进行附加,即优先级较高的层内的 bbappend 将在后面添加。

Yocto 构建系统示意图

图2.25概括了Yocto项目:从左上角开始获取源代码,然后在编译前打补丁和配置,然后使用不同的格式(如rpm、deb、db)生成相应应用程序的软件包等等。最后,各种软件包可以合并成一个镜像,如右下角所示。

图片
图片

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/264164.html

联系我们
联系我们
分享本页
返回顶部