目录
1.简介
Poky是Yocto项目的参考发行版。它包含OpenEmbedded构建系统。它提供了构建Linux操作系统栈所要求的全部必要的工具、菜谱和配置数据。正如我们在前面一章中看到的,Poky是打包成简单包的几乎自包含的系统。仅仅有少量额外的组件需要安装在构建主机上以使用Poky。
本章先分析针对开源软件包的典型的工作流。然后解释OpenEmbedded工作流是如何将各个软件包的构建与创建完整的Linux操作系统栈和可启动文件系统镜像的过程集成起来的。有了这些知识,我们就可以详细了解Poky架构及其组件了。
2.构建开源软件包
如果你先前曾为Linux主机系统构建过开源软件包,那么你可能已经注意到了,工作流遵循特定的模式。这个工作流的一些步骤你自己执行,而其他的通常是通过某种自动化(例如Make或者其他开源到二进制的构建系统)来实施的。
- 获取:获取源代码。
- 解压:解压源代码。
- 补丁:针对缺陷修复和增加的功能应用补丁。
- 配置:依据环境准备构建过程。
- 构建:编译和连接。
- 安装:复制二进制和辅助文件到它们的目标目录。
- 打包:为在其他系统上安装而打包二进制和辅助文件。
如果你正在构建仅仅用在你用来构建的主机系统上的软件包,那么通常你将在系统上安装了二进制以后就停止了。然而,如果你希望为了在其他系统上安装和使用而分发二进制,那么你将也包括打包步骤,它创建可以被包管理系统安装的包。
让我们来看看各个步骤。
2.1.获取
所有的一切都是以获取针对软件包的源代码开始。通常,开源软件项目有一个下载区域,从那里源代码、指令、文档以及其他信息可以以包的形式被下载,包通常也是压缩的。理论上听起来很像一个简单的任务,但事实上需要大量对细节的关注。当下载源代码包时,没有通用的要遵循的约定。
当然,每个开源项目有自己的统一资源定位地址(Uniform Resource Locator,URL)来访问它的网站、文件服务器和下载区域。另外,下载可能是通过一个或者更多协议访问的,例如HTTP、HTTPS、FTP、SFTP和其他协议。一些项目可能也提供对已发布版本和来自Git、Subversion、并发版本系统(Concurrent Versions System,CVS;也被称为并发修改系统)等的源代码控制管理系统(Source Control Management,SCM)的源代码开发分支的访问。
通常,从远程位置(例如下载站点或者仓库)获取的源可能由存储在本地文件系统上的补丁和辅助文件来补充。
对于如OpenEmbedded构建系统这样的自动化构建系统来说,这种获取源代码方式的变化性意味着它需要的是灵活,并且其能够为开发者最透明地处理这种变化性。
2.2.解压
在源代码被下载后,必须将其解开并且把它从下载位置复制到你将构建它的位置。通常,开源软件包被封装进包,大部分情况下封装成压缩的tar包,但是CPIO和其他序列化多个文件成单一包的格式也是在使用中的。最常用的压缩格式是GZIP和BZIP,但是一些项目使用其他的压缩方案。再一次说明,构建系统必须能够自动检测源包的格式并且使用正确的工具来解压它。
如果源是从源控制管理系统获得的,那么解压包一般意味着把它们从源控制管理系统检出到BitBake构建它们的地方。
2.3.打补丁
打补丁是通过增加、删除和变更源文件来修改源代码的过程。有很多理由说明为什么源代码在构建前可能要打补丁:应用缺陷和安全修复、增加功能性、提供配置信息、为交叉编译做出调整等。例如,Linux内核需要提供了数百个用于内核构建系统的配置项的文件,例如目标架构、硬件信息、设备驱动等。
应用补丁可能与复制文件到源代码的目录结构中一样简单。在这种情况下,构建系统当然需要知道把文件复制到哪里去。通常,补丁是使用补丁工具来被应用的,它把用diff工具创建的补丁文件作为输入。diff将原始文件和修改过的文件进行比较并且创建了不但包含变化而且包含如文件的名字和路径、修改的精确位置和上下文等元数据的差异文件。这个文件的格式是标准化的,被称为统一格式(unified format)。使用了统一格式的补丁文件可以包含一次打多个文件补丁的信息,并且它可以增加或者删除完整文件。因为所有关于文件被修改、增加或者删除的信息都是在补丁文件中包含的,所以构建系统不需要知道任何关于要打补丁的源代码的目录结构。
补丁被应用的顺序是很重要的,因为补丁可能是互相依赖的。以正确的顺序应用大量补丁可能是困难的任务。Quilt补丁管理系统通过创建补丁栈来维护顺序从而极大地简化了这个任务。在众多其他功能中,Quilt也允许撤回已经应用的补丁和所有依赖补丁。Quilt是一系列最开始为Linux内核开发而现在也经常被其他开源项目使用的shell脚本。
2.4.配置
以源代码的形式提供软件包,服务了这样的目的:用户可以自己针对大范围的目标系统构建软件。随变化性而来的是要求针对软件包的构建环境能够针对目标系统而被正确配置的多样性。精确的配置对于构建主机的CPU架构不同于目标系统的CPU架构这一交叉构建环境是特别重要的。
许多软件包现在为配置而使用GNU构建系统,也被称作Autotools。Autotools是一套目标是使源代码软件包可以移植到很多类UNIX系统的工具。Autotools是反映目标系统和依赖的变化性和多样性的相当复杂的系统。简言之,Autotools从一些列具有特殊源代码体特征的输入文件中创建configure脚本。通过一系列处理步骤,configure创建了特别用于目标系统的makefile。Autotools经常因为难以使用而受到批评。这种困难性,当然,依赖于视角。从用户的视角看,执行单一脚本来配置针对目标系统的源代码包构建环境当然是巨大的收益。希望向他们的软件用户提供便利性的开发者需要理解Autotools的工作方式以及如何正确创建必要的输入文件。而且,它值得努力,并且使用类似针对许多不同目标系统的OpenEmbedded构建系统的自动化构建系统极大地简化构建软件包。
一些软件包使用它们自己的配置系统。在这种情况下,自动化的构建系统需要提供对应调整配置步骤的灵活性。
2.5.构建
大部分的软件包使用Make来从源代码构建二进制文件例如可执行程序文件和库以及辅助文件。一些软件包可能使用其他工具,例如CMake或者针对使用了Qt图形库的软件包的qmake。
2.6.安装
安装步骤复制二进制、库、文档、配置和其他文件到目标系统的正确位置。程序文件通常被安装进/usr/bin(对于用户程序)和/usr/sbin(对于系统管理程序)。库被复制到/usr/lib以及位于/usr/lib之内的特定于应用的子目录。配置文件通常被安装到/etc。虽然关于在哪里安装特定文件有常用的惯例,但是一些软件开发者有时选择不同的目录来安装属于他们软件包的文件。文件系统层级标准(filesystem Hierarchy Standard,FHS)(https://wiki.linuxfoundation.org/en/FHS
)是针对用于UNIX操作系统的文件系统布局的规格说明。
大部分软件包提供作为它们makefile一部分的install目标,它执行安装步骤。正确写下的安装目标使用安装工具来从构建环境中复制文件到它们各自的目标目录。安装工具也可以在复制文件时设置文件属主和权限。
2.7.打包
打包是捆绑软件、二进制和辅助文件到单一用于分发和在目标系统上直接安装的包文件的过程。打包可以像压缩的tar包一样简单,然后用户可以在目标系统上进行获取。
为了便利性和可使用性,大部分软件包捆绑它们的文件和安装程序或者包管理系统一起使用。一些系统包含安装软件和软件包并且创建用于自包含安装的可执行文件。其他系统依赖于已经安装在目标系统上的包管理器,并且仅仅捆绑实际的软件和用于包管理器的元数据信息。所有系统的共同点是,它们不但从软件包中复制文件到目标系统而且验证依赖性和系统配置以避免最终导致系统不可操作的不匹配。
Linux系统通常依赖作为发行版部分的包管理系统而不是使用自包含的安装包。好处是,包管理器,作为唯一的实例,维护系统上的软件数据库,并且软件包在尺寸上更小,因为它们不需要包含安装软件。然而,对每个Linux发行版来说,维护者决定它的包管理系统,这需要软件包针对不同的目标系统而被打包多次。
对Linux发行版来说最常用的包管理系统是RPM包管理器(RPM;最初是红帽包管理器)和dpkg(Debian的包管理程序)。对嵌入式设备来说,Itsy包管理系统(ipkg)已经获得了流行。Ipkg是类似dpkg的轻量级系统。Ipkg的开发是被中断的,并且很多一直使用ipkg的嵌入式项目现在在使用opkg,它是由Openmoko项目从ipkg派生出来的。Opkg是以C编写的——它是被Yocto项目积极维护的并且被OpenEmbedded和许多其他项目使用着。
安装和打包不一定是连续的步骤;并且它们也是可选的。如果你正在构建本地使用而非再分发的软件包,那么不需要打包软件。如果你是包维护者并且创建用于再分发的包,那么你可能不需要执行在构建系统上安装软件包的步骤。
这里简述的步骤本质上是相同的,不管你是在原生地构建软件包还是执行交叉构建。然而,在设置和配置构建环境以及为交叉构建构建包时,你必须要考虑错综复杂的事物。通过本书,我们解决交叉构建软件的复杂性。
3.OpenEmbedded工作流
图3-1说明了OpenEmbedded工作流。这个工作流不是BitBake固有的。BitBake完全不建立工作流。工作流和它的配置是被元数据定义的,它被组织成不同类别的文件。
3.1.元数据文件
元数据文件被划分成两个类别:配置文件和菜谱。
3.1.1.配置文件
配置文件包含简单变量赋值形式的全局构建系统设置。BitBake在全局数据字典中维护变量设定,并且它们可以在任何元数据文件中被访问到。变量可以被设置在配置文件中并且被另外的配置文件覆盖。菜谱可以设置和覆盖变量,但是在菜谱中所做的赋值对于菜谱来说仍然是本地的。BitBake对于赋值元数据变量采用了特殊的语法。赋值和覆盖元数据变量的优先级由多个因素决定,例如层结构、层优先级、文件解析顺序以及赋值语法。我们将在第4章中解释BitBake元数据语法和优先级的细节。
BitBake区分多个不同类型的配置文件,但是都有相同的文件扩展名.conf。
- BitBake主配置文件(bitbake.conf)
BitBake的主要配置文件被命名为bitbake.conf。BitBake期望这个文件存在于在它的元数据搜索路径下列出的所有目录中。这个文件包含所有默认配置设置。其他配置文件和菜谱通常根据它们的特定需求而覆盖这个文件中的一些变量设置。
文件bitbake.conf是OpenEmbedded核心(OpenEmbedded Core)元数据层的部分,并且可以在那个层的conf配置文件子目录中找到。
- 层配置文件(layer.conf)
OpenEmbedded构建系统使用层来组织元数据。层本质上是目录和文件的层级结构。每个层有自己的名字为layer.conf的配置文件。这个文件包含了针对这个层的菜谱文件的路径设置和文件模式。文件layer.conf可以在层的conf子目录中找到。
- 构建环境层配置(bblayers.conf)
构建环境需要告诉BitBake它需要什么层来针对它的构建过程。文件bblayers.conf提供BitBake关于什么层要包含在构建过程中以及在哪里找到文件路径的信息。每个构建环境有自己的bblayers.conf文件,它可以在构建环境的conf子目录中找到。
- 构建环境配置(local.conf)
构建环境的本地配置是通过名为local.conf的配置来提供的。文件local.conf包含应用到特定构建环境的设置,例如到下载位置、构建输出和其他文件的路径;针对目标系统的配置设置,例如目标机器、包管理系统以及分发策略;和许多其他设置。文件local.conf可以在构建环境的conf子目录中找到。
- 发行版配置(.conf)
发行版配置文件包含反映应用到由OpenEmbedded构建系统构建的特殊发行版的策略的变量设置。对于Poky参考发行版,默认的镜像名字也是Poky,它的配置设置包含在名为poky.conf文件中。发行版策略设置通常包含工具链、C库和发行版名字等。发行版通过设置在构建环境的local.conf文件中的变量DISTRO来被选择。当然,不限于由Poky作为参考所提供的发行版策略。你可以创建你自己的发行版策略文件并且在构建环境中使用它。
发行版配置文件通常在定义发行版的层(例如meta-yocto层)的conf/distro子目录中找到。
- 机器配置(.conf)
OpenEmbedded工作流最强力的特性之一是它能够严格区分构建过程中依赖于特殊硬件系统、机器和其架构的部分和不依赖的部分。这种能力极大地简化了板支持包的创建,允许它们仅仅提供依赖于硬件的必要部分,并补充构建系统的机器独立部分。因此,对另外机器构建相同的Linux发行版是如同用另一个板支持包替换板支持包一样简单的。
这个架构的主要部分由机器配置文件组成,该文件包含由构建需要机器特定适配的软件包的菜谱引用的机器相关性的变量设置。机器配置文件是以机器命名的,并且可以在板支持包层的conf/machine子目录中找到。
3.1.2.菜谱
BitBake菜谱形成构建系统的核心,因为它们定义针对软件包的工作流。菜谱包含用于BitBake的关于如何通过实施在3.1节中列出的过程步骤而构建特定软件包的指令。BitBake菜谱以它们的.bb文件扩展名标识。
菜谱包含简单的变量复制和以可执行元数据(executable metadata)形式存在的构建指令,构建指令本质上是执行过程步骤的函数。我们在下一章讨论BitBake内幕时会解释可执行元数据和BitBake任务的细节。
与配置文件相反,所有在菜谱中做出的变量赋值都是仅仅本地于菜谱的。虽然菜谱通常引用在配置文件中做出的变量设置并且有时为了它们的目的而覆盖变量设置,但是所有设置都是保持本地于菜谱的。
许多软件包是以很相似的方式被构建出来的,这种方式使用遵循相同过程步骤的几乎相同的构建指令。在调整仅仅一些特定于软件包的部分时重复性地复制相同的菜谱将导致大量多余的努力。因此,BitBake提供了类的概念——一种简单的允许菜谱可以容易地在通用工作流中共享的继承机制。类可以被任何BitBake层所定义并且被它们的.bbclass文件扩展所识别出来。
另外的针对菜谱、促进重用的BitBake机制是追加文件(append files)——通过它们的.bbappend文件扩展而被识别出来。追加文件通常由构建在其他层之上的层根据针对它们的特殊需求来优化那些层中包含的菜谱。在大部分情况下,它们会覆盖变量设置或者修改变量设置。追加文件拥有和从其他它们正在追加的层来的核心菜谱相同的基础文件名。
3.2.工作流过程步骤
由OpenEmbedded核心元数据层确立和由BitBake执行的工作流本质上遵循在3.1节中列出的步骤。
3.2.1.源获取
菜谱召集源(例如源文件包、补丁和辅助文件)的位置。BitBake可以从构建主机本地或远程地借助网络从外部源仓库获取源。源文件可以以大量不同的格式呈现,例如普通或者压缩的tar包。它们可以借由文件传输协议而被获取,也可以从例如Git、SVN等的源控制管理(Source Control Management,SCM)系统获取。
菜谱通过在变量SRC_URI中包含源文件的统一资源标识符(Uniform Resource Identifier,URI)来指定源文件的位置。在SRC_URI中的统一资源标识符经常指向软件包的上游源仓库,例如文件下载服务器或者上游项目的源控制管理系统。
在尝试从由菜谱的SRC_URI变量指定的上游仓库中下载源软件包之前,BitBake先检查本地的下载目录以确认正确版本的源文件是否已经被获取下来。如果它在本地下载区域找不到源,那么BitBake尝试从一列被称为预先镜像(premirror)(如果它们被配置了)的镜像文件服务器上获取源文件。如果没有任何预先镜像包含必要的文件,那么BitBake尝试实际的、由SRC_URI指定的上游仓库。如果它从那里找不到文件或者如果上游仓库是无法访问的,那么BitBake尝试从第2个列表的镜像服务器下载文件。在本书的上下文中,我们称这些服务器为后镜像(postmirror),虽然在OpenEmbedded术语中,它们仅仅被称为镜像(mirrors)。
Yocto项目维护了具有高可用性的文件服务器,团队把所有上游软件包放在这些服务器上。Poky发行版配置命令BitBake在尝试直接从上游仓库下载文件之前使用Yocto项目镜像。使用Yocto项目镜像使得构建更少地依赖上游文件服务器的可用性。
你也可以通过设置作为你自己构建基础设施一部分的镜像来维护你构建中包含的源的直接控制。
3.2.2.源解压和打补丁
一旦源被下载到本地的下载目录,它们将被解压进本地构建环境中。如果任何补丁被指定成源下载的一部分,那么使用Quilt来应用它们。
通常,源包是不适合于交叉构建的,因此大部分补丁都是集成补丁,修改了使用BitBake进行正确构建的源代码。
3.2.3.配置、编译和安装
通过它的类,OpenEmbedded提供了各种模式来构建标准软件包,例如基于Make的包、基于GNU Autotools的包和基于CMake的包。这些模式提供了标准化的方法来指定定制化的环境设置。在第8章中,我们将探索用BitBake通过标准模式构建包以及定制化它们的细节。
虽然配置、编译和安装是构建过程中不同的步骤,但它们通常是在相同的类中被解决的,因为它们都包含调用包自己构建系统的部分。
安装步骤是使用pseudo 命令来执行的,它允许特殊文件的创建和被正确设置的属主、属组以及其他等权限。所有文件是被安装进私有的、存在于针对特定包的构建环境中的系统根目录中。
3.2.4.输出分析和打包
在输出分析中,由前一个步骤生成和安装的软件按照它的功能被分类成:运行时文件、调试文件、开发文件、文档和语言环境。这允许文件为包管理系统而被拆分进多个物理包中。
在分析之后,包通过使用一个或者多个常见的打包格式RPM、dpkg和ipkg而被创建。
BitBake为在构建环境配置文件local.conf的PACKAGE_CLASSES变量中包含的包管理系统类创建包。虽然BitBake可以为一个或者多个类创建包,但是它只使用第一个列出的类来为发行版创建最终的根文件系统。
3.2.5.镜像创建
针对发行版的根文件系统的各种镜像是使用来自打包步骤的包仓库创建的。使用包管理系统将包从包仓库安装进根文件系统试运行区域。
哪些包被安装进镜像,是由集合了针对基于定义的需求集的工作系统的功能集的镜像菜谱决定的。例如,最小镜像可能包含仅仅足够启动带有最少基础应用集合的命令行操作的包,而带有图形用户界面的镜像可能包含X服务器和许多其他应用包。
镜像创建是由core-image类处理的,其中,它评估变量IMAGE_INSTALL来判断要包含在镜像中的包的列表。
镜像可以以多种格式被创建,包括用于解压在格式化的文件系统中的tar.bz2,以及其他格式,例如ext2、ext3、ext4和jffs,它们可以被直接比特复制到合适的存储设备。
3.2.6.软件开发工具包生成
作为格外的步骤,它不是标准构建过程的一部分,带着创建可启动操作系统栈的目的,软件开发工具包(Software Development Kit,SDK)可以被创建。
软件开发工具包包含了针对开发主机的原生应用,例如交叉工具链、QEMU模拟器和安装脚本。它可能也包含和模拟器一起使用的、基于镜像创建步骤内容的根文件系统镜像。软件开发工具包可以被应用开发者用来创建和测试应用程序,其使用与构建目标系统时相同的环境,而没有实际使用OpenEmbedded构建系统。
软件开发工具包和它的工具可能从命令行直接应用在开发主机上,并且是通过与Eclipse集成开发环境集成而被使用。对于后者来说,Yocto项目提供了用于Eclipse的、可以直接被从Eclipse工作台安装的插件。