写在前面
博主目前从事BMC工作,由于公司要开发openbmc项目,所以要学习Yocto项目。截至目前,我已经学习了一段时间了,大致可以熟练使用Yocto项目进行嵌入式系统的开发,由于网上这方面的相关知识不太多,所以想尽绵薄之力为这方面的知识做一些补充。文中可能有所疏漏,欢迎留言指正,另外有兴趣的同学也欢迎交流。
1. Yocto项目是什么
Yocto项目本质是一个构建工具,其帮助开发者能够快速地、简单地设计一个基于Linux的系统。该项目由Linux基金会赞助,于2010年启动。同时,在谈到Yocto项目的时候,就不得不提到OpenEmbedded项目,该项目源于夏普的一个开源项目OpenZaurus(服务于SL-5000D),后来结合了其他几个类似的嵌入式项目(Familiar Linux, OpenSIMpad),其目的是为嵌入式系统构建Linux发行版。OpenEmbedded项目维护了一个构建工具BitBake和一个元数据层(详细描述了构建一个Linux发行版所需要的包及构建过程)。Poky Linux是OpenEmbedded项目的一个扩展应用,同时也是Yocto项目的前身。在2011年的时候,OpenEmbedded项目宣布于Yocto项目进行合作,共同维护BitBake以及一个核心数据层。
你可能想问它俩究竟区别在哪,其实它两最终目标都是构建Linux发行版,但侧重点不同,OpenEmbedded聚焦在尖端技术、菜谱和一大套针对不同硬件平台的板支持包,而Yocto项目聚焦在构建系统本身和针对交叉开发的工具化上。如果还不明白,那你直接就可以理解为一个偏硬件,一个偏软件,相辅相成。
另外,我希望你可以通过下面这幅图加深对我之前说的话的理解,图片来自Yocto官网:
在上面图中,poky是Yocto项目为开发者提供的一个开发样例,用户可以直接使用poky来生成一个Linux发行版镜像,或者也可以通过扩展它来自定义镜像。与此同时,poky中包含了一个核心元数据,其详细描述了构建一个Linux发行版所需要的包及构建过程,而它正是OpenEmbedded项目的一部分。
2. Yocto项目有什么用
要说Yocto项目有什么用处,实际上前一节已经说了个大概。如果现在你需要基于Linux系统设计一个定制版的发行版,那么借助于Yocto项目你可以通过修改一些菜谱和配置文件(这些概念不懂没事,之后会提到,你在这只需知道这些文件控制了构建Linux发行版系统的过程)非常简单的构建出一个可用的发行版镜像。又或者你现在有个小型嵌入式工控设备,需要为其提供一个特别小的可运行Linux系统,那么你也可以利用Yocto项目完成你的目的。
总之,借用Yocto官网的描述,Yocto项目就是一个工具,用于构建基于Linux的系统:
3. 如何快速上手Yocto项目
如果你之前曾今接触过Yocto项目,那你肯定会抱怨过关于这方面网络信息资源的匮乏。如果你真的对这个内容感兴趣,你可以通过两种学习路径来理解和熟悉使用Yocto项目。
第一个学习路径是我极为推荐的,那就是使用官网的学习手册。这个手册每次Yocto项目更新后,它也会随之更新,因此内容是比较新的,不容易出现问题。但是问题就是内容是英文的,可能学起来稍微比较费时。
另外一个比较推荐的是通过Rudolf J. Streif写的一本书《Embedded Linux Systems with the Yocto Project》,现在这本书已经被国内的一位大佬胥峰翻译过来了,书名叫《嵌入式Linux系统开发:基于Yocto Project》。有点遗憾的是,该书是2018年出版的,所以文中有些内容已经有点过时了,所以需要读者多注意一下。另外,如果有同学想要该书的电子版,可以留下邮箱。
最后,还要注意的是,不论哪种方法,文中都有大量的测试实验,这些内容还请务必尝试,最好可以举一反三,我可以保证在学习完成之后你会有巨大的收获。
4. 带你通过Yocto项目编译一个自定义镜像文件
在做这个实验之前,你必须先确认一下你的系统是否达到这些要求:
如果确定达到了这些要求,那么我们现在开始构建一个带打印Hello World应用的桌面Linux系统发行版镜像。
首先你需要预安装一些Yocto工程会使用到的软件包(以Ubuntu为例):
$ sudo apt install gawk wget git-core diffstat unzip texinfo gcc-multilib
$ sudo apt install build-essential chrpath socat cpio python3 python3-pip python3-pexpect
$ sudo apt install xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev
$ sudo apt install pylint3 xterm
其次,我们还需要克隆一个Yocto项目到本地:
$ git clone git://git.yoctoproject.org/poky
到此为止,你已经得到了一个完整的Yocto项目demo,直接构建该工程,你可以得到一个Linux系统发行版:
首先你需要初始化构建环境,以此来得到一些重要的环境变量,进入poky目录,运行命令:
source oe-init-build-env build
,此时系统会创建一个构建目录build(该目录存放整个构建输出内容,或者可以将其称作构建环境),并跳转到该目录下。使用vim打开build/conf/local.conf文件(该文件提供一些全局配置),增加两行内容:
BB_NUMBER_THREADS = "4"
PARALLEL_MAKE = "-j 4"
这两行内容分别是构建器使用的线程数,和编译器(Make)使用的线程数,建议设置为小与系统实际能提供的最大线程数,否则默认使用最大线程数。这样做的目的是避免线程数太多导致内存空间不足,以至于构建失败,或者你也可以打开交换内存来增加内存空间避免这一问题,方法见这篇博客。
现在,你可以开始构建一个镜像了,运行命令
bitbake core-image-sato
,这时你便开始构建一个带用户操作界面的Linux系统镜像。当然了,大多数情况下,你一定会遇到一些构建错误,这时,你可以参考下这篇博客,或者留言,之后我会尽可能做出回复。如果你成功构建完成,那么恭喜你,你已经成功了一大半了。现在开始,你可以验证你构建的镜像是否能够使用,运行命令
runqemu tmp/deploy/images/qemux86-64/bzImage-qemux86-64.bin tmp/deploy/images/qemux86-64/core-image-sato-qemux86-64.ext4
。此时,系统将会使用默认参数启动你刚刚构建的位于build/tmp/deploy/images/qemux86-64/目录下的操作系统镜像,例如你可以看到下面的界面:
通过上面的步骤,你已经得到了一个利用poky制作的样例镜像,接下来,我们要为这个镜像嵌入一个我们要用的软件包。
首先,先建立一个自己的层(一般在顶级目录下,以meta开头的目录都叫层,每个层都是独立的,因此为了避免污染其他层,我们建立自己的层),进入poky顶层目录,执行命令mkdir meta-mylayer
。
对于每个层,都需要有自己层的配置文件,用于告诉构建器层中菜谱文件的位置及其他内容,因此我们提供这样一个文件,进入meta-mylayer目录中,新建一个文件夹conf,并在该目录下新建一个layer.conf文件,其内容如下:
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend \
"
BBFILE_COLLECTIONS += "mylayer"
BBFILE_PATTERN_mylayer := "^${LAYERDIR}/"
BBFILE_PRIORITY_mylayer = "5"
除此之外,我们需要提供helloworld的源码包,在meta-mylayer目录中新建文件夹recipes-apps,并进入该目录,新建文件夹hello-1.0,在这个文件夹新建三个文件,内容如下:
之后,我们将这三个文件打包为hello-1.0.tar.gz,并存放到hello-1.0目录下。
随后,我们需要设计软件包菜谱,这个菜谱告诉了构建器从哪里找包,并如何编译安装到镜像中,在recipes-apps目录下新建hello_1.0.bb菜谱文件,其内容如下:
SUMMARY = "Simple Hello World Application"
DESCRIPTION = "A test application to demonstrate how to create a recipe \
by directly compiling C files with BitBake."
# a category this package belong to
SECTION = "examples"
# this package is optional, lacking of it doesn't cause error
PRIORITY = "optional"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "\
file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://hello-1.0.tar.gz"
# S = "${WORKDIR}"
# fix WARN_QA error
TARGET_CC_ARCH += "${LDFLAGS}"
do_compile() {
${CC} -c helloprint.c
${CC} -c hello.c
${CC} -o hello hello.o helloprint.o
}
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}
}
最后,我们将这个包添加到镜像中,在文件meta/recipes-sato/images/core-image-sato.bb或者build/conf/local.conf中添加一行内容IMAGE_INSTALL += " hello "
。重新构建镜像bitbake core-image-sato
,测试时,你可以发现多出了一个新的命令hello。
我希望能通过这个简单的实例让大家对Yocto有个初步的认识,如果想继续深入了解Yocto项目,可以参照第三节内容学习,另外,你也可以关注我,后续我会不定期的更新这方面的相关知识。