利用Yocto构建嵌入式Linux教程01--第一个Yocto项目构建

大家好,从今日开始,计划写一个利用Yocto构建嵌入式Linux的教程,算是对个人工作和学习的一个总结。

本教程选用的Yocto版本为3.0.4,我使用的Linux发行版为Ubuntu 18.04 (LTS),图中所有示例为实际测试截图,有问题请给我留言。

1 构建主机要求

1.1 支持的Linux发行版

Yocto Project版本已针对下表中Linux发行版进行了测试。所以推荐大家采用下面的Linux发行版来构建你的Yocto项目,其他发行版可能会遇到问题。

Yocto项目与Windows Linux子系统(WSL)不兼容,不要使用运行WSL的构建主机。

  • Ubuntu 16.04 (LTS)

  • Ubuntu 18.04 (LTS)

  • Ubuntu 19.04

  • Fedora 28

  • Fedora 29

  • Fedora 30

  • CentOS 7.x

  • Debian GNU/Linux 8.x (Jessie)

  • Debian GNU/Linux 9.x (Stretch)

  • Debian GNU/Linux 10.x (Buster)

  • OpenSUSE Leap 15.1

1.2 电脑硬件要求

  • 虽然Yocto项目对于32位和64位的CPU都是支持的,但还是推荐使用64位CPU的电脑。Yocto项目的构建系统还可以利用多线程来并行处理构建任务,所以,带有多个CPU或者一个多核CPU的构建主机都能极大地减少构建时间。

  • 推荐的内存是4GB或者更多。

  • Yocto项目对硬盘空间要求非常大。对于完整的构建过程,建议预留120G的可用空间。使用虚拟机的朋友看到这个数字是不是要崩溃。

  • 互联网连接肯定是带宽越大越好,这个应该现在都不成问题。最好有翻墙软件,因为软件包的源地址都是国外,没有也没关系,以后我会告诉大家怎么解决软件包下载失败的问题。

1.3 构建主机需要安装的软件包

1.3.1 Ubuntu和Debian
$ sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib \
     build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
     xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
     pylint3 xterm
1.3.2 Fedora
$ sudo dnf install gawk make wget tar bzip2 gzip python3 unzip perl patch \
     diffutils diffstat git cpp gcc gcc-c++ glibc-devel texinfo chrpath \
     ccache perl-Data-Dumper perl-Text-ParseWords perl-Thread-Queue perl-bignum socat \
     python3-pexpect findutils which file cpio python python3-pip xz python3-GitPython \
     python3-jinja2 SDL-devel xterm
1.3.3 openSUSE
$ sudo zypper install python gcc gcc-c++ git chrpath make wget python-xml \
     diffstat makeinfo python-curses patch socat python3 python3-curses tar python3-pip \
     python3-pexpect xz which python3-Jinja2 Mesa-libEGL1
$ sudo pip3 install GitPython libSDL-devel xterm
1.3.4 CentOS
$ sudo yum install -y epel-release
$ sudo yum makecache
$ sudo yum install gawk make wget tar bzip2 gzip python unzip perl patch \
     diffutils diffstat git cpp gcc gcc-c++ glibc-devel texinfo chrpath socat \
     perl-Data-Dumper perl-Text-ParseWords perl-Thread-Queue python34-pip xz \
     which SDL-devel xterm
$ sudo pip3 install GitPython jinja2

1.4 对于git、tar、python的最低版本要求

  • Git 1.8.3.1

  • tar 1.27

  • Python 3.4.0

2 下载Yocto

$ mkdir ~/yocto
$ cd ~/ycoto
$ git clone -b zeus git://git.yoctoproject.org/poky.git
$ cd poky

3 准备构建环境

Yocto提供了脚本oe-init-build-env来创建新的构建环境。该脚本设置构建环境的目录结构,并初始化配置文件。

$ source oe-init-build-env <builddir>

执行该命令,将在当前目录中以由参数<builddir>提供的名字创建新的构建环境。如果省略该参数,脚本会默认使用build作为名字。并且脚本会改变当前目录到构建目录。

新创建的构建环境里面,生成了conf目录,详情如下:

其中的conf/local.conf文件,保存了定制你的嵌入式Linux的各个变量设置。对于我们的第一个Yocto项目,建议修改以下两个变量。

  • DL_DIR:软件包下载的目录,默认的设置是在构建环境目录下的downloads目录,建议修改到构建环境以外的目录,这样,当你新建一个构建环境时,不用重复下载这些软件包。(Yocto项目构建的大部分时间都浪费在下载这些软件包上)

  • SSTATE_DIR:共享的状态缓存文件目录,默认的设置是在构建环境目录下的sstate-cache目录,建议修改到构建环境以外的目录。因为在构建过程中,很多任务会产生大量的中间输出,而这些中间输出对将来其他的构建来说时可以重用的,这样可以大大加速构建过程。

4 开始构建

在构建环境的顶级目录调用BitBake指定构建目录。对于第一个构建,我使用了带有图形用户界面的完整Linux操作系统作为构建目标。

$ bitbake core-image-sato

5 验证构建结果

Yocto默认用的目标机器是qemu,Yocto提供了一个脚本来启动新构建的Linux系统。

$ runqemu qemux86-64

启动效果如下图:

 

 利用Yocto构建嵌入式Linux教程02--基本概念介绍

本教程选用的Yocto版本为3.0.4,我使用的Linux发行版为Ubuntu 18.04 (LTS),图中所有示例为实际测试截图,有问题请给我留言。

在Yocto项目中,有一些专业的术语、比喻、专有名词等。这些基本概念是我们学习和使用Yocto构建自己的嵌入式Linux系统的前提。

1 Yocto术语

Yocto项目:是一个开源协作项目。

Yocto项目使用基于OpenEmbedded(OE)构建主机,该项目使用 BitBake 工具构建完整的Linux镜像。将BitBake和OE组件组合在一起形成参考构建主机,该主机以前称为 Poky

Poky两层含义

含义一:OpenedHand(公司名)最初开发的开源项目。该项目可以从现有的OpenEmbedded构建系统中开发出poky,从而成为对嵌入式Linux商业支持的构建系统。公司被英特尔收购后,该项目便成为Yocto Project构建系统的基础。

含义二:在Yocto Project源存储库中, poky作为一个单独的Git存储库存在,您可以克隆它之后在主机系统上生成本地副本。

Metadata:元数据集,所谓元数据集就是发行版内各基本元素的描述与来源 。百科中对元数据的描述是:中间数据,中继数据,描述数据、数据属性的数据。

Layers:即各种meta-xxx目录,将Metadata按层进行分类,有助于项目的维护。

Bitbake:一个任务执行引擎,用来解析并执行Metadata。

Output:即各种输出image。

总结:假如用烹饪一桌酒席来形容构建发行版,则

Yocto就是餐厅名

Poky就是厨房(以及提供作为参考搭配套餐)

Metadata就是烹饪资源(.bb表示配方,.bbappend就是配方上的贴士,.conf表示厨房里的管事的小组长)

Layers就是菜谱的分类(如川菜谱、粤菜谱)

Bitbake就是厨师

Output就是得到的一桌酒席。

2 Yocto项目的组成

所述BitBake与各种类型的配置文件、任务、执行器一起形成 OpenEmbedded-Core(OE-Core)。本节描述它们的用法、相互作用以及组成关系。

2.1 BitBake

BitBake是OpenEmbedded构建系统的核心工具, 负责解析元数据,从中生成任务列表,然后执行这些任务。

  • 要查看BitBake支持的选项列表,请使用以下命令之一:

$ bitbake -h
$ bitbake --help
  • 仅对某组配方文件执行任务

如您要构建的配方的名称为matchbox-desktop_1.2.3.bb:

$ bitbake matchbox-desktop
  • 完成某项特定任务,清除该任务:

$ bitbake  matchbox-desktop -c clean
  • 执行某个任务的编译:

$ bitbake optee_example -c compile
  • 在构建系统时,先下载不构建:

$ bitbake -c fetchall core-image-stao
  • 使用“-k”忽略错误,继续执行其它任务:

最常用场景,在您构建系统时,使用 -k 选项,可忽略某个出错任务,继续执行其它构建任务。

$ bitbake -k core-image-stao

BitBake用来处理数据文件的解析和执行。而数据本身也有多种类型,下面依次介绍。

2.2 配方文件

.bb后缀的文件是“配方”文件。这些配方文件为BitBake提供以下内容:

  • 有关软件包的描述性信息(作者,主页,许可证等)

  • 配方版本

  • 现有依赖关系(构建和运行时依赖关系)

  • 源代码所在的位置以及如何获取它

  • 源代码是否需要任何补丁,在哪里可以找到它们以及如何应用它们

  • 如何配置和编译源代码

  • 如何将生成的工件组装到一个或多个可安装的程序包中

  • 在目标计算机上的哪个位置安装软件包或创建的软件包

2.3 配置文件

.conf结尾的文件是配置文件。在<build dir>中的配置文件 conf/local.conf,用户的定义变量影响着每个构建过程。

local.conf文件提供了许多定义构建环境的基本变量。对部分常用变量进行描述:

#目标机器的选择

MACHINE ??= "qemux86-64"

#构建过程,同时启用线程的数量

BB_NUMBER_THREADS = "2"

#下载存放目录

DL_DIR ?= "${TOPDIR}/downloads"

#构建缓存目录

SSTATE_DIR ?= "${TOPDIR}/sstate-cache"

#构建过程目录

TMPDIR = "${TOPDIR}/tmp"

#发行版

DISTRO ?= "poky"

#指定OpenEmbedded构建系统在打包数据时使用的程序包管理器
PACKAGE_CLASSES ?= "package_rpm"
EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
USER_CLASSES ?= "buildstats image-mklibs image-prelink"
PATCHRESOLVE = "noop"
BB_DISKMON_DIRS ??= "\
  STOPTASKS,${TMPDIR},1G,100K \
  STOPTASKS,${DL_DIR},1G,100K \
  STOPTASKS,${SSTATE_DIR},1G,100K \
  STOPTASKS,/tmp,100M,100K \
  ABORT,${TMPDIR},100M,1K \
  ABORT,${DL_DIR},100M,1K \
  ABORT,${SSTATE_DIR},100M,1K \
  ABORT,/tmp,10M,1K"
CONF_VERSION = "1"

机器配置文件位于<source dir>中 ,它们定义特定硬件的变量,并且仅在为该目标构建时使用。

bblayers.conf文件告诉BitBake在构建过程中要使用哪些层。默认情况下,此文件中列出的层仅包括构建系统所必需的层。因此,您必须手动添加已创建的所有自定义层。

如何理解Yocto的配置方法?

这要从发行版的定制流程说起。我们的目的很简单,是要得到uboot、kernel、rootfs这三个image;

Yocto的目的也很简单,它要经过一级一级配置,逐步缩小配方,直至得到uboot、kernel、rootfs这三个image。

每一级需要哪些配方,由该级对应的配置文件(.conf/.bb)决定。越上级的配置是越笼统的,越下级的配置越细致。如果下级的配置项相对于上级有补充或者冲突,则以下级的内容为准,可以认为下级会对上级进行“重写”。一个简单的示例图如下:

有关构建的路线和流程:对于整个发行版构建,虽然每一级的配方由(.conf/.bb)决定,但是每一级路线和方向的选择,是由我们最终bitbake的对象决定的,比如bitbake avi-image-core,我们想要获得rootfs.img,那么:

  • 第一步Poky就会从local.conf开始,一路向下,一级一级配置,直到配置到和rootfs有关的那一堆.bb配方文件,最终形成完整完全的配方;

  • 然后获取配方需要的资源,比如各种软件包,比如kernel的源码;

  • 最后把所有的资源编译出我们需要的镜像。

最后说一下bitbake,比如我们要选择编译rootfs.img,那么使用bitbake avi-image-core即可,有时候并不直接采用这种做法。我们也可以在项目目录下写一个Makefile,里面包含各种各样的功能,内部以bitbake指令实现。

2.4 类

类文件(.bbclass)包含有助于在配方文件之间共享的信息。一个示例是 autotools类,其中包含Autotools使用的任何应用程序的通用设置。

BitBake构建系统过程中必须要包含的一个类是 base.bbclass ,您可以在classes目录中找到此文件。base.bbclass类文件是特殊的,因为它总是被所有的配方和类自动包含。此类包含用于标准基本任务的定义,例如获取,解压缩,配置(默认情况下为空),编译(运行存在的任何Makefile),安装(默认情况下为空)和打包(默认情况下为空)。这些任务通常被在项目构建过程中被其它类进行覆盖或者扩展。

2.5 层

层的可以将不同类型的自定义内容相互隔离。尽管您可能会发现在单个项目中将所有内容都保留在一层中很诱人,但是元数据的模块化程度越高,应对将来的更改就越容易。

用一句话概括层:层是组织文件和目录结构的元数据(配置文件、配方)集合。

创建层:

即使你只有一两个配方文件,还是建议你创建自己的层,而不是把配方添加到OE-Core或者Yocto项目层,随着你的配方越来越多,这种好处更能体现出来,且容易迁移到你的其它项目中去。你可以修改配置文件,使你的层添加到项目中。还可以用yocto-layer脚本来创建层。

$ yocto-layer create <layername>

然后根据脚本提示,然后创建配方和配置文件。

├── conf
│   └── layer.conf
└── xxx.bb

2.6 追加文件

追加文件是以.bbappend结尾的扩展名文件,用于扩展或覆盖现有配方文件中的信息。

每个追加文件都应有一个对应的配方文件,且二者具有相同的文件名,仅后缀不同(例如formfactor_0.0.bbformfactor_0.0.bbappend)。

追加文件中的信息扩展或覆盖了文件名相同的配方文件中的信息。

为追加文件命名时,可以使用“ %”通配符来匹配配方名称。例如,假设您有一个名为如下的追加文件:

busybox_1.21.%.bbappend

该追加文件将与配方的任何busybox_1.21.x.bb版本匹配。因此,追加文件将与以下配方名称匹配:

busybox_1.21.1.bb
busybox_1.21.2.bb
busybox_1.21.3.bb

注意

“%”字符的使用受到限制,因为它只能直接在附加文件名的.bbappend部分前面使用。您不能在名称的其他位置使用通配符。

如果busybox配方更新为busybox_1.3.0.bb,则追加名称将不匹配。但是,如果您将追加文件命名为 busybox_1.%.bbappend,则会匹配。

在一般情况下,您可以将追加文件命名为busybox_%.bbappend。完全独立于版本的名称。

3 总结

本节主要介绍了一些Yocto的一些专业术语、BitBake、部分元数据。后续章节会对OpenEmbedded系统构建过程进行描述,然后使用bitbake构建一个Yocto版的“hello world”。

 利用Yocto构建嵌入式Linux教程03--Yocto构建系统的配置文件

 

1 Yocto的构建示意图

OpenEmbedded是Yocto Project特有的构建系统,构建系统的核心是任务执行器BitBake,OpenEmbedded的构建过程流程如下图所示:

这个构建过程的流程图初一看晦涩难懂,但将其分成下面5个部分后,便很容易理解。

区域1配置文件:包括用户配置、元数据(包含配方、补丁)、机器配置、发行版配置;

区域2源文件:下载的三个途径:上游发行版,本地项目和SCM;

区域3:构建系统:包括源代码获取、打补丁、编译。分析输出以生成软件包,创建和测试软件包,生成映像以及SDK;

区域4:扩展软件包:包含输出软件包(RPM,DEB或IPK)的目录,这些目录随后用于构建系统生成的映像或软件开发套件(SDK)的构建。如果启用了运行时程序包管理,还可以使用Web服务器或其他方式复制和共享这些提要,以方便在运行时扩展或更新设备上的现有镜像;

区域5:生成镜像文件和SDK。

整个构建过程的顺序分别是:

源文件获取,源文件解压和打补丁,配置、编译和安装,输出分析和打包,创建镜像,创建SDK。

本节主要讲述第一部分:配置文件。

2 配置文件

2.1 用户配置

使用oe-init-build-env脚本创建构建环境

$ source oe-init-build-env build

构建脚本便会在poky/build/conf目录下生成默认用户配置文件,包含local.confbblayers.conf

local.conf文件提供了许多定义构建环境的基本变量。用户配置列出了构建镜像目标的体系结构、在何处存储下载源代码及构建属性等。用户目录拥有最高级别的配置。下图为local.conf文件,对部分常用变量进行描述:

切换到build目录,查看conf/local.conf

$ cat conf/local.conf
#目标机器的选择
MACHINE ??= "qemux86-64"
#发行版
DISTRO ?= "poky"
#指定OpenEmbedded构建系统在打包数据时使用的程序包管理器
PACKAGE_CLASSES ?= 'package_rpm'

EXTRA_IMAGE_FEATURES ?= "debug-tweaks"

USER_CLASSES ?= "buildstats image-mklibs image-prelink"

PATCHRESOLVE = "noop"
#构建时,启用线程个数。
BB_NUMBER_THREADS = "4"
.........
#源下载被存放的位置(注意此时该目录在BUILD目录下,建议把该目录放到构建环境目录之外)
DL_DIR ?= "${TOPDIR}/downloads/"
#共享缓存目录(注意此时该目录在BUILD目录下,建议把该目录放到构建环境目录之外)
SSTATE_DIR ?= "${TOPDIR}/sstate_cache/"
#构建输出目录
TMP_DIR ?= "${TOPDIR}/tmp/"
CONF_VERSION = "1" 

注意:

DL_DIR:软件包下载的目录,默认的设置是在构建环境目录下的downloads目录,建议修改到构建环境以外的目录,这样,当你新建一个构建环境时,不用重复下载这些软件包。(Yocto项目构建的大部分时间都浪费在下载这些软件包上)

SSTATE_DIR:共享的状态缓存文件目录,默认的设置是在构建环境目录下的sstate-cache目录,建议修改到构建环境以外的目录。因为在构建过程中,很多任务会产生大量的中间输出,而这些中间输出对将来其他的构建来说时可以重用的,这样可以大大加速构建过程。

您可以使用绝对路径对变量指向的路径进行设置:

DL_DIR ?= "home/hann/poky/downloads/"
SSTATE_DIR ?= "home/hann/poky/sstate_cache/"

bblayers.conf文件告诉BitBake在构建过程中要使用哪些层。默认情况下,此文件中仅列出的层包括构建系统所需的层。所以,您必须手动添加已创建的所有自定义图层。下图为bblayers.conf的内容:

# build/conf/bblayers.conf文件发生变化后,变量POKY_BBLAYERS_CONF_VERSION的数字会随着增加。
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
  /home/hann/poky/meta \
  /home/hann/poky/meta-poky \
  /home/hann/poky/meta-yocto-bsp \
  "

2.2 配方文件

下面通过一个简单例子hello.bb介绍配方文件,hello.bb在项目中的位置:

/poky/documentation/ref-manual/examples/hello-single

hello.bb配方文件的内容如下:

#配方需编译文件的描述
DESCRIPTION = "Simple helloworld application"
SECTION = "examples"
#遵守的协议
LICENSE = "MIT"
#LICENSE文件,该文件对应的MD5
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
#从本地获取源文件
SRC_URI = "file://helloworld.c"
#变量S指的是bitbake放置已解压文件目录的完整路径
S = "${WORKDIR}"
#构建:通过执行make命令来实现编译和链接
do_compile() {
    ${CC} helloworld.c -o helloworld
}
#安装:通过执行make install命令将编译好的文件安装到变量${D}${bindir}指定的目录中
do_install() {
    install -d ${D}${bindir}
    install -m 0755 helloworld ${D}${bindir}
}

2.3 机器配置

Yocto项目板级支持包meta-yocto-bsp层的目录结构如下所示,可以看出在/conf/machine中存放机器配置文件*.conf。

$ hann@hann-virtual-machine:~/yocto/poky/meta-yocto-bsp$ tree -L 2

.

├── conf
│   ├── layer.conf
│   └── machine
      ├── beaglebone-yocto.conf
      ├── edgerouter.conf
      ├── genericx86-64.conf
      ├── genericx86.conf
      ├── include
      └── mpc8315e-rdb.conf
├── lib
│   └── oeqa
├── README.hardware
├── recipes-bsp
│   ├── formfactor
│   └── gma500-gfx-check
├── recipes-graphics
│   └── xorg-xserver
├── recipes-kernel
│   └── linux
└── wic
  ├── beaglebone-yocto.wks
  ├── edgerouter.wks
  ├── genericx86.wks
  └── mpc8315e-rdb.wks

12 directories, 6 files

下面是一个默认的典型配置文件,机器名为x86_64,统用的PC机和服务器的计算机配置。支持常用的驱动程序,这些驱动程序可以在“典型”的硬件上使用。

DEFAULTTUNE ?= "core2-64"
require conf/machine/include/tune-core2.inc
require conf/machine/include/genericx86-common.inc

SERIAL_CONSOLES_CHECK = "ttyS0"
#For runqemu
QB_SYSTEM_NAME = "qemu-system-x86_64"

3.4 层配置文件

为特定发行版构建的镜像或SDK提供顶级或常规策略。例如,在Poky中,发行层是 meta-poky层。在发行版层中是一个conf/distro包含发行版配置文件的目录,如poky.conf ,其中包含用于Poky发行版的 许多策略配置。

meta-poky

$ hann@hann-virtual-machine:~/yocto/poky/meta-poky$ tree -L 2

.

├── classes
│   └── poky-sanity.bbclass
├── conf
│   ├── bblayers.conf.sample
│   ├── conf-notes.txt
│   ├── distro
│   ├── layer.conf
│   ├── local.conf.sample
│   ├── local.conf.sample.extended
│   └── site.conf.sample
├── README.poky
└── recipes-core
  ├── busybox
  ├── psplash
  └── tiny-init

7 directories, 8 files

layer.conf

#在conf和classes目录下搜素配置文件和类文件
BBPATH =. "${LAYERDIR}:"

#在recipes-*文件中查找配方文件和追加文件
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"
#下面定义 搜索的方式和等级
BBFILE_COLLECTIONS += "yocto"
BBFILE_PATTERN_yocto = "^${LAYERDIR}/"
BBFILE_PRIORITY_yocto = "5"

LAYERSERIES_COMPAT_yocto = "zeus"

#版本号
LAYERVERSION_yocto = "3"

LAYERDEPENDS_yocto = "core"

REQUIRED_POKY_BBLAYERS_CONF_VERSION = "2"

3 总结

本文对OpenEmbedded的构建过程总结为5个部分,并对配置文件部分进行了分析。OpenEmbedded构建过程的其它部分,将在公众号(嵌入式Linux那些事儿)后续文章中进行分析。

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐