前言
Yocto Project简称YP, 是一个致力于帮助开发者构建自己的Linux嵌入式的项目,除了Yocto还有其它的开源项目例如:Debian,著名的Ubuntu就是基于Debian来构建的发行版。
什么是Yocto Project?
Yocto Project (YP)是一个开源协作项目, 可帮助开发人员创建基于Linux内核的自定义系统, 而无需考虑其硬件体系结构。
该项目提供了一套灵活的Build工具, 开发者可以更快的上手去构建自己的Linux操作系统, 经过许多年的发展Yocto已经支持了许多架构, 例如:
Intel
ARM
MIPS
AMD
PPC
同时这些厂商也加入到Yocto项目的维护当中,并为这些架构开发BSP包来让Yocto适配自己的架构。
Yocto与Linux内核的关系
Yocto诞生的目的是为完善Linux内核,一个完整的操作系统是由多个部分组成的,其中内核是最关键的部分,这和CPU是一个道理,一个完整的PC如果光只有CPU是无法运行的,我们还需要有总线、内存、显示器、键盘、鼠标才能构成可供我们使用的PC电脑,而控制这些设备的核心部分就是CPU,操作系统也亦是如此,构成一个完整的操作系统需要有文件系统,桌面应用服务、shell、基本设施程序(ls、cd、rm), 最早开发人员如果想用Linux内核来构建自己的系统是非常麻烦的,你需要去进行适配然后移植文件系统、开发各种工具才能让Linux在你的架构上运行起来并提供给别人使用。
Yocto诞生的目的就是为了加快构建Linux操作系统,开发者们可以基于Yocto来快速构建自己的Linux操作系统,Yocto里集成了大量开发包、软件包、文件系统,集成了一个完整操作系统的所有部分,并且提供了Build工具来统一化管理与构建项目。
所以Yocto与Linux之间的关系就像是CPU与PC之间的关系一样,为Linux内核提供完整操作系统的功能。
为何Yocto还需要进行架构上的适配?
虽然Linux内核已经对许多架构进行了适配,可以很轻易的移植到不同的架构上,但是一系列软件包并没有,所以Yocto需要对这些组成部分也进行移植适配才能更好的运行在这些架构上。
Open Embedded
Open Embedded是以工业界标准的开放式系统为基础而开发出来的嵌入式系统,针对特定的硬件体系结构, 利用专门的指令系统开发出来的嵌入系统, Yocto是实现Open Embedded的一种方式,除此之外还有Debian,著名的apt-get工具就是出自Debian项目。
开始!构建你的Yocto项目
准备工作
Yocto是一个庞大的项目,如果你想要构建Yocto首先你的电脑需要具备以下条件:
一个基于Linux内核构建的发行版操作系统,例如Ubuntu20.04
可利用的磁盘分区大小至少达到70GB以上(可能会更大), 建议准备100GB以上的磁盘
网络通顺,并且能够科学上网
获取Yocto项目
Yocto官方提供了一个示例Open Embedded Os: Poky, 这个项目不光是一个示例项目还包含了完整的Yocto的构建服务,开发者们可以基于Poky来构建自己的发行版
官方Git链接:git://git.yoctoproject.org/poky
Github链接:https://github.com/YoeDistro/poky.git
可以选择一个适合你下载的链接,Github与官方的Git是同步维护的
git clone https://github.com/YoeDistro/poky.git
cd poky
下载的是最新版本的yocto项目,这里建议大家使用稳定长期维护的版本,你可以在这里找到你想要的分支名:https://wiki.yoctoproject.org/wiki/Releases
不同的分支里它们的构建语法可能有所不同,但大同小异,这里使用的分支是Hardknott:
git fetch --tags
git checkout -t origin/hardknott -b t_hardknott
下面是对Yocto的项目文件结构的介绍
文件名 | 作用 |
bitbake | 工具目录bitbake,是一metedate解释器,读取metedate并执行定义的task。执行bitbake命令时,其实执行的就是bitbake/bin/下面的文件 |
build | 用户配置文件和工程构建输出目录,build目录在建立环境变量时进行创建并进行配置文件初始化。构建的所有文件都在该目录下组织存放。 |
documentation | 说明文件 |
meta | Open EmbeddedCore的Metedata,包括recipes,comon classes等 |
meta-poky | poky发行版本的配置数据 |
meta-yocto-bsp | yocto工程包含的一些参考的BSP配置,通常厂商自己会增加自己的bsp目录 |
meta-selftest | Open Embedded自测的recipes和append 文件 |
meta-skeleton | BSP和kernel开发用的一些临时recipes |
scripts | 脚本文件,用来提供一些特性的功能。该路径会被添加到环境变量中 |
oe-init-build-env | 构建Open Embedded的环境 |
在项目文件体系里没有包含一些核心code,例如Linux内核,Yocto是一个通过分布配方组成的项目,拉取下来的原始项目只包含了Build配置文件,这些文件里包含了其它发行版以及架构的配置信息,在build的时会读取这些配置信息来下载对应的源代码,所以为什么很多人会说Yocto编译非常庞大与麻烦的原因就在这里,Yocto只会在构建阶段才会去根据你指定的配置来去下载对应的Code在进行配置与编译
在开始之前需要安装一些构建时所需要的Tools:
sudo apt install gcc g++ cpp chrpath cpio diffstat gawk make wget python3 python3-pip
开始构建
首先初始化环境变量:
source oe-init-build-env
如果初始化成功会提示如下输出:
You can now run 'bitbake <target>'
Common targets are:
core-image-minimal
core-image-full-cmdline
core-image-sato
core-image-weston
meta-toolchain
meta-ide-support
You 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
当初始化完成之后Yocto提供了三个工具:
工具名 | 作用 |
devtool | 可以使用该工具有选择地将构建的内容集成到OpenEmbedded构建系统构建的映像中,同时该工具可以快速修改源码 |
bitbake | 是一个类似于GNU的make的构建工具,主要是为了管理嵌入式Linxu交叉编译的各个版本和包。 |
oe-pkgdata-util | 处理常见的目标包任务 |
这里解释一下上面生成几个镜像的差异:
镜像名 | 作用 |
core-image-minimal | 最小镜像,不能再这个基础上精简,这个镜像仅仅能启动而很多功能还无法使用,因为缺乏应用层软件 |
core-image-full-cmdline | 仅控制台映像,安装了更多功能齐全的Linux系统功能 |
core-image-sato | 在core-image-full-cmdline基础上添加一个叫sato的GUI演示 |
core-image-weston | 这是基于Wayland协议和Weston参考合成器的镜像 |
meta-toolchain | 生成通用SDK工具链 |
meta-ide-support | 此命令将生成可在Yocto构建环境之外使用的跨工具链 |
如果你想知道每个镜像安装了哪些包可以使用如下命令来查看
bitbake -g core-image-minimal
执行之后会在本地生成一个pn-buildlist的文件,里面存放了要安装的包名称, 如果想查看包的版本可以使用如下命令-s:
bitbake -s
需要值得注意的是每个分支都有一些不同的开发者组织维护的,它们生成时在别的分支上可能有所不同
这里构建一个仅有CMD命令的镜像:
bitbake core-image-full-cmdline
在构建时你可能会遇到这样的问题:
Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).
Python can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.
这个原因是因为本地语言设置的问题, bitbake工具需要本地语言环境为en_US.UTF-8, 解决方案如下:
首先安装语言包
sudo apt-get install locales
然后设置语言:
sudo dpkg-reconfigure locales
使用上述命令之后会弹出语言选择画面,选择en_US.UTF-8的数字编号就可以了
(Enter the items you want to select, separated by spaces.)
Locales to be generated: 158
Many packages in Debian use locales to display text in the correct language for the user. You can choose a default locale for the system from the
generated locales.
This will select the default language for the entire system. If this system is a multi-user system where not all users are able to speak the default
language, they will experience difficulties.
1. None 2. C.UTF-8 3. en_US.UTF-8
Default locale for the system environment: 2
然后生效设置:
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8
第一次构建时会下载大量包,此时需要保证你的网络通顺且能科学上网,否则可能会出现下载失败的情况,整个过程大概会需要3个多小时
NOTE: Fetching uninative binary shim http://downloads.yoctoproject.org/releases/uninative/3.5/x86_64-nativesdk-libc-3.5.tar.xz;sha256sum=e8047a5748e6f266165da141eb6d08b23674f30e477b0e5505b6403d50fbc4b2 (will check PREMIRRORS first)
Initialising tasks: 100% |############################################################################################################| Time: 0:00:01Sstate summary: Wanted 1390 Local 0 Network 0 Missed 1390 Current 0 (0% match, 0% complete)
NOTE: Executing Tasks
Currently 16 running tasks (383 of 3770) 10% |########## |0: binutils-cross-x86_64-2.36.1-r0 do_fetch (pid 6256) 3% |## | 1004K/s1: mpfr-native-4.1.0-r0 do_fetch (pid 6313) 0% | |2: glibc-2.33-r0 do_fetch (pid 6561) 21% |#################### | 873K/s3: rpm-native-1_4.16.1.3-r0 do_fetch (pid 20145) 22% |################## | 983K/s4: curl-native-7.75.0-r0 do_fetch (pid 29249) 0% | |5: cmake-native-3.19.5-r0 do_fetch (pid 30171) 3% |## | 25.5M/s6: linux-yocto-5.10.107+gitAUTOINC+24ab54209a_763c0dbc04-r0 do_fetch (pid 37703) 0% | | 767K/s7: patch-native-2.7.6-r0 do_configure - 14s (pid 56047)
8: bison-native-3.7.5-r0 do_configure - 8s (pid 75451)
9: linux-libc-headers-5.10-r0 do_unpack - 4s (pid 92723)
10: gcc-source-10.3.0-10.3.0-r0 do_unpack - 4s (pid 94125)
11: pkgconfig-native-0.29.2+gitAUTOINC+edf8e6f0ea-r0 do_compile - 1s (pid 107522)
12: rsync-native-3.2.3-r0 do_configure - 1s (pid 108818)
13: autoconf-archive-native-2019.01.06-r0 do_populate_sysroot - 0s (pid 110639)
14: gmp-native-6.2.1-r0 do_install - 0s (pid 110701)
15: unifdef-na
如果过程中出现了警告可以忽略,这个是Yocto里的某个源不可用了,但是没关系Yocto会去别的源上下载
WARNING: mpfr-native-4.1.0-r0 do_fetch: Failed to fetch URL https://www.mpfr.org/mpfr-4.1.0/mpfr-4.1.0.tar.xz, attempting MIRRORS if available
WARNING: curl-native-7.75.0-r0 do_fetch: Failed to fetch URL https://curl.haxx.se/download/curl-7.75.0.tar.bz2, attempting MIRRORS if available
WARNING: libmnl-1.0.4-r0 do_fetch: Failed to fetch URL https://netfilter.org/projects/libmnl/files/libmnl-1.0.4.tar.bz2;name=tar, attempting MIRRORS if available
编译完成之后生成build目录,在build目录下的downloads目录就是下载的包,如果想下次不这么麻烦可以把这个包打包一下,下次直接解压到build目录下就可以直接使用了
下面对build目录文件结构的介绍:
文件 | 作用 |
conf/local.conf | 用户的配置文件,包含所有定制化的配置。该文件配置的所有变量都会覆盖其他文件相应变量的软赋值 (?= 形式)(注意=形式的硬编码无法覆盖) |
conf/bblayers.conf | 该文件用来定义BBLAYERS,BBLAYERS是决定哪些路径下的模块需要构建,哪些不需要构建,并将这些信息提供给BitBake |
conf/sanity_info | 可用性信息 |
downloads | 构建过程中,下载的所有源码。可以将该目录放到一个公共目录下,提供每次的编译效率 |
sstate-cache | 构建构成中的构建状态缓存。可以将该目录放到一个公共目录下,提供每次的编译效率 |
tmp | 构建时所有的输出都存放在该目录下 |
tmp/buildstats | 构建统计信息,每次构建,都会在该目录下生成一个日期目录 |
tmp/cache | BitBake解析metedata(包括recipes和config文件)后,将解析的结果缓存在该目录,以提高后续效率 |
tmp/deploy | 部署文件目录,最终需要的文件(boot rootfs image等)都在该目录中 |
tmp/deploy/deb | 存放系统产生的所有.deb类型的安装包 |
tmp/deploy/rpm | 存放系统产生的所有rpm类型的安装包 |
tmp/deploy/ipk | 存放系统产生的所有ipk类型的安装包 |
tmp/deploy/licenses | 系统使用的各种软件的许可信息 |
tmp/deploy/images | 存放boot rootfs image等文件 |
/tmp/deploy/sdk | 工具链安装脚本 |
tmp/sstate-control | 状态跟踪文件 |
tmp/sysroots-components | 制作sysroots前需要额外添加的一些组件 |
tmp/sysroots | 构建出的根文件系统内容 |
tmp/stamps | 记录BitBake跟踪task执行时间的一些信息 |
tmp/log | 日志信息 |
tmp/work | 包含和CPU架构相关的工作目录 |
tmp/work-shared | 工作信息缓存,为了提高效率 |
当完成构建之后可以使用qemu命令来测试镜像,bitbake默认生成的是qemu Intel x86-64架构的image:
runqemu qemux86-64
执行之后会弹出Qemu运行窗口:
加载画面
Home画面
镜像存放路径在build/tmp/deploy/images下,新版的Yocto项目会在images目录下生成一个架构平台名字的目录,里面就存放了生成的镜像文件
构建指定架构的Yocto
我们下载原生的Yocto项目提供的Poky演示嵌入式操作系统里只提供了Qemu架构的环境,你可以在meta/conf/machine里面找到支持的架构:
qemuarm.conf qemumips64.conf qemuppc64.conf qemuriscv32.conf qemux86-64.conf
qemuarm64.conf qemuarmv5.conf qemumips.conf qemuppc.conf qemuriscv64.conf qemux86.conf
可以看到Poky仅提供了Qemu架构的配置文件,我们可以通过Poky这个项目来进项修改,参考它的方式来定制化自己的发行版,例如OpenstLinux就是基于Poky改过来的。
Yocto有两个关键变量MACHINE、DISTRO,这两个变量的意义如下:
MACHINE:架构,指定要生成的架构环境
DISTRO:发行版策略
目前DISTRO只有poky,MACHINE只有qemu的架构环境,所以从这些配置就可以看出poky只是Yocto提供的一个示例项目,期望开发者们基于这个项目来定制化自己的发行版,如果我们想要定制化自己的项目可以在meta-poky目录里找到示例写法,例如配置交叉编译器,定制策略与设备树文件这些信息
你可以在build/conf/local.conf文件里修改这两个内容,也可以指定环境变量,Yocto在构建时会去读取这两个环境变量,如果内容为空则读取local.conf里的内容作为默认值
下面构建一个arm64架构的Yocto
在重新构建之前需要清除上一次编译的缓存
bitbake -c cleansstate core-image-full-cmdline
重新初始化环境
export DISTRON=poky
export MACHINE=qemuarm64
source oe-init-build-env
构建
bitbake core-image-full-cmdline
在构建时可以看到输出信息, 可以看到构建时的MACHINE变更为了qemuarm64
Build Configuration:
BB_VERSION = "1.50.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "aarch64-poky-linux"
MACHINE = "qemuarm64"
DISTRO = "poky"
DISTRO_VERSION = "3.3.6"
TUNE_FEATURES = "aarch64 armv8a crc cortexa57"
TARGET_FPU = ""
meta
meta-poky
meta-yocto-bsp = "my-hardknott:1cefabe0f0a2dd2ca8b6eb83e8e0824b72da941a"
如果你想要加快编译,加快make的执行速度,可以在conf/local.conf文件里添加如下内容:
PARALLEL_MAKE ?= "-j4"
和make使用多线程编译一样的用法,同时如果想要加快bitbake执行任务时的线程数可以增加如下内容:
BB_NUMBER_THREADS ?= "8"
这两个变量分别对应make的编译线程和bitbake执行工作任务时线程数,例如bitbake在执行下载任务时可以使用多线程来加快下载速度
当编译完成之后可以使用qemu来进项模拟运行:
runqemu qemuarm64