目录
3 Configuration, Compilation, and Staging
7 Stamp Files and the Rerunning of Tasks
在菜谱中添加systemd-networkd.service
Yocto开机后检查systemd-networkd服务是否正常启动
BitBake中的优先选择变量PREFERRED_PROVIDER
Yocto Project概述
Yocto Project是一个开源协作项目,它帮助开发人员定制基于Linux的系统,这些系统是为嵌入式产品而设计的,与产品的硬件架构无关。Yocto Project提供了一个灵活的工具集和一个开发环境,允许全世界的嵌入式开发人员通过共享技术、软件堆栈、配置和最佳实践进行协作,以生成这些定制的Linux镜像。
如下图所示,Yocto Project至少包含三个关键的开发元素。
- YP:一组集成工具,使嵌入式Linux成功运行,包括自动构建和测试工具,板级支持和许可证合规流程,以及基于Linux的自定义嵌入式操作系统的组件信息
- Poky:参考嵌入式发行版
- OpenEmbedded:构建系统
架构
灰色框是构建发行版的输出目录,里面包含构建环境时自动生成的两个.conf文件(即配置文件--你想要构建什么机型的发行版,以及所包想要实现的功能的文件路径),灰色框左边黄色框中所列出的四个选项(商业软件、用户界面、中间件、板级支持包)都可以将他们的路径添加到bblayers.conf中。这样在编译发行版时才可以把这些信息包含进去。灰色框中的蓝色框中是构建输出的一些文件,如参考映像,许可证,打包文件,SDK等)。最下面的黑色框则是构建发行版的一些基础文件,也就是下载到电脑上的POKY文件,它提供了一个构建Linux开发版的基础环境。
每个目录下主要有三级目录构成:meta-xxx -> recipes-yyy -> zzz/ttt.bb。
meta-xxx就是layer(菜谱的分类如川菜谱、粤菜谱,xilinx、freescale),recipes-yyy就是Metadata(具体某一本菜谱),zzz就是菜谱上具体的一个配方。
meta-xxx有的可以从官方下载,然后拿过来经过配置后直接可使用,下载网址:http://git.yoctoproject.org/cgit/cgit.cgi/
Yocto Project术语
- Configuration Files:保存变量,用户定义变量和硬件配置信息的全局定义的文件。这些文件告诉开放的嵌入式构建系统要构建什么以及要放入图像以支持特定平台的内容。
- Extensible Software Development Kit (eSDK):应用程序开发人员的自定义SDK。该eSDK允许开发人员将其库和编程更改合并回图像,以使其代码可供其他应用程序开发人员使用。
- Layer:相关食谱的集合。图层允许您合并相关元数据以自定义构建。层还隔离构建多个体系结构时使用的信息。图层在覆盖以前的规范方面是分层的。您可以从Yocto Project中包含任意数量的可用图层,并通过在图层后面添加图层来自定义构建。
- Metadata:Yocto Project的关键元素是用于构建Linux发行版的元数据,并包含在构建图像时开放嵌入构建系统解析的文件中。通常,元数据包括食谱,配置文件和其他参考构建指令本身的信息,以及用于控制构建内容和构建效果的数据。元数据还包括用于指示使用什么版本的软件,从何处获得它们的命令和数据,以及用于修复错误或自定义软件以用于软件本身的更改或添加(补丁或辅助文件)在特定情况下。OpenEmbedded-Core是一组重要的经过验证的元数据。
- OpenEmbedded Build System:术语“BitBake”和“Build System”有时用于OpenEmbedded Build System。BitBake是一种任务调度程序和执行引擎,可解析指令(即食谱)和配置数据。在解析阶段之后,BitBake创建一个依赖树来排序编译,安排所包含代码的编译,最后执行指定的自定义Linux镜像(发行版)的构建。BitBake类似于make工具。在构建过程中,构建系统跟踪依赖关系并执行包的本机或交叉编译。作为交叉构建设置的第一步,框架尝试创建适合目标平台的交叉编译器工具链(即Extensible SDK)。
- OpenEmbedded-Core (OE-Core):OE-Core是由基础食谱,类和相关文件组成的元数据,这些文件在许多不同的OpenEmbedded派生系统(包括Yocto Project)中都很常见。OE-Core是由OpenEmbedded社区开发的原始存储库的策划子集,该存储库已缩减为较小的核心连续验证食谱集。结果是严格控制和质量保证的核心配方集。
- Packages:在Yocto Project的背景下,该术语是指通过烘烤产生的配方的包输出(即“烘焙配方”)。包通常是从配方来源产生的编译二进制。
- Poky:Poky是参考嵌入式发行版和参考测试配置。Poky提供以下内容:
- 基本功能分布图,用于说明如何自定义分布。
- 测试Yocto Project组件的方法(即Poky用于验证Yocto Project)。
- 可以通过它下载Yocto Project。
- Poky不是产品级分布。相反,这是定制的良好起点。注意:Poky是OE-Core顶部的集成层。
- Recipe:最常见的元数据形式。配方包含用于构建包的设置和任务(即说明)列表,然后用于构建二进制镜像。配方描述您获取源代码的位置以及要应用的补丁。食谱描述了库或其他食谱的依赖关系以及配置和编译选项。相关配方合并为一层。
假如用烹饪一桌酒席来形容构建发行版,则Yocto就是饭店名,Poky就是厨房(以及提供作为参考的菜的搭配套餐),Metadata就是烹饪资源(.bb/.bbappend表示配方/配方上的贴士,.conf表示厨房里的管事的小组长),Layers就是菜谱的分类(如川菜谱、粤菜谱),Bitbake就是厨师,Output就是得到的一桌酒席
开箱食用
构建主机配置
构建主机要符合如下要求:
-
50 GB的磁盘空间
-
运行一个主流的Linux发行版(Fedora, openSUSE, CentOS, 或者 Ubuntu)
-
Git 1.8.3.1或者更高版本
-
tar 1.27或者更高版本
-
Python 3.4.0或者更高版本
另外还需要按照如下软件包:
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint3 xterm
使用Git下载Poky
使用下面的命令克隆Poky仓库
$ git clone git://git.yoctoproject.org/poky
$ cd poky
$ git fetch --tags
$ git tag
$ git checkout tags/yocto-3.1 -b my-yocto-3.1
构建镜像
使用以下步骤构建镜像,构建过程创建整个Linux发行版,包括工具链。
-
初始化构建环境:在poky目录中,运行 oe-init-build-env 环境设置脚本以在构建主机上定义Yocto Project的构建环境。
source poky/oe-init-build-env
You had no conf/local.conf file. This configuration file has therefore been
created for you with some default values. You may wish to edit it to, for
example, select a different MACHINE (target hardware). See conf/local.conf
for more information as common configuration options are commented.You had no conf/bblayers.conf file. This configuration file has therefore been
created for you with some default values. To add additional metadata layers
into your configuration please add entries to conf/bblayers.conf.The Yocto Project has extensive documentation about OE including a reference
manual which can be found at:
https://docs.yoctoproject.orgFor more information about OpenEmbedded see their website:
https://www.openembedded.org/
### Shell environment set up for builds. ###You can now run 'bitbake <target>'
Common targets are:
core-image-minimal
core-image-sato
meta-toolchain
meta-ide-supportYou can also run generated qemu images with a command like 'runqemu qemux86'
Other commonly useful commands are:
- 'devtool' and 'recipetool' handle common recipe tasks
- 'bitbake-layers' handles common layer tasks
- 'oe-pkgdata-util' handles common target package tasks
添加bitbake环境变量
export PATH=$PATH:/home/lucky/Yocto/poky/bitbake/bin
编译minimal镜像
bitbake core-image-minimal
使用QEMU模拟器启动镜像
runqemu qemux86-64
OpenEmbedded构建系统
Poky是Yocto项目的参考发行版,它包含 OpenEmbedded构建系统(BitBake和 OpenEmbedded-Core)以及一组元数据,可帮助我们开始构建自己的发行版。
OpenEmbedded工作流
OpenEmbedded构建系统 采用了“工作流程”来完成镜像和SDK的生成。下图概述了该工作流程:
以下是“工作流程”的简短步骤:
-
源获取:构建系统从指定位置获取并下载源代码。构建系统支持标准方法,如tarball或源代码存储库系统,如Git。
-
源解压和打补丁:下载源代码后,构建系统会将源提取到应用修补程序的本地工作区。
-
配置,编译和安装:构建系统提供了各种模式来构建标准软件包,例如基于Make,GNU Autotools和CMake的包。运行配置和编译软件的常用步骤后,构建系统讲软件安装到临时暂存区域。
-
输出分析和打包:在输出分析中,由前一个步骤生成和安装的软件按照功能分成:运行时文件,调试文件,开发文件,文档和语言环境。在分析之后,我们选择的二进制包格式(DEB,RPM或IPK)用于汇总和打包软件。
-
QA和健全性检查:在整个构建过程中运行不同的QA和健全性检查。
-
镜像创建:创建二进制文件后,构建系统会生成二进制包提要,用于创建最终的根文件镜像。镜像可以以多种格式被创建,包括用于解压在格式化的文件系统中的tar.bz2,它们可以被直接比特复制到合适的存储设备。
-
软件开发工具包生成:作为格外的步骤:构建系统生成用于并行应用程序开发的自定义可扩展SDK(eSDK)。
通常,构建的“工作流程”包含几个功能区域:
-
用户配置: 可用于控制构建过程的元数据。
-
元数据层: 提供软件,机器和发行版元数据的各种层。
-
源文件: 上游版本,本地项目和SCM。
-
构建引擎: BitBake 控制下的进程 。该块扩展了BitBake如何获取源代码,应用补丁程序,完成编译,分析包生成的输出,创建和测试包,生成镜像以及生成交叉开发工具。
-
包源: 包含输出包(RPM,DEB或IPK)的目录,随后用于构建系统生成的镜像或软件开发工具包(SDK)。
-
镜像: 工作流程生成的镜像。
-
应用程序开发 SDK: 与镜像一起生成或使用BitBake单独生成的交叉开发工具。
下面介绍其中几个重点的功能区域。
用户配置
用户配置有助于定义构建过程。通过用户配置,可以告诉BitBake你要为其构建镜像的目标体系结构,存储下载源的位置以及其他构建属性。
下图显示了常规工作流程图的“用户配置”框的扩展表示 :
BitBake需要一些基本配置文件才能完成构建。这些文件是*.conf文件。最小必要的文件作为示例文件驻留在源目录的build/conf目录中。为了简单起见,这里将源目录称为“Poky Directory”。
Poky内部的meta-poky层包含一个conf目录,其中包含配置文件示例。在源代码oe-init-build-env(构建环境脚本)时,这些示例文件用作创建实际配置文件的基础。
执行环境脚本将创建Build目录。BitBake在构建期间使用Build目录进行所有工作。Build目录有一个conf目录,其中包含本地.conf以及bblayers.conf配置文件。只有在Build目录中不存在时,才会创建这些默认配置文件。
根据脚本的来源,调用不同的子脚本来设置构建目录(Yocto或OpenEmbedded)。具体地说,poky目录中的scripts/oe-setup-builddir设置构建目录,并使用适合于Yocto Project开发环境的配置文件为目录来设定。注意:scripts/oe-setup-builddir脚本使用$TEMPLATECONF变量来确定要定位的配置文件示例。
下面程序清单显示了在构建已经运行后的前2级目录:
.
└── conf
├── bblayers.conf
├── local.conf
└── templateconf.cfg
新创建的环境主要包含conf子目录和2个文件:bblayers.conf和local.conf。
local.conf,这个文件包含用户构建环境的所有配置设置。
#
# This sets the default machine to be qemux86-64 if no other machine is selected:
MACHINE ??= "qemux86-64"
#DL_DIR ?= "${TOPDIR}/downloads"
#SSTATE_DIR ?= "${TOPDIR}/sstate-cache"
#TMPDIR = "${TOPDIR}/tmp"
DISTRO ?= "poky"
PACKAGE_CLASSES ?= "package_rpm"
#SDKMACHINE ?= "i686"
USER_CLASSES ?= "buildstats image-mklibs image-prelink"
#TESTIMAGE_AUTO_qemuall = "1"
#OE_TERMINAL = "auto"
# By default disable interactive patch resolution (tasks will just fail instead):
PATCHRESOLVE = "noop"
- Target Machine Selection:由MACHINE变量控制。
- Download Directory:由DL_DIR变量控制。
- Shared State Directory:由SSTATE_DIR变量控制。
- Build Output:由TMPDIR变量控制。
- Distribution Policy:由DISTRO变量控制。
- Packaging Format:由PACKAGE_CLASSES变量控制。
- SDK Target Architecture:由SDKMACHINE变量控制。
- Extra Image Packages:由EXTRE_IMAGE_FEATURES变量控制。
bblayers.conf包含用户构建环境的层设置,比如下面这个典型的bblayers.conf文件:
# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"
BBPATH = "${TOPDIR}"
BBFILES ?= ""
BBLAYERS ?= " \
/home/lucky/Yocto/poky/meta \
/home/lucky/Yocto/poky/meta-poky \
/home/lucky/Yocto/poky/meta-yocto-bsp \
"
元数据层
元数据层是分组和组织菜谱,类,配置文件和其他元数据到逻辑实体中的容器。通常,存在三种类型的层输入:
-
元数据(.bb+补丁): 包含用户提供的配方文件,补丁和附加文件的软件层。一个很好的例子可能是 meta-qt5,该层适用于桌面和嵌入式的流行的Qt跨平台应用程序开发框架。
-
机器BSP配置: 板支持包(BSP)层(即下图中的“BSP层”),提供特定于机器的配置。此类信息特定于特定目标体系结构。来自 Poky的BSP层的一个很好的例子是meta-yocto-bsp层。
-
发行配置: 发行层(即下图中的“Distro Layer”),为正在为特定分发构建的镜像或SDK提供顶级或一般策略。例如,默认发行层是meta-poky层。
通常,所有层都具有类似的结构。如果要分发图层,它们都包含许可文件COPYING.MIT,README作为良好实践的说明文件,特别是如果要分发图层,配置目录和配方目录的时候会非常有效。
这些层目录中的每一个都包含名为conf/layer.conf的文件
层配置文件conf/layer.conf的目的是正确设置变量BBPATH和BBFILES以使得BitBake可以找到在该层中包含的菜谱、类和配置文件:
-
BBPATH:BitBake使用这个变量来在名为classes的子目录中定位类(.bbclass文件)和在名为conf的子目录中定位配置文件(.conf文件)以及子目录等。
-
BBFILES:这个变量包含针对菜谱文件的、带有通配符的路径列表。
-
BBFILE_COLLECTIONS:包含已配置层的名字的列表。这个列表被BitBake使用以在它的数据目录中找到其他BBFILE_*变量。通常每个层都增加它自己的名字到这个列表
-
BBFILE_PATTERN:告诉BitBake如何从BBFILES的这一层中定位菜谱文件的正则表达式。层所设置的变量值对应于它增加到BBFILES变量的路径。因为所有在BBFILES中的路径都以层的顶级目录开头,所以这个正则表达式反映了那个惯例。变量的名字必须追加下划线(_)和层的名字。
-
BBFILE_PRIORITY:向包含在该层中的菜谱赋予优先级。变量的名字必须追加层的名字。
源文件
为了使OpenEmbedded构建系统从而创建镜像或其他,它必须能够访问源文件。通用工作流图使用“Upstream Project Releases”、“Local Projects”和“SCMs (optional)”框表示源文件。此图表示镜像源,它在定位源文件时也起着作用,并带有“Source Materials”框。
BitBake使用SRC_URI变量来指向源文件,而不考虑它们的位置。每个配方必须有一个指向源的SRC_URI变量。
另一个在源文件的来源中起重要作用的区域是由DL_DIR变量指向的。这个区域是一个缓存,可以保存以前下载的源文件。您还可以指示OpenEmbedded构建系统从Git存储库创建tarball(这不是默认行为),并使用BB_GENERATE_MIRROR_TARBALLS变量将它们存储在DL_DIR中。
明智地使用DL_DIR目录可以节省构建系统在查找文件时跨越Internet的行程。使用下载目录的一个好方法是让DL_DIR指向构建目录之外的区域。这样做可以在需要时安全地删除构建目录,而不必担心删除任何下载的源文件。
下面是对常规工作流图的源文件区域的更详细的查看:
Upstream Project Releases
上游项目版本以存档文件的形式存在于任何地方(例如tarball或zip文件)。这些文件对应于各个配方。例如,图中的BusyBox、Qt和Dbus都有特定版本。存档文件可以用于任何可以使用配方构建的已发布产品。
Local Projects
本地项目是用户提供的自定义软件。这些软件位于项目的本地位置,可能是用户项目的目录(例如,包含该组使用的开发源树的本地目录)。
包含本地项目的规范方法是使用externalsrc类来包含该本地项目。你可以使用local.conf或者一个配方的append file来覆盖或设置配方指向磁盘上的本地目录来拉入整个源码树。
Source Control Managers (Optional)
构建系统可以从中获取源文件的另一个途径是使用各种源代码管理器(SCMs)的抓取器,比如Git或Subversion。在这种情况下,将克隆或切换存储库。BitBake中的do_fetch任务使用SRC_URI变量和参数的前缀来确定正确的抓取器模块。
在获取存储库时,BitBake使用SRCREV变量来确定要从中生成的特定版本。
有两种镜像:预镜像和常规镜像。PREMIRRORS和MIRRORS变量分别指向这些变量。BitBake在向上游查找任何源文件之前检查预镜像。如果共享目录不是由DL_DIR变量定义的目录,则预镜像是合适的。预镜像通常指向本地的共享目录。
常规镜像可以是Internet上的任何站点,如果主站点由于某种原因无法正常运行,则可以将其用作源代码的替代位置。
构建引擎
OpenEmbedded构建系统使用 BitBake 生成镜像和软件开发工具包(SDK)。该构建引擎主要完成的工作包括:获取源代码,应用补丁程序,完成编译,分析包生成的输出,创建和测试包,生成镜像以及生成交叉开发工具。
从根本上说,BitBake是一个通用的任务执行引擎,它允许shell和Python任务在复杂的任务间依赖性约束中工作时高效并行地运行。从概念上讲,Bitbake是类似Make的构建引擎,但是又有着显著的差异:
BitBake根据提供的构建任务的元数据执行任务。
BitBake包括一个fetcher库,用于从各种位置获取源代码,例如本地文件,源代码控制系统或网站。
要构建的每个单元的指令(例如一个软件)称为“菜谱”文件,并包含有关该单元的所有信息(依赖项,源文件位置,校验和,描述等)。
允许shell和Python任务在复杂的依赖性约束中工作时高效并行地运行。
历史和目标
BitBake最初是OpenEmbedded项目的一部分。它的灵感来自Gentoo Linux发行版使用的Portage包管理系统。2004年12月7日,OpenEmbedded项目团队成员Chris Larson将项目分为两个截然不同的部分:
-
BitBake:一个通用任务执行器
-
OpenEmbedded:BitBake使用的元数据集
BitBake是OpenEmbedded项目的主要基础,该项目被用作诸如Yocto项目之类的Linux项目的构建工具 。在BitBake之前,没有任何其他构建工具能够充分满足有抱负的嵌入式Linux发行版的需求。传统桌面Linux发行版使用的所有构建系统都缺乏重要的功能,并且在嵌入式领域中普遍存在的基于Buildroot的临时系统都不具备可扩展性或可维护性。BitBake的一些重要原始目标是:
-
处理交叉编译。
-
处理包间依赖关系。
-
支持在给定包中运行任意数量的任务,包括但不限于获取上游源,解压缩,打补丁,配置等等。
-
支持多个构建和目标操作系统(例如Cygwin,BSD等)。
-
是自包含的,而不是紧密集成到构建机器的根文件系统中。
-
易于使用BitBake在多个项目之间进行协作以进行构建。
-
提供继承机制以在许多包之间共享公共元数据。
-
处理基本配方的变体(例如native,sdk和multilib)。
-
将元数据拆分为图层,并允许图层增强或覆盖其他图层。
概念
BitBake是一个用Python语言编写的程序。在最高级别,BitBake解释元数据,决定运行所需的任务,并执行这些任务。与GNU Make类似,BitBake控制着软件的构建方式。GNU Make通过“makefile”实现其控制,而BitBake使用“Recipes”。
BitBake元数据
菜谱
BitBake Recipes,由文件扩展名.bb表示,是最基本的元数据文件。这些菜谱文件为BitBake提供以下内容:
-
有关包的描述性信息(作者,主页,许可证等)
-
菜谱的版本
-
现有依赖项(构建和运行时依赖项)
-
源代码所在的位置以及如何获取它
-
源代码是否需要任何补丁,在何处找到它们以及如何应用它们
-
如何配置和编译源代码
-
在目标机器上安装包或创建的包的位置
配置文件
配置文件由.conf扩展表示 ,定义了管理项目构建过程的各种配置变量。这些文件分为几个区域,用于定义计算机配置选项,分发配置选项,编译器调整选项,常规通用配置选项和用户配置选项。主配置文件是示例bitbake.conf文件,它位于BitBake源树conf目录中。
类
由.bbclass扩展名表示的类文件 包含在元数据文件之间共享的有用信息。BitBake源代码树目前附带一个名为的类元数据文件base.bbclass。您可以在classes目录中找到此文件 。该base.bbclass类文件很特殊,因为它总是自动包含在所有配方和类中。此类包含标准基本任务的定义,例如提取,解包,配置(默认为空),编译(运行任何Makefile),安装(默认为空)和打包(默认为空)。这些任务经常被项目开发过程中添加的其他类覆盖或扩展。
图层
图层允许您将不同类型的自定义设置相互隔离。虽然您可能会发现在处理单个项目时将所有内容保留在一个层中很有吸引力,但是组织元数据越模块化,就越容易应对未来的更改。
追加文件
附加文件,这些文件具有 .bbappend文件扩展名,扩展或覆盖现有配方文件中的信息。
BitBake希望每个附加文件都有一个相应的配方文件。此外,附加文件和相应的配方文件必须使用相同的根文件名。文件名只能在使用的文件类型后缀(例如formfactor_0.0.bb和 formfactor_0.0.bbappend)中有所不同。
命名附加文件时,可以使用“%”通配符来匹配配方名称。例如,假设你有一个名为如下的追加文件:
busybox_1.21%.bbappend
该追加文件将匹配任何版本的配方。因此,append文件将匹配以下配方名称: busybox_1.21.x.bb
busybox_1.21.1.bb
busybox_1.21.2.bb
busybox_1.21.3.bb
在最常见的情况下,您可以将追加文件命名为busybox_%.bbappend完全独立于版本。
包含文件(.inc)
通过使用include和require指令,任何元数据文件可以包含其他文件。包含文件通常提供多个元数据文件共享的元数据。包含文件的内容被插入到正在包含的元数据文件的各个指令所在的位置。这当然承担着圆形夹杂的风险,BitBake会检测并对这种情况作出警告。文件包含不限于相同的层,但是层中的菜谱可以包含来自另一层的文件。.inc文件后缀是完全惯例的。一个元数据文件可以包含任何其他元数据文件;然而,包含可执行元数据的文件可能仅仅被菜谱、追加文件和类所包含。
BitBake命令
该bitbake命令是BitBake工具的主要接口。可以查看命令帮助:
$ bitbake -h
下面是一些示例:
针对单个菜谱执行任务
以下命令在foo_1.0.bb菜谱文件上运行构建任务,这是默认任务:
$ bitbake -b foo_1.0.bb
以下命令在foo.bb菜谱文件上运行clean任务 :
$ bitbake -b foo.bb -c clean
对一组菜谱文件执行任务
bitbake命令在不使用“--buildfile”或“-b”时仅接受“PROVIDES”。你不能提供任何其他东西。默认情况下,配方文件通常“提供”其“包名”,如以下示例所示:
$ bitbake foo
下一个示例“提供”包名称,并使用“-c”选项告诉BitBake只执行do_clean任务:
$ bitbake -c clean foo
执行任务和菜谱组合列表
指定多个目标时,BitBake命令行支持为各个目标指定不同的任务。
$ bitbake myfirstrecipe:do_taskA mysecondrecipe:do_taskB
生成依赖图
BitBake能够使用dot语法生成依赖图。您可以使用Graphviz中的dot工具 将这些图形转换为图像 。
以下是创建依赖关系图的两个示例。第二个示例省略了常见的依赖:
$ bitbake -g foo
$ bitbake -g -I virtual/kernel -I eglibc foo
BitBake食谱语法
了解BitBake食谱文件语法对于编写食谱非常重要。以下列表概述了构成BitBake食谱文件的基本项目。有关更完整的BitBake语法描述,请参阅BitBake用户手册的“ 语法和操作符 ”一章。
变量赋值和操作符
变量赋值允许将值赋给变量。赋值可以是静态文本,也可以包含其他变量的内容。除了赋值,还支持追加和前增操作符。
以下示例显示了在食谱中使用变量的一些方法:
S = ${WORKDIR}/postfix-${PV} CFLAGS += -DNO_ASM SRC_URI_append = file://fixup.patch
函数
函数提供一系列要执行的操作。通常使用函数来覆盖任务函数的默认实现或补充默认函数(即追加或前增到现有函数)。标准函数使用sh shell语法,但也可以访问OpenEmbedded变量和内部方法。
以下是sed食谱中的示例函数 :
do_install () { autotools_do_install install -d ${D}${base_bindir} mv ${D}${bindir}/sed ${D}${base_bindir}/sed rmdir ${D}${bindir}/ }
只要新函数不替换或补充默认功能,也可以实现在现有任务之间调用的新函数。你可以用Python而不是shell实现函数。但是在大多数食谱中都没有看到这两种选择。
关键字
BitBake食谱仅使用几个关键字。你可以使用关键字包含常用函数(inherit),从其他文件加载食谱的一部分(include和 require)以及将变量导出到环境(export)。
以下示例显示了其中一些关键字的用法:
export POSTCONF = ${STAGING_BINDIR}/postconf inherit autoconf require otherfile.inc
注释(#)
以散列字符(#)开头的任何行都被视为注释行而被忽略:
# This is a comment
行继续(\)
使用反斜杠(\)字符将语句拆分为多行。将斜杠字符放在要在下一行继续的行的末尾:
VAR = A really long \ line
注意
斜杠字符后面不能包含任何字符,包括空格或制表符。
使用变量(${VARNAME})
使用${VARNAME}语法访问变量的内容:
SRC_URI = ${SOURCEFORGE_MIRROR}/libpng/zlib-${PV}.tar.gz
注意
重要的是要理解以这种形式表示的变量的值不会立即扩展替换。这些表达式的扩展会在稍后按需发生(例如,通常在引用变量的函数执行时)。此行为可确保变量值最适合最终使用它们的上下文。在极少数情况下,你确实需要立即扩展变量表达式,您可以使用:=运算符而不是=在进行赋值时,但通常不需要这样做。
引用所有赋值(value)
在所有变量使用双引号(例如value)赋值。以下是一个例子:
VAR1 = ${OTHERVAR}
VAR2 = The version is ${PV}
条件赋值(?=)
条件赋值用于为变量赋值,但仅限于当前未设置变量的情况。使用问号后跟等号(?=)来进行条件赋值的“软”赋值。通常,“软”赋值在local.conf文件中用于从外部环境获取的变量。
这是一个示例:如果VAR1如果当前为空, 则设置为“New value”。但是,如果VAR1已经设置,它将保持不变:
VAR1 ?= New value
在下一个示例中,VAR1保留值“Original value”:
VAR1 = Original value
VAR1 ?= New value
追加(+=)
使用加号后跟等号(+=)将值附加到现有变量。
注意
此运算符在变量的现有内容和新内容之间添加空格。
这是一个例子:
SRC_URI += file://fix-makefile.patch
前增(=+)
使用等号后跟加号(=+)将值前增到现有变量。
注意
此运算符在新内容和变量的现有内容之间添加空格。
这是一个例子:
VAR =+ Starts
追加(_append)
使用_append运算符将值附加到现有变量。此运算符不会添加任何额外空格。此外,此运算符在所有的+=和=+运算符起效后起效,并且在所有=号赋值发生之后才起效。
以下示例是显式地在开头添加空格,以确保附加值未与现有值合并:
SRC_URI_append = file://fix-makefile.patch
您还可以将_append操作符与覆盖一起使用,这将导致仅对指定的目标或机器执行操作:
SRC_URI_append_sh4 = file://fix-makefile.patch
前增(_prepend)
使用_prepend运算符将值前增到现有变量。此运算符不会添加任何额外空格。此外,此运算符在所有的+=和=+运算符起效后起效,并且在所有=号赋值发生之后才起效。
以下示例是显式地在末尾添加空格,以确保前置值未与现有值合并:
CFLAGS_prepend = -I${S}/myincludes
您还可以将_prepend操作符与覆盖一起使用,这将导致仅对指定的目标或机器执行操作:
CFLAGS_prepend_sh4 = -I${S}/myincludes
覆盖
您可以使用覆盖来有条件地设置值,通常基于食谱的构建方式。例如,要将任何目标机器的KBRANCH变量值设置 为“standard/base”,qemuarm机器除外,它应设置为“standard/arm-versatile-926ejs”,可以执行以下操作:
KBRANCH = standard/base
KBRANCH_qemuarm = standard/arm-versatile-926ejs
缩进
使用空格进行缩进而不是制表符。对于shell函数,两者目前都有效。但是,Yocto项目的策略是在shell函数中使用制表符。我们需要意识到某些层的所有缩进都使用空格。
将Python用于复杂操作
对于更高级的处理,可以在变量赋值期间使用Python代码(例如,对变量进行搜索和替换)。
使用${@python_code}语法表示使用Python代码为变量赋值:
SRC_URI = ftp://ftp.info-zip.org/pub/infozip/src/zip${@d.getVar('PV',1).replace('.', '')}.tgz
Shell函数语法:
在描述要执行的操作列表时,编写shell函数就像编写shell脚本一样。应确保脚本使用通用脚本,并且不需要任何bash或其他特定shell的功能。同样的考虑也适用于你可能希望使用的各种系统实用程序(例如sed, grep,awk等)。如果有疑问,就应该检查多个实现 - 包括来自BusyBox的实现。
Yocto构建过程
1 Source Fetching
构建配方的第一步是获取和对源代码解包:
图中do_fetch
和do_unpack任务会获取源文件并将它们解压到Build目录中。
对于配方的SRC_URI语句中的每个本地文件(例如file://
),OpenEmbedded构建系统将获取配方文件的校验和,并将校验和插入do_fetch
任务的签名中。如果修改了任何本地文件,则会重新执行do_fetch
任务和依赖它的所有任务。
默认情况下,所有操作都在Build目录中完成,该目录具有已定义的结构。
每个配方在构建目录中都有一个区域,解压后的源代码就在那里。S变量指向此区域,以获取配方的未打包源代码。任何给定配方的目录名都是从几个不同的变量定义的。上图和下表描述了构建目录的层次结构:
TMPDIR:
OpenEmbedded构建系统在构建期间执行所有工作的基目录。默认的基本目录是tmp
目录。PACKAGE_ARCH:
构建的一个或多个包的体系结构。因一个或多个包的最终目的(即机器架构、构建主机、SDK或特定机器),PACKAGE_ARCH
会有所不同。TARGET_OS:
目标设备的操作系统。典型就是“linux”(例如“qemux86-poky-linux”)。- PN:用于构建包的配方名称。这个变量可以有多种含义。但是,当在输入文件的上下文中使用时,
PN
表示配方的名称。 WORKDIR:
OpenEmbedded构建系统构建配方的位置(即创建包的工作处)。S:
给定配方的解压源文件。
在上图中,请注意存在两个示例层次结构:一个基于包的体系结构(即PACKAGE_ARCH
),另一个基于机器的(即MACHINE
)。它们底层结构是相同的,区别是OpenEmbedded构建系统用作构建目标(例如,通用体系结构、构建主机、SDK或特定机器)。
2 Patching
获取并解包源代码后,BitBake将查找补丁文件并将其应用于源文件:
do_patch 任务会使用配方的SRC_URI 语句和FILESPATH 变量来定位适用的补丁文件。
补丁文件的默认处理文件具有*.patch
或 *.diff
文件类型。可以使用SRC_URI
参数来更改构建系统识别补丁文件的方式。
BitBake将按照查找补丁程序的顺序为单个配方查找并应用多个补丁程序。FILESPATH
变量在构建系统时用于搜索补丁文件的默认目录集。一旦找到,补丁程序就会应用到配方的源文件中,这些文件位于S 目录中。
3 Configuration, Compilation, and Staging
给源代码打补丁后,BitBake将执行配置和编译源代码的任务。一旦编译开始后,文件将被复制到保留区域(暂存),以准备打包:
构建过程中的步骤包括以下任务:
- do_prepare_recipe_sysroot:此任务在
${
WORKDIR}
中设置两个sysroots (即recipe-sysroot
和recipe-sysroot-native
),以便在打包阶段,sysroots 可以包含任务配方所依赖的do_populate_sysroot 任务内容。sysroot存在于在主机系统上运行的目标和本机二进制文件。 do_configure
:此任务通过启用和禁用一些软件的构建时间和配置选项来配置源代码。配置可以来自配方本身,也可以来自继承的类。此外,软件本身可能会根据构建它的目标进行自我配置。do_configure 任务处理的配置特定于由配方生成的源代码的配置。如果使用的是autotools 类,则可以通过使用额外的EXTRA_OECONF 或PACKAGECONFIG_CONFARGS 变量添加其他配置选项。do_compile
:一旦完成了一个配置的任务,BitBake将使用do_compile 任务编译源代码。编译发生在B 变量指向的目录中。默认情况下,B 目录与S 目录相同。do_install
:编译完成后,BitBake执行do_install 任务。此任务从B
目录复制文件,并将它们放在D 变量指向的保留区域中。稍后将使用此保存目录中的文件进行打包。
4 Package Splitting
在configured、compiled和staged源代码之后,构建系统将分析结果并将输出拆分为包:
do_package 和do_packagedata 任务会结合起来分析在D 目录中找到的文件,并根据可用的包和文件将它们拆分为子集。分析包括以下内容以及其他项目:拆分调试符号、查看包之间的共享库依赖项以及查看包关系。
do_packagedata
任务根据分析创建包元数据,以便生成系统最终的包。do_populate_sysroot 任务将do_install 任务安装的文件的子集转移(复制)到相应的sysroot中。分析和包拆分过程的工作、阶段和中间结果使用几个方面:
-
PKGD:在将包拆分为单个包之前,包的目标目录(即
package
)。 -
PKGDESTWORK:PKGDESTWORK任务用于保存包元数据的临时工作区(即
pkgdata
)。 -
PKGDEST:拆分包后的父目录(即
packages-split
)。 -
PKGDATA_DIR:一个共享的全局状态目录,用于保存打包过程中生成的打包元数据。打包过程会将
PKGDESTWORK
中的元数据复制到PKGDATA_DIR
区域,在那里它将成为全局可用的。 -
STAGING_DIR_HOST:要在其上运行组件的系统sysroot路径(即
recipe-sysroot
)。 -
STAGING_DIR_NATIVE:为构建主机生成组件时使用的sysroot路径(即
recipe-sysroot-native
)。 -
STAGING_DIR_TARGET:当一个组件被构建在一个系统上执行,并且它为另一台机器生成代码时的sysroot路径(例如cross-canadian recipes)。
FILES 变量定义包中每个包中的文件。如果要知道这是如何实现的,可以看看package.bbclass。
根据正在创建的包的类型(RPM、DEB或IPK), do_package_write_*任务会创建实际的包并将它们放在包提要区域中,即${TMPDIR}/deploy
。
注意:不支持直接从deploy/*
目录创建数据元。创建这样的数据元通常需要某种类型的数据元维护机制,将新的包上传到一个官方的包数据元中(例如Ångström 发行版)。此功能是特定的发行版,因此不是开箱即用的。
5 Image Generation
一旦将包拆分并存储在Package Feeds区域中,构建系统将使用BitBake生成根文件系统镜像:
镜像生成过程由几个阶段组成,并依赖于多个任务和变量。do_rootfs 任务为镜像创建根文件系统(文件和目录结构)。此任务使用几个关键变量来帮助创建要实际安装的包列表:
-
IMAGE_INSTALL: 列出要从Package Feeds区域安装的包的基本设置。
-
PACKAGE_EXCLUDE: 指定不应安装到镜像中的包。
-
IMAGE_FEATURES: 指定要包含在镜像中的特性。这些特性中的大多数映射到附加的安装包。
-
PACKAGE_CLASSES: 指定要使用的包后端(例如RPM、DEB或IPK),从而帮助确定在Package Feeds区域中定位包的位置。
-
IMAGE_LINGUAS: 确定为其安装其他语言支持包的语言。
-
PACKAGE_INSTALL: 传递给包管理器以安装到镜像中的包的最终列表。
通过IMAGE_ROOTFS 指向正在构建的文件系统的位置,PACKAGE_INSTALL
变量提供要安装的包的最终列表,就创建了根文件系统。
包安装由包管理器(例如dnf/rpm、opkg或apt/dpkg)控制,无论目标是否启用包管理。在进程结束时,如果没有为目标启用包管理,则包管理器的数据文件将从根文件系统中删除。作为包安装的最后阶段的一部分,将运行作为包一部分的安装后脚本。第一次启动目标系统时,任何未能在生成主机上运行的脚本都将在目标系统上运行。如果使用的是只读根文件系统,那么在包安装阶段,所有安装后脚本都必须在构建主机上成功,因为目标上的根文件系统是只读的。
do_rootfs
任务的最后阶段控制后期处理。后期处理包括创建清单文件和优化。
清单文件(.manifest
)与根文件系统镜像位于同一目录中。此文件逐行列出已安装的软件包。清单文件对于testimage 类非常有用,例如,用于确定是否运行特定的测试。
在镜像中运行的优化进程包括mklibs
、prelink
和ROOTFS_POSTPROCESS_COMMAND 命令变量定义的任何其他后处理命令。mklibs
进程优化库的大小,而prelink
进程优化共享库的动态链接,以减少可执行文件的启动时间。
在构建根文件系统之后,通过do\u image任务开始对映像进行处理。构建系统运行由IMAGE_PREPROCESS_COMMAND变量定义的任何预处理命令。此变量指定在生成系统创建最终图像输出文件之前要调用的函数列表。
构建系统根据需要动态创建do_image_*
任务,基于IMAGE_FSTYPES 变量中指定的镜像类型。该过程将所有内容转换为一个镜像文件或一组镜像文件,并可以压缩根文件系统镜像以减小映像的总体大小。根文件系统使用的格式取决于IMAGE_FSTYPES
变量。压缩取决于格式是否支持压缩。
例如,创建特定镜像type
时动态创建的任务将采用以下形式:
do_image_type
因此,如果IMAGE_FSTYPES
指定的type
是ext4
,那么动态生成的任务将如下所示:
do_image_ext4
镜像创建中涉及的最后一个任务是do_image_complete 任务。此任务通过IMAGE_POSTPROCESS_COMMAND 命令变量定义的一些镜像后处理来完成镜像。该变量指定生成系统创建最终镜像输出文件后要调用的函数列表。
注意:整个镜像生成过程在Pseudo下运行。在Pseudo下运行可以确保根文件系统中的文件拥有正确的所有权。
6 SDK Generation
OpenEmbedded构建系统使用BitBake为标准SDK和可扩展SDK(eSDK)生成Software Development Kit(SDK)安装程序脚本:
与镜像生成一样,SDK脚本过程由几个阶段组成,并且依赖于许多变量。do_populate_sdk 和do_populate_sdk_ext 任务使用这些关键变量来帮助创建要实际安装的包列表。
do_populate_sdk
任务帮助创建标准sdk并处理两个部分:目标部分和主机部分。目标部件是为目标硬件构建的部件,包括库和头文件。主机部分是SDKMACHINE运行的SDK一部分。
do_populate_sdk_ext
任务有助于创建可扩展的sdk,并处理主机和目标部件的方式不同于标准SDK的计数器部分。对于可扩展的SDK,任务封装了构建系统,包括SDK所需的一切(主机和目标)。
不管构建的是哪种类型的SDK,任务都会执行一些清理,然后创建一个跨开发环境设置脚本和任何需要的配置文件。最终输出的是交叉开发工具链安装脚本(.sh
文件),其中包括环境设置脚本。
7 Stamp Files and the Rerunning of Tasks
对于成功完成的每个任务,BitBake会将一个stamp文件写入STAMPS_DIR 目录。stamp文件的文件名的开头由STAMP 变量确定,名称的结尾由任务名称和当前input checksum组成。
注意:这个命名方案假设BB_SIGNATURE_HANDLER 处理程序是“OEBasicHash”,在当前OpenEmbedded中几乎总是这样。若要确定是否需要重新运行任务,BitBake将检查该任务是否存在具有匹配输入校验和的stamp文件。如果存在这样的stamp文件,则假定任务的输出存在并且仍然有效。如果文件不存在,则任务将重新运行。
注意:stamp机制比“Setscene Tasks and Shared State”部分中描述的共享状态(sstate)缓存机制更通用。如果任务的缓存不能被加速,则可以避免重新运行任何文件。
但是,stamp文件只作为一个标记,表明一些工作已经完成,并且这些文件不记录任务输出。实际的任务输出通常在TMPDIR 中的某个地方(例如在某个配方的WORKDIR中)。sstate缓存机制添加的是一种缓存任务输出的方法,然后这些输出可以在构建机器之间共享。
由于STAMPS_DIR
通常是TMPDIR
的子目录,删除TMPDIR
也将删除STAMPS_DIR
,这意味着任务将正确地重新运行以重新填充TMPDIR
。
如果你想让某个任务总是被认为是“过时”的,你可以用nostamp var flag标记它。如果其他任务依赖于此类任务,则该任务也将始终被视为过期,这可能不是您想要的。
8 Setscene Tasks and Shared State
到目前为止,任务的描述假定BitBake需要构建所有内容,并且不存在可用的预构建对象。如果预构建的对象可用,BitBake确实支持跳过任务。这些对象通常以共享状态(sstate)缓存的形式提供。
setscene任务(即do_
taskname
_setscene
)是任务的一个版本,其中BitBake可以跳到最终结果,只需根据需要将一组文件放置到特定位置。在某些情况下,有一个setscene任务变量是有意义的(例如,在do_package_write_*任务中生成包文件)。在其他情况下,由于所涉及的工作量等于或大于基础任务,因此没有意义(例如do_patch 任务或do_unpack 任务)。
在构建系统中,具有setscene变量的常见任务有do_package、do_package_write_*
、do_deploy、do_packagedata和do_populate_sysroot。请注意,这些任务表示输出为最终结果的大多数任务。
构建系统了解这些任务和其他先前任务之间的关系。例如,如果BitBake运行do_populate_sysroot_setscene
执行某些操作,则运行任何do_fetch
、do_unpack
、do_patch
、do_configure
、do_compile
和do_install
任务都没有意义。但是,如果需要运行do_package
,BitBake则需要运行其他任务。
如果所有内容都可以来自sstate缓存,则会变得更加复杂,因为有些对象根本就不需要。例如,如果不存在可编译或修补的内容,则不需要编译器或本机工具(如quilt)。如果do_package_write_*
包可从sstate获得,则BitBake不需要do_package
任务数据。
为了处理所有这些复杂性,BitBake分两个阶段运行。第一个阶段是“setscene”阶段。在此阶段,BitBake首先检查sstate缓存中它计划构建的任何目标。BitBake会快速检查对象是否存在,而不是完整的下载。如果什么都不存在,那么第二阶段,即setscene阶段,就完成了,主构建继续进行。
如果在sstate缓存中找到对象,则生成系统将从用户指定的最终目标向后运行。例如,如果正在构建镜像,则构建系统首先查找该镜像所需的包以及构造镜像所需的工具。如果这些可用,则不需要编译器。因此,编译器甚至不被下载。如果发现某些内容不可用,或者下载或setscene任务失败,则生成系统将尝试从缓存安装依赖项,例如编译器。
sstate缓存中对象的可用性由BB_HASHCHECK_FUNCTION 函数变量指定的函数处理,并返回可用对象的列表。BB_SETSCENE_DEPVALID 变量指定的函数是一个函数,用于确定是否需要遵循给定的依赖关系,以及是否需要为任何给定关系传递函数。函数返回True 或False 值。
包源
当OpenEmbedded构建系统生成镜像或SDK时,它从位于build目录中的package feed区域获取包。“常规工作流”图在右上角显示了此包源区域。
Package feeds是构建过程中的中间步骤。OpenEmbedded构建系统提供类来生成不同的包类型,可以通过PACKAGE_CLASSES变量指定要启用的类。在将包放入package feeds之前,构建过程将通过insane类生成的输出质量保证检查来验证它们。
package feed区域位于Build目录中。构建系统的目录用于临时存储包,它由变量和正在使用的特定包管理器的组合确定。请参阅图中的“Package Feeds”框,并注意该区域右侧的信息。下面定义了包文件的保存位置:
-
DEPLOY_DIR:在Build目录中定义为tmp/deploy。
-
DEPLOY_DIR_*:依赖于使用的包管理器,包类型的子文件夹。给定RPM、IPK或DEB打包和tarball创建,将分别使用DEPLOY_DIR_RPM, DEPLOY_DIR_IPK, DEPLOY_DIR_DEB, 或 DEPLOY_DIR_TAR变量。
-
PACKAGE_ARCH:定义特定体系结构的子文件夹。例如,i586或qemux86架构存在于包中。
BitBake使用do_package_write_*任务生成包并将其放入包保留区域(例如,do_package_write_ipk 是关于UPK包)。此外还有"do_package_write_deb", "do_package_write_ipk", "do_package_write_rpm""do_package_write_tar"和部分。例如使用IPK打包管理器,并且同时支持i586和qemux86的包架构,i586体系结构的包会放在 build/tmp/deploy/ipk/i586中,而qemux86体系结构的包会放在 build/tmp/deploy/ipk/qemux86中。
镜像
构建系统生成的镜像是根文件系统的压缩形式,可以在目标设备上启动。从一般工作流图中可以看到BitBake输出部分由镜像组成:
如图所示,构建过程将镜像写到tmp/deploy/images/
文件夹内的Build Directory中。此文件夹包含目标设备上预期加载的所有文件。DEPLOY_DIR 变量指向machine
/deploy
目录,而DEPLOY_DIR_IMAGE 变量指向包含当前配置镜像的相应目录。
kernel-image
:一个内核二进制文件。KERNEL_IMAGETYPE 变量确定内核镜像文件的命名方案。根据变量的不同,可以用不同的字符串开始命名。deploy/images/
machine
目录可以包含该机器的多个镜像文件。root-filesystem-image
:目标设备的根文件系统(例如*.ext3
或*.bz2
文件)。IMAGE_FSTYPES 变量确定根文件系统镜像类型。deploy/images/
machine
目录可以包含机器的多个根文件系统。kernel-modules
:包含为内核构建的所有模块的tarballs 。内核模块tarballs 用于遗留目的,可以通过将MODULE_TARBALL_DEPLOY 变量设置为“0”来禁止生成。deploy/images/
machine
目录可以包含机器的多个内核模块tarballs 。bootloaders
:如果适用于目标机器,则为支持镜像的引导加载程序。deploy/images/
machine
目录可以包含该机器的多个引导加载程序。symlinks
:deploy/images/
machine
文件夹包含一个符号链接,指向每台机器最近生成的文件。这些链接对于需要获取每个文件的最新版本的外部脚本可能很有用。
用户程序SDK
在通用工作流图中,标记为“Application Development SDK”的输出表示一个SDK。根据是构建Extensible SDK(例如bitbake -c populate_sdk_ext
imagename
)或者Standard SDK(例如bitbake -c populate_sdk
imagename
),SDK生成过程会有所不同。
此输出的特定形式是一组文件,其中包括自解压SDK installer (*.sh
)、host 和target manifest 文件以及用于SDK测试的文件。运行SDK安装程序文件时,它将安装SDK。SDK由一个交叉开发工具链、一组库和头文件以及一个SDK环境安装脚本组成。运行这个安装程序实际上是在安装交叉开发环境。您可以将交叉工具链视为“host”部分,因为它运行在SDK机器上。您可以将库和头视为“target”部分,因为它们是为target 硬件构建的。添加环境安装脚本,以便可以在使用工具之前初始化环境。
SDK的所有输出文件都会写入构建目录中的deploy/sdk
文件夹中,如上图所示。根据SDK的类型,有几个变量可以帮助配置这些文件。
以下列表显示了与Extensible SDK关联的变量:
- DEPLOY_DIR:指向
deploy
目录。 - SDK_EXT_TYPE:控制是否将共享状态工件复制到Extensible SDK中。默认情况下,所有必需的共享状态构件都被复制到SDK中。
- SDK_INCLUDE_PKGDATA:指定对于“world”目标中的所有配方,packagedata是否包含在Extensible SDK中。
- SDK_INCLUDE_TOOLCHAIN:指定在构建Extensible SDK时是否包含工具链。
- SDK_LOCAL_CONF_WHITELIST:一个允许从构建系统配置到Extensible SDK配置的变量列表。
- SDK_LOCAL_CONF_BLACKLIST:一个不允许从构建系统配置进入Extensible SDK配置的变量列表。
- SDK_INHERIT_BLACKLIST:一个在Extensible SDK配置中要从INHERIT 值中全局删除的类列表。
下一个列表显示了与Standard SDK关联的变量:
- DEPLOY_DIR:指向
deploy
目录。 - SDKMACHINE:指定运行交叉开发工具以为目标硬件创建包的机器体系结构。
- SDKIMAGE_FEATURES:列出要包含在SDK的“target”部分中的特性。
- TOOLCHAIN_HOST_TASK:列出构成SDK主机部分(即在
SDKMACHINE
上运行的部分)的包。使用bitbake -c populate_sdk
创建SDK时,将应用一组默认包。此变量允许添加更多包。imagename
- TOOLCHAIN_TARGET_TASK:列出构成SDK目标部分的包(即为目标硬件构建的部分)。
- SDKPATH:定义安装脚本提供的默认SDK安装路径。
- SDK_HOST_MANIFEST:列出构成SDK主机部分的所有已安装包。这个变量在Extensible SDK开发中也起着次要作用。但是,它主要用于Standard SDK。
- SDK_TARGET_MANIFEST:列出构成SDK目标部分的所有已安装包。这个变量在Extensible SDK开发中也起着次要作用。但是,它主要用于Standard SDK。
调试工具和技术
调试构建失败的确切方法取决于问题的性质以及bug发起的系统区域。标准调试方法,例如与上一个已知工作版本的比较,检查更改以及重复识别导致问题的步骤,对Yocto项目是有效的,就像它们用于任何其他系统一样。尽管不可能详细说明每个可能的潜在bug,但这里提供了一些有助于在各种情况下进行调试的一般提示。
从失败的任务中查看日志
可以在${WORKDIR}/temp/log.do_taskname文件中找到任务的日志。例如,用于x86机器(qemux86)的QEMU最小镜像的do_compile任务的日志可能位于tmp/work/qemux86-poky-linux/core-image-minimal/1.0-r0/temp/log.do_compile中。要查看为生成日志而运行的BitBake命令,请在相同目录中的查看相应的do_taskname文件。
log.do_taskname和run.do_taskname实际上是log.do_taskname.pid和log.run_taskname.pid的符号链接,其中pid就是task的PID号。符号链接始终指向最近运行任务相对应的文件。
查看变量值
BitBake的-e选项用于在解析后显示变量值。下面的命令在所有配置文件被解析后显示变量值:
$ bitbake -e
以下命令在解析特定食谱后显示变量值,包括配置中的变量:
$ bitbake -e recipename
用oe-pkgdata-util查看包信息
可以使用oe-pkgdata-util 命令行实用程序来查询 PKGDATA_DIR 和显示各种与包相关的信息。以下是一些可用的 oe-pkgdata-util子命令:
oe-pkgdata-util list-pkgs [pattern]:列出已构建的所有包,可选择将匹配限制为匹配的包 pattern。 oe-pkgdata-util list-pkg-files package ...:列出给定包中包含的文件和目录。 oe-pkgdata-util find-path path ...:列出包含给定路径的包的名称。例如,以下内容告诉我们 /usr/share/man/man1/make.1 包含在make-doc 包中: $ oe-pkgdata-util find-path /usr/share/man/man1/make.1 make-doc: /usr/share/man/man1/make.1 oe-pkgdata-util lookup-recipe package ...:列出生成给定包的食谱的名称。
有关oe-pkgdata-util命令的更多信息,请使用帮助工具:
$ oe-pkgdata-util ‐‐help
$ oe-pkgdata-util subcommand --help
查看食谱和任务之间的依赖关系
有时很难理解为什么BitBake想要在你指定的食谱之前建立其他食谱。依赖关系信息可以帮助你了解食谱的构建原因。
要为食谱生成依赖关系信息,请运行以下命令:
$ bitbake -g recipename
此命令将以下文件写入当前目录:
pn-buildlist:构建recipename时包含的食谱/目标列表
task-depends.dot:显示任务之间依赖关系的图表。
你也可以使用一个不同的方法来查看依赖关系:
$ bitbake -g -u taskexp recipename
使共享状态无效以强制运行任务
OpenEmbedded构建系统使用 校验 和和 共享状态 缓存来避免不必要的重建任务。总的来说,这种方案被称为“共享状态代码”。
与所有方案一样,这个方案有一些缺点。可以对代码进行隐式更改,校验和计算不会考虑这些更改。这些隐式更改会影响任务的输出,但不会触发共享状态代码来重建食谱。
识别隐式更改时,可以轻松地采取措施使缓存无效并强制运行任务。可以采取的步骤就像在源代码中更改函数的注释一样简单。例如,要使程序包共享状态文件无效,更改do_package 其调用的某个函数的注释语句 或注释。即使更改纯粹是装饰性的,它也会导致重新计算校验和,并强制构建系统再次运行任务。
运行特定任务
任何给定的食谱都包含一组任务。在大多数情况下,标准BitBake的行为是:do_fetch, do_unpack, do_patch, do_configure, do_compile, do_install, do_package, do_package_write_*, 和 do_build. 默认任务是do_build和它首先依赖于build的任何任务。有些任务,比如do_devshell,不是默认构建链的一部分。如果希望运行不属于默认构建链的任务,可以使用BitBake中的-c选项。举个例子:
$ bitbake matchbox-desktop -c devshell
如果想强制重新运行一个最新的任务(例如,因为对菜谱的WORKDIR进行了手工修改),那么可以使用-f选项。
下面的例子展示了一种使用-f选项的方法:
$ bitbake matchbox-desktop
对工作目录中的源代码进行一些更改
$ bitbake matchbox-desktop -c compile -f $ bitbake matchbox-desktop
此序列首先构建然后重新编译 matchbox-desktop。最后一个命令在编译后重新运行所有任务(基本上是打包任务)。BitBake认识到该do_compile 任务已重新运行,因此理解其他任务也需要再次运行。
没有依赖的构建
要构建特定食谱,可以使用以下命令格式:
$ bitbake -b somepath/somerecipe.bb
此命令不检查依赖项。因此,只有在知道已满足现有依赖项时才应使用它。
使用devshell
在调试某些命令甚至只是编辑包时,devshell可能是一个有用的工具。当调用devshell时,将为指定的目标运行到do_patch之前和包括do_patch在内的所有任务。然后,打开一个新终端,并将放置在源目录${S}中。在新的终端中,仍然定义了所有与构建相关的OpenEmbedded环境变量,因此可以使用configure和make等命令。这些命令执行起来就像OpenEmbedded构建系统正在执行它们一样。因此,在调试构建或准备与OpenEmbedded构建系统一起使用的软件时,这种方法非常有用。
下面是一个在名为matchbox-desktop的目标上使用devshell的例子:
$ bitbake matchbox-desktop -c devshell
该命令在OpenEmbedded的构建环境中生成一个带有shell提示符的终端。OE_TERMINAL变量控制打开的shell类型。
对于衍生终端,发生以下情况:
PATH变量包括交叉工具链。
pkgconfig变量找到正确的.pc文件。
configure命令查找Yocto项目站点文件以及任何其他必要的文件。
在这个环境中,可以运行configure或compile命令,就好像它们是由OpenEmbedded构建系统本身运行的一样。如前所述,工作目录也会自动更改为源目录。
值得记住的是,在使用devshell时,需要使用完整的编译器名称,比如arm-poky-linux-gnuea -gcc,而不是仅仅使用gcc。这同样适用于其他应用程序,如binutils、libtool等。BitBake设置了环境变量,比如CC来帮助应用程序,比如make来找到正确的工具。
使用目标板上的GDB进行调试
执行以下操作:
确保GDB在目标上。可以通过将“gdb”添加到 IMAGE_INSTALL:
IMAGE_INSTALL_append = gdb
或者,可以将“tools-debug”添加到 IMAGE_FEATURES:
IMAGE_FEATURES_append = tools-debug
确保存在调试符号。可以通过安装-dbg来确保这些符号存在:
IMAGE_INSTALL_append = packagename-dbg
或者,可以执行以下操作来包含所有调试符号:
IMAGE_FEATURES_append = dbg-pkgs
板级支持包(BSP)
板级支持包(BSP)是一组信息,用于定义如何支持特定硬件设备,设备集或硬件平台。BSP包括有关设备上存在的硬件功能和内核配置信息以及所需的任何其他硬件驱动程序的信息。除了通用Linux软件堆栈之外,BSP还列出了基本和可选平台功能所需的任何其他软件组件。
BSP层
BSP由基本目录中的文件结构组成。总的来说,你可以将基本目录、文件结构和内容看作一个BSP层。虽然不是严格的要求,但Yocto项目中的BSP层使用以下公认的命名约定:
meta-bsp_root_name
字符串“meta-”前缀到机器或平台名称,即上面中的bsp_root_name。
为了帮助理解BSP层的概念,请参考Yocto项目支持并提供的每个版本的BSP。你可以通过http://git.yocproject.org在Yocto项目源存储库中看到这些层。
每个存储库都是Yocto项目支持的BSP层(例如meta-raspberrypi和meta-intel)。每个层本身都是一个存储库,单击一个层可以显示包含两个链接的信息,你可以从中选择在本地主机系统上设置该层存储库的克隆。下面是一个克隆树莓派BSP层的例子:
$ git clone git://git.yoctoproject.org/meta-raspberrypi
除了BSP层之外,meta-yocto-bsp层也是附带的poky存储库的一部分。meta-yocto-bsp层维护几个BSP,比如Beaglebone、EdgeRouter以及32位和64位IA机器的通用版本。
层的基本目录(meta-bsp_root_name)是BSP层的根目录。这个目录是你添加到构建目录中的conf/BBLAYERS.conf文件中的BBLAYERS变量的目录,该文件是在运行OpenEmbedded构建环境设置脚本(即oe-init-build-env)之后建立的。举个例子:
BBLAYERS ?= \ /usr/local/src/yocto/meta \ /usr/local/src/yocto/meta-poky \ /usr/local/src/yocto/meta-yocto-bsp \ /usr/local/src/yocto/meta-mylayer \
准备构建主机以使用BSP层
下面的步骤使构建主机准备好使用BSP层。
设置构建环境:确保设置为在shell中使用BitBake。
克隆poky存储库:你需要Yocto项目源目录的本地副本(即本地poky存储库)。
确定你想要的BSP层:Yocto项目支持许多BSP,这些BSP在它们自己的层中维护,或者在设计为包含几个BSP的层中维护。
可选地克隆meta-intel BSP层:如果你的硬件基于当前Intel cpu和设备,那么你可以利用这个BSP层。有关meta-intel BSP层的详细信息,请参阅该层的Readme文件。
$ cd /home/you/poky $ git clone git://git.yoctoproject.org/meta-intel.git $ cd meta-intel $ git checkout -b warrior remotes/origin/warrior 初始化构建环境: $ source oe-init-build-env
示例文件系统布局
下面是BSP层中文件结构的常见形式。虽然这个基本形式代表了标准,但是要认识到特定BSP的实际文件结构可能有所不同。
meta-bsp_root_name/ meta-bsp_root_name/bsp_license_file meta-bsp_root_name/README meta-bsp_root_name/README.sources meta-bsp_root_name/binary/bootable_images meta-bsp_root_name/conf/layer.conf meta-bsp_root_name/conf/machine/*.conf meta-bsp_root_name/recipes-bsp/* meta-bsp_root_name/recipes-core/* meta-bsp_root_name/recipes-graphics/* meta-bsp_root_name/recipes-kernel/linux/linux-yocto_kernel_rev.bbappend
下面描述了的BSP格式的重点部分。
层配置文件:
meta-bsp_root_name/conf/layer.conf
conf/layer.conf文件将文件结构标识为一个层,标识该层的内容,并包含有关构建系统应该如何使用它的信息。一般情况下,标准示例文件是这样的。
# We have a conf and classes directory, add to BBPATH BBPATH .= :${LAYERDIR} # We have a recipes directory, add to BBFILES BBFILES += ${LAYERDIR}/recipes-*/*/*.bb \ ${LAYERDIR}/recipes-*/*/*.bbappend BBFILE_COLLECTIONS += bsp BBFILE_PATTERN_bsp = ^${LAYERDIR}/ BBFILE_PRIORITY_bsp = 6 LAYERDEPENDS_bsp = intel
硬件配置选项:
meta-bsp_root_name/conf/machine/*.conf
机器文件将BSP中包含的所有信息绑定到构建系统可以理解的格式中。每个BSP层至少需要一个机器文件。如果BSP支持多台机器,则可以存在多个机器配置文件。
这些文件定义了要使用的内核包、要包含在不同类型镜像中的硬件驱动程序、需要的任何特殊软件组件、任何引导加载程序信息,以及任何特殊的镜像格式要求。
例如,BeagleBone和BeagleBone Black开发板的机器配置文件位于poky/meta-yocto-bsp/conf/machine层,名为BeagleBone-yocto.conf:
#@TYPE: Machine #@NAME: Beaglebone-yocto machine #@DESCRIPTION: Reference machine configuration for http://beagleboard.org/bone and http://beagleboard.org/black boards PREFERRED_PROVIDER_virtual/xserver ?= xserver-xorg XSERVER ?= xserver-xorg \ xf86-video-modesetting \ MACHINE_EXTRA_RRECOMMENDS = kernel-modules kernel-devicetree EXTRA_IMAGEDEPENDS += u-boot DEFAULTTUNE ?= cortexa8hf-neon include conf/machine/include/tune-cortexa8.inc IMAGE_FSTYPES += tar.bz2 jffs2 wic wic.bmap EXTRA_IMAGECMD_jffs2 = -lnp WKS_FILE ?= beaglebone-yocto.wks IMAGE_INSTALL_append = kernel-devicetree kernel-image-zimage do_image_wic[depends] += mtools-native:do_populate_sysroot dosfstools-native:do_populate_sysroot SERIAL_CONSOLES = 115200;ttyO0 PREFERRED_PROVIDER_virtual/kernel ?= linux-yocto PREFERRED_VERSION_linux-yocto ?= 4.12% KERNEL_IMAGETYPE = zImage KERNEL_DEVICETREE = am335x-bone.dtb am335x-boneblack.dtb am335x-bonegreen.dtb KERNEL_EXTRA_ARGS += LOADADDR=${UBOOT_ENTRYPOINT} SPL_BINARY = MLO UBOOT_SUFFIX = img UBOOT_MACHINE = am335x_boneblack_config UBOOT_ENTRYPOINT = 0x80008000 UBOOT_LOADADDRESS = 0x80008000 MACHINE_FEATURES = usbgadget usbhost vfat alsa IMAGE_BOOT_FILES ?= u-boot.${UBOOT_SUFFIX} MLO
Linux内核配置
meta-bsp_root_name/recipes-kernel/linux/linux*.bbappend meta-bsp_root_name/recipes-kernel/linux/*.bb
Append文件(*.bbappend)修改用于构建镜像的主内核配方。*.bb文件将是开发人员提供的内核配方。BSP层次结构的这个区域可以包含这两种类型的文件,尽管在实践中,你很可能拥有其中一种。
假设你正在使用 linux-yocto_4.4.bb配方来构建内核。换句话说,通过添加PREFERRED_PROVIDER和PREFERRED_VERSION语句,你已经在bsp_root_name.conf文件中选择了内核,如下所示:
PREFERRED_PROVIDER_virtual/kernel ?= linux-yocto PREFERRED_VERSION_linux-yocto ?= 4.4%
使用bitbake-layers脚本创建新的BSP层
使用以下步骤创建BSP层:
-
创建常规图层: 将bitbake-layers脚本与 create-layer子命令一起使用以创建新的常规图层。
-
创建一个层配置文件:每个层都需要一个层配置文件。这个配置文件为该层的配方和优先级建立位置等等。你可以在Yocto项目源存储库中找到layer.conf文件的示例。
-
创建一个机器配置文件:创建一个conf/ Machine /bsp_root_name.conf文件。有关示例bsp_root_name.conf文件,请参考meta-yocto-bsp/conf/machine。
-
创建内核配方:通过使用内核附加文件或新的自定义内核配方文件(例如yocto-linux_4.12.bb)在recipes-kernel/linux中创建内核配方。
配置Yocto默认使用systemd启动
在BSP层的配置文件conf中添加systemd启动功能:
VIRTUAL-RUNTIME_init_manager = systemd
PREFERRED_PROVIDER_udev = systemd
PREFERRED_PROVIDER_udev-utils = systemd
DISTRO_FEATURES_BACKFILL_CONSIDERED = sysvinit
VIRTUAL-RUNTIME_initscripts = IMX_DEFAULT_DISTRO_FEATURES += systemd
DISTRO_FEATURES_append = systemd
DISTRO_FEATURES_remove = sysvinit
在菜谱中添加systemd-networkd.service
在一个菜谱中添加systemd-networkd.service,并且在开机的时候启动它(Yocto最新的systemd启动包都默认安装了systemd-networkd.service,所以可以忽略这一步骤):
SYSTEMD_SERVICE_${PN} = systemd-networkd.service SYSTEMD_AUTO_ENABLE_${PN} = enable
这样Yocto构建BSP完成后就会在rootfs目录生成如下的配置文件:
$ cd poky/build/tmp/work/qemux86-poky-linux/core-image-sato/1.0-r0/rootfs/ $ find . -name *networkd* ./etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service ./etc/systemd/system/sockets.target.wants/systemd-networkd.socket ./etc/systemd/system/multi-user.target.wants/systemd-networkd.service ./usr/share/polkit-1/rules.d/systemd-networkd.rules ./lib/systemd/systemd-networkd-wait-online ./lib/systemd/system/systemd-networkd.socket ./lib/systemd/system/systemd-networkd-wait-online.service ./lib/systemd/system/systemd-networkd.service ./lib/systemd/systemd-networkd
添加eth0.network配置文件
在recipes-core/base-files/base-files/目录下添加eth0.network文件,内容如下:
[Match] Name=eth0 [Network] DHCP=yes [DHCP] RouteMetric=0
然后在recipes-core/base-files/base-files_%.bbappend文件中添加该配置文件到rootfs:
SRC_URI += file://eth0.network do_install() { install -D -m 0644 ${WORKDIR}/eth0.network ${D}${sysconfdir}/systemd/network/ }
这样Yocto构建BSP完成后就会在rootfs目录生成如下的配置文件:
$ cd poky/build/tmp/work/qemux86-poky-linux/core-image-sato/1.0-r0/rootfs/
$ find . -name *eth0* ./etc/systemd/network/eth0.network
Yocto开机后检查systemd-networkd服务是否正常启动
systemd-networkd服务开机启动后会自动从/etc/systemd/network目录读取配置文件来管理网络设备,使用如下命令可以检查该服务的状态。
root# systemctl status systemd-networkd ● systemd-networkd.service - Network Service Loaded: loaded (/lib/systemd/system/systemd-networkd.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2019-03-08 09:02:14 UTC; 2min 42s ago Docs: man:systemd-networkd.service(8) Main PID: 906 (systemd-network) Status: Processing requests... Tasks: 1 (limit: 4915) CGroup: /system.slice/systemd-networkd.service └─906 /lib/systemd/systemd-networkd Mar 08 09:02:22 lorank8 systemd-networkd[906]: br0: Lost carrier Mar 08 09:02:22 lorank8 systemd-networkd[906]: br0: DHCPv6 lease lost Mar 08 09:02:27 lorank8 systemd-networkd[906]: eth0: Gained IPv6LL
可以看到systemd-networkd服务启动后,eth0也自动获取到了ip地址。
Linux Kernel 开发
本文介绍使用Yocto Project Linux内核时要执行的几项常见任务。这些任务包括为主机开发系统准备内核开发,准备层,修补内核,配置内核等。内核开发最好使用devtool而不是通过传统的内核工作流方法来完成,下面会介绍这两个方案的信息。
使用devtool准备开发
初始化BitBake环境
$ cd ~/poky
$ source oe-init-build-env
准备local.conf文件:默认情况下,MACHINE变量设置为“qemux86”,如果你在32位模式下为QEMU仿真器构建,则可以正常运行。但是,如果不是,则需要在构建目录中找到MACHINE的conf/local.conf文件中 正确设置 变量 。
为修补程序创建图层:
$ cd ~/poky/build
$ bitbake-layers create-layer ../../meta-mylayer
把图层通知BitBake构建环境
$ cd ~/poky/build
$ bitbake-layers add-layer ../../meta-mylayer
构建可扩展SDK
$ cd ~/poky/build $ bitbake core-image-minimal -c populate_sdk_ext
安装可扩展SDK
$ cd ~/poky/build/tmp/deploy/sdk $ ./poky-glibc-x86_64-core-image-minimal-i586-toolchain-ext-2.7.1.sh
设置新终端以使用可扩展SDK:必须要打开一个新的终端来使用新的SDK,不能使用之前使用的BitBake shell。
$ source ~/poky_sdk/environment-setup-i586-poky-linux
构建全新镜像:准备在内核上工作的最后一步是使用devtool在刚刚为SDK设置并初始化的新终端中构建初始镜像:
$ devtool build-image
准备一个Layer
创建图层的结构:conf目录保存配置文件,recipes-kernel目录保存追加文件和最终补丁文件。
$ cd $HOME $ mkdir meta-mylayer $ mkdir meta-mylayer/conf $ mkdir meta-mylayer/recipes-kernel $ mkdir meta-mylayer/recipes-kernel/linux $ mkdir meta-mylayer/recipes-kernel/linux/linux-yocto
创建层配置文件:移动到meta-mylayer/conf目录,创建layer.conf文件:
# We have a conf and classes directory, add to BBPATH BBPATH .= :${LAYERDIR} # We have recipes-* directories, add to BBFILES BBFILES += ${LAYERDIR}/recipes-*/*/*.bb \ ${LAYERDIR}/recipes-*/*/*.bbappend BBFILE_COLLECTIONS += mylayer BBFILE_PATTERN_mylayer = ^${LAYERDIR}/ BBFILE_PRIORITY_mylayer = 5
创建内核配方附加文件:移动到meta-mylayer/recipes-kernel/linux目录并创建内核的附加文件。本例使用linux-yocto-4.12内核。因此,append文件的名称为linux-yocto_4.12.bbappend:
FILESEXTRAPATHS_prepend := ${THISDIR}/${PN}: SRC_URI_append += file://patch-file-one SRC_URI_append += file://patch-file-two SRC_URI_append += file://patch-file-three
使用devtool开发内核
下面这个过程中的步骤展示了如何使用可扩展SDK和devtool对内核进行打补丁。
使用以下devtool命令下载内核代码:
$ source ~/poky_sdk/environment-setup-i586-poky-linux $ devtool modify linux-yocto
修改内核源码:
$ cd ~/poky_sdk/workspace/sources/linux-yocto # Edit the init/calibrate.c file
构建更新的内核源代码
$ devtool build linux-yocto
使用新的内核创建镜像
$ cd ~
$ devtool build-image core-image-minimal
测试新的镜像:
$ runqemu qemux86
# dmesg | less
提交修改源码:
$ cd ~/poky_sdk/workspace/sources/linux-yocto $ git status $ git add init/calibrate.c $ git commit -m calibrate: Add printk example
导出补丁并创建附加文件
$ devtool finish linux-yocto ~/meta-mylayer
使用修改后的内核构建镜像:
$ cd ~/poky/build $ bitbake core-image-minimal
使用传统方式开发内核
我们可以在下载好的内核源码目录修改代码:
$ cd poky/build/tmp/work/qemux86-poky-linux/linux-yocto/4.12.12+gitAUTOINC+eda4d18......967-r0/linux-qemux86-standard-build/source # Edit the init/calibrate.c file
接着进入内核构建目录:
$ cd poky/build/tmp/work/qemux86-poky-linux/linux-yocto/4.12.12+gitAUTOINC+eda4d18......967-r0/linux-qemux86-standard-build/
使用可扩展SDK来构建开发内核:
$ source ~/poky_sdk/environment-setup-i586-poky-linux $ make menuconfig $ make
提交修改源码:
$ cd poky/build/tmp/work/qemux86-poky-linux/linux-yocto/4.12.12+gitAUTOINC+eda4d18......967-r0/linux-qemux86-standard-build/source $ git status $ git add init/calibrate.c $ git commit -m calibrate: Add printk example
BitBake中的条件变量-OVERRIDES
BitBake 使用 OVERRIDES 来控制在 BitBake 解析食谱和配置文件后去覆盖哪些变量。下面会描述如何把 OVERRIDES 用作条件元数据,并且讨论与 OVERRIDES 有关的关键字展开,同时提供一些示例来帮助理解。
条件变量元数据
我们可以用OVERRIDES来有条件地选择变量的特定版本,以及有条件地附加或添加变量的值。
注意:OVERRIDES名称(值)只能使用小写字符。另外,名称中不允许使用下划线,因为它们用于将OVERRIDES与其他名称和变量名称分开。
选择一个变量:OVERRIDES变量是一个冒号字符分隔的列表,该列表包含要满足条件对应的所有替代。因此,如果有一个变量以“arm”为条件,而“arm”也在OVERRIDES中,那么系统就会使用“arm”特定版本那个变量,而不是无条件版本的变量。这是一个例子:
OVERRIDES = architecture:os:machine TEST = default TEST_os = osspecific TEST_nooverride = othercondvalue
在此示例中,OVERRIDES 变量列出了三个替代(条件):“architecture”,“os”和“machine”。变量TEST本身的默认值为“default”。我们通过将“os”这个条件附加到变量TEST(即TEST_os)来选择特定os对应的变量版本。
为了更好地理解这一点,请考虑一个实际的示例,该示例假定基于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
追加和前置(添加):BitBake还支持根据是否在OVERRIDES中列出特定项,来对变量值进行追加和前置操作。这是一个例子:
DEPENDS = glibc ncurses OVERRIDES = machine:local DEPENDS_append_machine = libmad
在此示例中,DEPENDS变为“glibc ncurses libmad”。
同样,以基于OpenEmbedded元数据的内核配方文件为例,以下几行将根据架构体系结构有条件地附加内容到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
为单个任务设置变量:BitBake支持仅在单个任务期间设置变量。这是一个例子:
FOO_task-configure = val 1
FOO_task-compile = val 2
在这个示例中,FOO 在执行do_configure任务时值为“val 1”,在执行do_compile任务时值为“val 2” 。
在系统内部,这是通过为了本地数据存储区的do_compile任务专门添加“task-compile”条目到OVERRIDES的值中来实现。
你还可以将此语法与其他组合(例如“ _prepend”)结合使用,如下示例所示:
EXTRA_OEMAKE_prepend_task-compile = ${PARALLEL_MAKE}
关键字扩展
在最后完成BitBake数据存储和解析时,将发生关键字扩展。为了更好地理解这一点,请考虑以下示例:
A${B} = X
B = 2
A2 = Y
在这种情况下,所有解析完成后,BitBake扩展${B}为“2”。在此扩展之前A2被设置为“Y”,扩展之后A2最终变为“X”。
示例
尽管前面的解释显示了变量定义的一些不同形式,但是还是很难确切地解释将变量运算符,条件覆盖和无条件覆盖组合在一起时发生的情况。本节介绍了一些常见情况,并解释通常会使用户感到困惑的变量交互案例。
关于overrides和各种“append”运算符生效的顺序通常会令人困惑。回想一下,使用_append和_prepend进行附加或前置操作不会像+=, “.=”, “=+”, 或者 =.那样使变量赋值立即生效。考虑以下示例:
OVERRIDES = foo
A = Z
A_foo_append = X
对于这种情况,A将无条件地设置为“Z”,并且将“X”无条件地赋值给变量 A_foo。由于尚未应用overrides, 而且因为_append和A仅等于“Z”, 所以A_foo等于“X”。
但是,应用overrides会改变结果。由于在OVERRIDES中列出了“foo” ,因此有条件的变量A将被替换为等于“X”的“foo”版本。最终A_foo代替了A。
下一个示例更改overrides和append的顺序:
OVERRIDES = foo
A = Z
A_append_foo = X
对于这种情况,在处理overrides之前,A设置为“Z”,而 A_append_foo 设置为“X”。但是,一旦应用了对“foo”的overrides, A_append变成“X”。因此,A最后值为“ZX”。请注意,这里没有空格。
下一个示例具有与第一个示例相反的append和overrides顺序:
OVERRIDES = foo
A = Y
A_foo_append = Z
A_foo_append = X
对于这种情况,在解决任何overrides之前, A使用立即扩展将其设置为“Y”。立即扩展结束后,A_foo将其设置为“Z”,然后进一步附加“X”,将变量设置为“ZX”。最后,对“foo”应用overrides会导致有条件的变量A变为“ZX”(即A被替换为A_foo)。
最后一个示例混合了一些不同的运算符:
A = 1
A_append = 2
A_append = 3
A += 4
A .= 5
对于这种情况,随着BitBake多次遍历代码,append操作符的类型会影响分配的顺序。最初,A由于使用立即数运算符的三个语句将其设置为“1 45”。完成这些运算后,BitBake将扩展“_append”操作。这些操作导致A的值变为“1 4523”。
BitBake中的优先选择变量PREFERRED_PROVIDER
当有多个菜谱提供同一个项目时,BitBake会使用PREFERRED_PROVIDER来优先选择其中一个菜谱。你需要在变量后缀指定被提供项目的名称,并将其设置为你想优先使用的配方的PN。这里是一些例子:
PREFERRED_PROVIDER_virtual/kernel ?= linux-yocto
PREFERRED_PROVIDER_virtual/xserver = xserver-xf86
PREFERRED_PROVIDER_virtual/libgl ?= mesa
这个变量起作用的逻辑基于提供者Providers和首选项Preferences,下面分别简单介绍它们的原理。
提供者Providers
假定BitBake被指定执行目标,并且已解析所有配方文件,那么BitBake需要弄清楚如何构建这个目标。BitBake会在PROVIDES列表中查找每个菜谱,一个PROVIDES表单是由已知菜谱名称组成的列表。每个菜谱的PROVIDES列表既可以通过菜谱的PN变量隐式创建,也可以通过菜谱的PROVIDES变量(可选的)显式创建。
当一个菜谱使用PROVIDES变量时,我们就可以用一个不是隐式PN名字的替换名称来找到该菜谱的所有功能。例如,假设一个名为keyboard_1.0.bb的菜谱包含以下内容:
PROVIDES += fullkeyboard
该菜谱的PROVIDES列表将成为“keyboard”(隐式的)和“fullkeyboard”(显式的)。因此,keyboard_1.0.bb的所有功能可以在这两个不同的名称下找到。
首选项Preferences
该PROVIDES列表只是确定目标菜谱的解决方案的一部分。由于目标可能有多个提供者,因此BitBake需要通过指定提供者首选项来对提供者进行优先级排序。
目标具有多个提供者的常见示例是“virtual/kernel”,它在每个内核菜谱的PROVIDES列表中。每一个machine通常使用配置文件中类似的行来选择最佳内核提供者:
PREFERRED_PROVIDER_virtual/kernel = linux-yocto
缺省 PREFERRED_PROVIDER 值是与目标名称相同的提供者。BitBake遍历需要构建的每个目标,并使用此过程解决它们之间的依赖性。
由于给定提供者可能存在多个版本,因此了解如何选择提供者变得很复杂。BitBake默认选择提供者的最高版本。你可以使用 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
注意
菜谱通常会提供两个版本-一个稳定的,有编号的(首选的)版本,以及从源代码存储库自动检出的版本,该版本被认为是“出血边缘”(不稳定版本),所以只能显式选择。
例如,在OpenEmbedded代码库中,有一个适用于BusyBox的标准版本菜谱文件 busybox_1.22.1.bb,但也有一个基于Git的版本 busybox_git.bb,该文件显式包含以下行:
DEFAULT_PREFERENCE =“ -1”
除非开发人员另有选择,否则请确保始终首选带编号的稳定版本。
Yocto-一些很有用的Bitbake构建调试命令
一些很有用的Bitbake构建调试命令:
命令 | 描述 |
bitbake | 构建指定目标 |
bitbake -c | 执行指定的任务 |
bitbake-layers show-layers | 显示图层 |
bitbake-layers show-recipes “” | 显示指定包对应的食谱 |
bitbake -e | grep -w DISTRO_FEATURES | 输出BitBake所分析到的元数据文件、变量、功能等等,然后从中查找DISTRO_FEATURES变量值 |
bitbake -e | grep -w MACHINEOVERRIDES | 输出BitBake所分析到的元数据文件、变量、功能等等,然后从中查找MACHINEOVERRIDES变量值 |
bitbake -e basename | grep ^WORKDIR= | 输出BitBake所分析到basename对应食谱的元数据文件、变量、功能等等,然后从中查找该食谱临时工作目录 |
bitbake -f | 强制执行操作,即使不需要 |
bitbake -v | 显示详细输出 |
bitbake -g | 以graphviz格式输出软件包之间的依赖关系树,最终会在构建目录下生成下面连个DOT语言描述文件:task-depends.dot : 描述任务级之间的依赖, recipe-depends.dot : 包与包之间的依赖 |
bitbake -g -u taskexp | 显示构建目标的包依赖关系,此命令将打开一个UI窗口,因此它必须在主机(虚拟或本机)内部的控制台上执行 |
bitbake -DDD | 显示更多调试信息 |
bitbake -c devshell | 打开一个新的shell,其中已为软件包定义了必要的系统值 |
bitbake -c listtasks | 列出软件包的所有任务 |
bitbake virtual/kernel -c menuconfig | 交互式内核配置 |
bitbake -c fetchall | 获取特定镜像的源码 |
bitbake -s | grep | 检查当前Yocto设置中是否存在某些软件包,并且显示对应食谱版本信息 |
配置Qt5 SDK
在Yocto里面配置Qt5 SDK(交叉编译工具链)的大致步骤如下:
下载meta-qt5并添加到 bblayers.conf.
在local.conf里面添加DISTRO_FEATURES_append = opengl wayland
在your-custom-image.bb里面添加inherit populate_sdk_qt5
为了解决后续使用SDK遇到的一个错误“…/sysroots/x86_64-phytecsdk-linux/usr/bin/qmlcachegen: not found”,需要创建nativesdk-packagegroup-qt5-toolchain-host.bbappend,然后在该文件添加:RDEPENDS_${PN} += nativesdk-qtdeclarative-tools
使用如下命令生成交叉编译工具链:bitbake your-custom-image -c populate_sdk
在rootfs里面配置Qt5
完成“配置Qt5 SDK”的前面两个步骤以后,只需要在your-custom-image.bb里面添加如下代码就可以基本完成rootfs里面Qt5的配置:
IMAGE_INSTALL_append = \ qtbase \ qtbase-plugins \ qtbase-tools \
不过编译出来的qtbase基础功能和库可能并不符合我们的需求,参考qtbase食谱说明里面提到的“Dependencies”和“PACKAGECONFIG options”列表,我们可以在local.conf里面添加qtbase里面的一些可选功能来符合我们的特定需求,比如我遇到的一个项目需要添加如下配置选项:
PACKAGECONFIG_append_pn-qtbase = linuxfb sql-sqlite gif ico fontconfig tslib widgets release qtquickcompiler
考虑到目标板可能需要“qtquickcompiler”相应的完整功能包,需要在your-custom-image.bb里面添加:
IMAGE_INSTALL_append = \ qtdeclarative \
如果Qt应用程序里面使用到了Qt Quick Controls,Qt Quick Controls 2以及Qt Graphical Effects等功能,类似于如下qml配置:
Source/qml/LoadingScreen.qml:2:import QtQuick.Controls 2.1 Source/qml/WindowManager.qml:3:import QtQuick.Controls 1.4
所有我们还需要在your-custom-image.bb里面添加程序包:
IMAGE_INSTALL_append = \ qtquickcontrols-qmlplugins \ qtgraphicaleffects-qmlplugins \ qtquickcontrols2 \
不要忘了在your-custom-image.bb里面添加应用程序所需的字体支持:
IMAGE_INSTALL_append = ttf-dejavu-sans ttf-dejavu-sans-mono ttf-dejavu-sans-condensed \ ttf-dejavu-serif ttf-dejavu-serif-condensed ttf-dejavu-common
最后使用 bitbake your-custom-image 命令来生成相应的镜像包即可。
使用技巧
列出包支持的操作
Yocto中对于不同的Package,有不同的task,即可以执行不同的操作,有一些是所有包共通的,例如clean,build等。我们可以使用下面命令来查看一个包都有哪些可执行的task:
bitbake Package -c listtasks
使用本地文件编译
参考:
这篇文章没有太多自己的原因,大部分来自下列优秀的文章
Systemcall驿站_Neutionwei_CSDN博客
《嵌入式linux系统开发》