Yocto项目中,采用的是BitBake工具来构建嵌入式Linux系统的。通过repo获取了Yocto项目的同时,也一起获取BitBake工具,直接使用即可。使用BitBake的最主要目的是生成一些安装包、内核、SDK以及一个完整的嵌入式Linux发行版(包括:U-Boot、Kernel、Rootfs、DeviceTree)。这些安装包或目标文件就构成了一个完成的嵌入式Linux发行版,可以通过Freescale提供的工具,将其生成一个SD卡镜像文件,用于烧写至开发板中。
运行imx-setup-release.sh脚本后,会自动生成一个build文件夹,进入该文件夹,运行bitbake命令:
bitbake imx-image-multimedia
BitBake命令格式为:bitbake target,其中Freescale提供了几个target镜像文件,可供选择,需要注意的是,镜像文件支持的功能越多,(根)文件系统就越大:
BitBake工具最主要的目的是编译生成相应的软件安装包、内核镜像文件、SDK或者用来构建嵌入式Linux发行版(Linux内核、BootLoader、根文件系统)。当然,也可以用于编译单个的recipe文件,实现获取、清除数据等。通过命令: bitbake target(例如:bitbake fsl-image-qt5)即可启动BitBake构建系统过程。
BitBake构建的第一步是解析Metedata基本配置文件,这些基本配置文件确定了所构建嵌入式Linux系统发行版的一些功能及特征。在了解解析Metadata基本配置之前,需要先了解几个概念。
Yocto由一些Metadata组成,具体来说,通过repo获取Yocto项目后,在source目录下有一些文件夹,这些文件夹就是一个个的metadata。如下图所示,在这些文件夹中包含了许多的文件,用于构建嵌入式Linux系统。
在Metadata中,有许多文件存放于source/meta-xxx文件夹下,用于构建嵌入式Linux系统发行版。如下图所示:
其中:
classes:该文件夹下的.bbclass文件,包含了一些在不同的metadata之间共享的信息,以及编译信息的抽象,例如:如何编译Linux内核。
conf:该conf文件夹下的layer.conf文件定义了该metadata中使用的哪些.bb、.bbappend文件等参与构建嵌入式Linux系统。
recipes-xxx:该文件夹中有许多的.bb或.bbappend文件,这些文件定义了构建嵌入式Linux系统需要的软件包或源码等,主要包括:
软件包的基本信息:作者、主页、License等
版本信息
依赖文件
从哪下载以及如何下载软件包
软件包补丁信息:是否需要补丁、补丁下载地址及方式等
如何配置、如何编译软件包、安装位置等
总的来说,解析Metadata的过程就是,BitBake根据build/conf/bblayers.conf中定义的所使能的layers(meta-xxx),找到对应meta-xxx文件夹下的layer.conf文件,根据layer.conf文件中所使用的.bb或.bbappend文件中定义的软件包或源码的下载、配置、编译方式、安装目录等,将需要的软件包或源码编译进根文件系统(使用的软件包等最终是安装在根文件系统中。对于U-Boot、Linux Kernel的配置编译等,后面会有专门的章节描述)。
备注:可以通过BitBake提供的命令查看当前使用的配置文件和class文件:
bitbake -e > mybb.log
查看mybb.log文件即可。
BitBake解析了Metadata基本配置之后,BitBake根据build/conf/bblayers.conf中定义的所使能的layers(meta-xxx),找到对应meta-xxx文件夹下的conf文件夹下的layer.conf文件,在该layer.conf文件中,通过BBFILES和BBPATH指定了当前layer下所使用的Recipes,说白了,就是通过BBPATH告诉BitBake在哪些路径下,找到哪些.bb和.bbappend文件(即BBFILES),通过这些BBFILES告诉BitBake,会使用哪些软件包或源码构建嵌入式Linux发行版。 通常来说,BBFILES以PN(package name)加PV(package version)命名,如:something_1.2.3.bb,PN=something,PV= 1.2.3。关于BBFILES将是构建嵌入式Linux系统的关键知识点,在后面移植过程中,会详细的讲解。
当recipe解析完成后,会生成一个“任务列表”,接下来就是BitBake根据“任务列表”(BBFILES中定义的内容数据等)进行系统的构建。实际上,在构建系统过程中,就是以一个个task的形式进行的。
在解析了Recipes之后,将会生成一个“任务列表”,BitBake根据该“任务列表”开始编译目标文件。BitBake会查找每一个Recipes对应的PROVIDES列表。PROVIDES列表是由模块的PN(package name)隐式的确定或者由Recipe中的PROBIDES变量显式的决定。当Recipes中通过PROVIDES变量显式的定义了之后,那么该Recipes中定义的功能将由PROVIDES变量定义的recipe文件确定;否则,如果Recipes中没有通过PROVIDES变量显式的定义,那么该Recipes中定义的功能将由模块的PN值定义的recipe文件确定。例如,假设一个名为keyboard_1.0.bb的recipe,在keyboard_1.0.bb中包含了PROVIDES += "fullkeyboard",那么对于recipes的PROVIDES列表,keyboard_1.0.bb是隐式的定义,而fullkeyboard.bb是显示的定义,该recipe中的功能将由fullkeyboard.bb确定。
对于确定所使用的目标recipe,PROVIDES列表仅仅是其中的一部分。由于目标recipe有可能会有多个PROVIDES,BitBake通过识别PROVIDES的优先级确定最终使用的provides。
例如,对于virtual/kernel来说,通常会有多个providers,通过类似下面的配置选择最优的providers:
PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
此外,还存在一种情况,同一个providers有多个版本的recipe文件。这时,一般情况下BitBake将会选择使用最新版本的的recipe文件,除非有其他特殊的设置。例如:
存在一个a_1.1.bb文件,对于该文件其PN为“a”,PV为“1.1”;同时,存在另外一个a_1.2.bb文件,那么BitBake将默认采用a_1.2.bb构建系统。然后,如果在.conf文件中定义了PREFERRED_PROVIDER_a = "1.1",那么BitBake将会采用a_1.1.bb文件构建系统。
BitBake构建系统时,都会分为多个任务执行,例如:fetch, unpack, patch, configure以及compile 。对于构建系统所使用的主机是多核的情况,BitBake内部会对各任务的依赖关系进行处理,不需要用户干预。
BitBake通过providers和dependencies计算出需要运行的任务及各任务之间的顺序。BitBake构建任务的运行受限于BB_NUMBER_THREADS变量的值,而该值又由构建系统所使用的主机的内核数量确定。 只要有满足依赖关系以及准备好的任务需要运行,并且当前运行任务的数量没有超过线程的阈值。BitBake就会继续派生线程来运行该任务。
BitBake通过运行${T}/run.do_taskname.pid脚本来执行任务。一般来说,构建系统的任务管理是由BitBake自己管理的,不需要用户进行干预。
校验和是任务输入的唯一签名。 任务的签名可用于确定任务是否需要运行。 因为是任务输入中的更改触发了运行任务,所以BitBake需要检测给定任务的所有输入。通常来说,这部分工作也是由BitBake自己完成的,不需要用户进行干预。