利用bitbake工具编译uboot,linux内核源码,根文件系统,将这三者组成一个完成的嵌入式发行版(distro),主要目的在硬件平台上运行linux系统,编译多用ubuntu,sudo apt-get install openssh-server(安装ssh)。Repo管理所有git仓库,将多个git组合在一起,形成一个完整的大版本。https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#detailed-supported-distros
。
mkdir /home//Linux/Yocto/fsl-release-yocto进入,curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ./repo。由于网络原因,通过curl下载repo工具往往比较慢。可以通过清华的源进行下载:curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo (多出一个repo文件不可执行),chmod a+x repo
。
Yocto项目采用repo管理各个git库的方式进行管理。因此,除了使用repo工具外,还需要使用到Git。使用Git前,需要设置Git的用户名和密码,在fsl-release-yocto文件夹里执行git config设置用户名和邮箱。切换至Yocto工作路径/home/Linux/Yocto/fsl-release-yocto,然后使用如下repo命令,获取Yocto项目(克隆NXP官方fsl-arm-yocto-bsp.git项目的imx-linux-zeus分支): ./repo init -u https://source.codeaurora.org/external/imx/imx-manifest -b imx-linux-zeus -m imx-5.4.47-2.2.0.xml
。
注意:由于国内的原因,直接运行上面repo init命令时,会出现fatal: Cannot get https://gerrit.googlesource.com/git-repo/clone.bundle的错误,这是因为repo运行时,会去google服务器请求最新版本,解决方式是在本地环境变量中指定repo服务器地址,可以使用清华的镜像源进行更新,即将如下内容复制到你的~/.bashrc里:export REPO_URL=“https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/” 。并重启Ubuntu即可。
输入上述命令./repo init -u https://source.codeaurora.org/external/imx/imx-manifest -b imx-linux-zeus -m imx-5.4.47-2.2.0.xml
后,会提示/usr/bin/env: ‘python’: No such file or directory,这是因为Ubuntu20.04中已经移除了python2的原因,直接使用的是Python3。因此,使用命令: sudo ln -s /usr/bin/python3 /usr/bin/python,将python连接为Python3即可。再次输入./repo....xml
,克隆完成后,输入几次y确认一些信息即可。通过ls -a命令,可以看到在fsl-release-yocto路径下有.repo隐藏目录,进入.repo:
可以看到,在.repo目录下的manifests中的文件,定义了imx-linux-zeus分支下使用到的哪些Git库。最后在fsl-release-yocto路径下,运行./repo sync
命令,获取Yocto项目(repo将会从网上下载很多东西)。需要注意的是,在./repo sync获取Yocto源码的过程中,由于网速等原因,会出现下载失败或下载“卡死”的情况,此时,可按Ctrl+c终止,再次输入./repo sync命令,即可继续从断点处下载。
获取Yocto项目源码成功后,会在Yocto工作路径/home/jason/Linux/Yocto/fsl-release-yocto路径下得到imx-setup-release.sh、setup-environment、sources等文件。其中:
imx-setup-release.sh:该脚本用于初始化Yocto构建嵌入式Linux系统工作环境。
setup-environment:该脚本根据运行imx-setup-release.sh脚本时输入的参数,设置Yocto工作环境。
sources文件夹:在该文件夹下存放了很多文件、源码以及编译工具,用于构建嵌入式Linux系统。
meta-bsp - meta-fsl-arm, poky, meta-openembedded层的一些更新软件。
meta-sdk - meta-freescale-distros以及发行版的一些更新软件。
meta-ml:机器学习相关的软件。
base:该文件夹下主要存放了bblayers.conf和setup-environment,构建Yocto工作环境时用到。
meta-clang:C语言家族前端和LLVM编译器后端。
meta-freescalse-3rdparty:第三方板卡支持软件。
meta-browser:提供了几种浏览器,如gnome、mozilla。
meta-freescale:提供了一些基于Freescale ARM官方参考板的基础支持软件。
meta-imx:
meta-freescalse-distro:官方提供的一些嵌入式Linux发行版。
meta-nxp-demo-experience:NXP官方提供的一些demo。
meta-python2: python2相关的软件。
meta-rust:rust相关的软件。
meta-openembedded:OE内核的一些集合,定义了构建Yocto使用到的一些工具软件。
meta-qt5:QT5相关的软件。
meta-timesys:提供Vigiles工具来查看和通知BSP漏洞。
poky:Yocto的基础发行版,在此版本基础上进行构建自己的嵌入式Linux发行版。
需要注意的是,对于i.MX板卡的配置,主要是在meta-imx以及meta-freescale中定义的,包括Linux内核、U-Boot以及一些板级硬件配置信息。
通过repo获取了Yocto项目源码(NXP官方的index: imx-manifest.git项目的imx-linux-zeus分支)之后,还需要初始化Yocto构建目录,用于Yocto构建嵌入式Linux系统的工作环境(实际上是创建一些文件夹、初始化一些变量值,得到的配置文件,用于构建特定的嵌入式Linux发行版本)
。 在repo获取的Yocto项目源码路径(/home/jason/Linux/Yocto/fsl-release-yocto)下,Freescales提供了imx-setup-release.sh脚本。该脚本用于初始化Yocto构建目录,如下方法执行imx-setup-release.sh脚本
(先使用chmod 777分配可执行权限):
DISTRO=<distro name> MACHINE=<machine name> source imx-setup-release.sh -b <build dir>
DISTRO=fsl-imx-fb MACHINE=imx6ull14x14evk source imx-setup-release.sh -b build
// 创建了一个基于imx6ull14x14evk硬件平台,嵌入式Linux系统发行版为fsl-imx-fb的Yocto构建环境,位于/home/jason/Linux/Yocto/fsl-release-yocto/build路径下
完成了Yocto构建目录的初始化,该脚本运行结束后,自动生成build文件夹,并自动切换至build路径
,后续系统的构建过程就是在该build文件夹下完成的。同时在build文件夹下,还会生成一个conf文件夹
: 该conf文件夹中有两个重要的文件:bblayers.conf和local.conf两个配置文件,后面将会详细解析:
<build dir>/conf/bblayer.conf:该配置文件定义了构建嵌入式Linux系统发行版所需要使用的metalayers。
<build dir>/conf/local.conf:该配置文件定义了MACHINE和DISTRO的配置项。
imx-setup-release.sh脚本运行时,需要输入3个主要参数:
DISTRO=fsl-imx-fb
MACHINE=imx6ull14x14evk
-b build
总体来说,imx-setup-release.sh脚本通过这3个参数来确定了构建环境,其中,-b build生成了一个build文件夹,用于存放Yocto在构建系统过程中产生的临时文件、构建日志以及最终生成的安装文件等。同时Yocto根据DISTRO(发行版本)和MACHINE(硬件平台)这两个参数,找到相对应的配置文件(.conf),这些配置文件定义了所需构建的嵌入式Linux系统的功能和状态。
在imx-setup-release.sh脚本中,有如下几个地方需要了解: 第22行,设置了变量PROGNAME为“setup-environment”,在imx-setup-release.sh脚本所在的路径下,有一个名叫setup-environment的shell脚本,在imx-setup-release.sh脚本中,会调用setup-environment脚本。
第59行,通过脚本参数-b build,设置变量BUILD_DIR为build(-b build传入build),用于创建工作目录。
第119行,通过脚本参数 DISTRO=fsl-imx-fb,设置变量DISTRO为fsl-imx-fb,用于设置嵌入式Linux系统的发型版本设置,在移植部分会详细讲解DISTRO。
第156行,通过DISTRO和MACHINE两个参数,调用PROGNAME脚本即setup-environment脚本。关于setup-environment脚本,下一小节中会进行描述。
第169~195行,比较重要的部分,将使用到的Layers写入build/conf/bblayers.conf文件中,用于设置构建嵌入式Linux系统所使用到的Layers。关于Layers的概念,后续章节会详细描述。
在imx-setup-release.sh脚本中,会通过DISTRO=$FSLDISTRO MACHINE=$MACHINE . ./$PROGNAME $BUILD_DIR
调用setup-environment脚本。输入 ./setup-environment -h命令,查看setup-environment脚本帮助信息,该信息列出了Yocto路径下支持的MACHINE。
在setup-environmet脚本中,第92行,通过MACHINE变量值找到相应的.conf文件,该.conf文件用来配置嵌入式Linux发行版。在/home//Linux/Yocto/fsl-release-yocto/sources路径下,有很多的meta-xxx文件夹,在这些文件夹中有各种不同的machine和distro文件夹
,在这两个文件下下面有不同的配置文件。通过imx-setup-release.sh脚本,就能确定所使用的是哪个machine、distro文件夹里
的配置文件,用于配置所需构建的嵌入式Linux发行版。
总的来说,imx-setup-release.sh脚本,主要实现了以下三个重要功能,用于配置所需构建的嵌入式Linux系统的发行版:
1.创建Yocto构建工作环境,新建build文件夹并进入,还创建了conf文件夹
2.将layers、machine、distro等信息写入配置文件:
<build dir>/conf/bblayer.conf:该配置文件定义了构建嵌入式Linux系统发行版所需要使用的metalayers。
<build dir>/conf/local.conf:该配置文件定义了MACHINE和DISTRO的配置项。
3.根据DISTRO和MACHINE这两个参数,找到相应路径下的配置文件(.conf)。这些配置文件定义了需要构建的嵌入式Linux的功能和状态。
DISTRO= fsl-imx-fb :sources/meta-imx/meta-sdk/conf/distro/fls-imx-fb.conf 在该文件中定义了一些变量,用于配置嵌入式Linux发行版
MACHINE= imx6ull14x14evk :sources/meta-imx/meta-imx/meta-bsp/conf/machine/imx6ull14evk.conf 在该文件中定义了一些变量,用于配置嵌入式Linux运行的硬件平台。
后续在根据不同的硬件板卡及软件需求定义相应的嵌入式Linux发行版时,会详细的描述如何修改imx-setup-release.sh脚本,以及相关的MACHINE、DISTRO对应的.conf文件的修改。
通过NXP提供的imx-setup-release.sh脚本,创建了一个工作空间后,就可以在该工作空间(build)文件夹下构建嵌入式Linux系统镜像文件,用于烧录到最终的开发板中。
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镜像文件,可供选择,需要注意的是,镜像文件支持的功能越多,(根)文件系统就越大: 实际yocto提供了poky项目,在这基础上构建了嵌入式系统,增加了额外功能,基于poky构建提供的镜像实际都是一些基础东西,实际工程中不会用到。
/home/Linux/Yocto/fsl-release-yocto :source imx-setup-release.sh
也可进入build目录,/build/bitbake -h
这里选的是imx-image-multimedia。实际上,通过运行bitbake imx-image-multimedia命令,bitbake会找到/sources/meta-imx/meta-sdk/recipes-fsl/images路径下的imx-image-multimedia.bb文件,根据imx-image-multimedia.bb
文件中的配置进行系统的构建。同时在/sources/meta-imx/meta-sdk/recipes-fsl/images路径下还可以看到fsl-image-core.bb
等文件,与上表中提到的镜像文件相对应。运行bitbake imx-image-multimedia命令后,就开始使用bitbake工具构建嵌入式Linux系统: 将构建整个嵌入式系统分成一个个task进行的,这些task主要根据bb文件下配置产生不同task编译来构建不通功能
在build文件夹下,运行bitbake命令“bitbake imx-image-multimedia” 后:开始构建系统。系统构建完成后,会在~/Linux/yocto/fsl-release-yocto/build/tmp/deploy/images/imx6ull14x14evk路径下输出manifest文件
, 这个文件里包含了对应文件系统中已安装的软件包
。同时该路径下还生成了一些其他文件:
BitBake构建的第一步是解析Metedata基本配置文件,这些基本配置文件确定了所构建嵌入式Linux系统发行版的一些功能及特征。在了解解析Metadata基本配置之前,需要先了解几个概念。
Yocto由一些Metadata组成,具体来说,通过repo获取Yocto项目后,在source目录下有一些文件夹,这些文件夹就是一个个的metadata。如下图所示,在这些文件夹中包含了许多的文件,用于构建嵌入式Linux系统。
从上图可以看出,在sources目录下有一些meta开头的meta-xxx文件夹,但是,针对不同的嵌入式Linux发行版的需求,需要使用不同的metadata,有可能需要增加新的metadata,也有可能减少一些metadata。对于使用那些metadata(meta-xxx文件夹)是由在通过imx-setup-release.sh脚本初始化构建目录时确定的,在使用imx-setup-release.sh脚本时,会创建一个build文件夹,在build/conf路径下,生成了一个bblayers.conf的配置文件,BitBake工具会根据该bblayers.conf文件中的定义,确定使用那些metadata用于构建嵌入式Linux发行版,例如:
如下oe-setup-builddir就是imx-setup-release.sh,这脚本就会把metadate用到的哪些内容echo到bblayers.conf
,写进去后就用bitbake根据bblays.conf文件找到相对应使用的metadata去构建系统。
在Metadata中,有许多文件存放于source/meta-xxx文件夹下,用于构建嵌入式Linux系统发行版。如下图所示:
classes
:该文件夹下的.bbclass文件,包含了一些在不同的metadata之间共享的信息,以及编译信息的抽象,例如:如何编译Linux内核。
conf
:该conf文件夹下的layer.conf文件定义了该metadata中使用的哪些.bb、.bbappend文件等参与构建嵌入式Linux系统。
recipes-xxx
:该文件夹中有许多的.bb或.bbappend文件,这些文件定义了构建嵌入式Linux系统需要的软件包或源码等,主要包括:软件包的基本信息:作者、主页、License等。
版本信息。
依赖文件。
从哪下载以及如何下载软件包。
软件包补丁信息:是否需要补丁、补丁下载地址及方式等。
如何配置、如何编译软件包、安装位置等。
备注:可以通过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列表(哪个厂家提供的哪个模块来参与构建)。例如,假设一个名为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自己完成的,不需要用户进行干预。
User Configuration
:用户配置信息,用于控制构建过程中使用到的Metadata。
Metadata Layers
:Metadata Layers中包含许多Recipes,用于设置需要使用哪些软件包、源码,以及这些软件包、源码的配置、编译、安装方式。
Source Files
:构建系统所使用到的软件包、源码,这些软件包、源码有多种获取途径,DL_DIR变量。
Build System
:主要指BitBake获取源码、打补丁、编译、安装、生成目标文件的过程。
Images
:构建嵌入式Linux系统生成的目标文件,用于最终的嵌入式Linux系统。
application Development SDK
:Yocto还可以用于构建交叉编译工具。
build/conf路径下的bblayers.conf和local.conf两个文件(就是User Configuration)都是有imx-setup-release.sh脚本生成的。BitBake在构建系统时会使用到这两个文件中的变量,但是如果需要更改配置,是通过imx-setup-release.sh脚本中修改,不建议直接修改这两个文件。
bblayers.conf文件确定了BitBake将使用哪些Metadata(layers)构建系统,主要由变量BBLAYERS确定。例如,在imx-setup-release.sh脚本中有如下定义:
local.conf提供了一些基本的变量,定义了构建环境,如:MACHINE、DISTRO、DL_DIR等,这些变量也是通过imx-setup-release.sh脚本确定的。
MACHINE
:目标平台选取,例如:imx6ull14x14evk。
DISTRO
:基于目标平台确定的嵌入式Linux发行版本。
PACKAGE_CLASSES
:定义生成的目标文件格式类型,例如:PACKAGE_CLASSES ?= “package_rpm package_deb package_ipk package_tar” 等。
BB_DISKMON_DIRS
:该变量定义了工作路径下各文件夹的大小。
DL_DIR
:定义了下载文件的存放路径。BitBake在构建系统过程中,需要下载各种软件源码、工具软件等,这些下载的软件或者软件源码就存放在DL_DIR变量定义的路径下,例如:DL_DIR ?= "${BSPDIR}/downloads/"所对应的就是/Linux/Yocto/fsl-release-yocto/downloads。
Metadata元数据,是BitBake构建嵌入式Linux系统过程中所使用的最基础的数据。Metadata一定程度上来说就是指的Layers,两个概念在一定的场景下表示的是同一个含义。在build/conf/bblayers.conf文件中定义了所使用的Layers,对应的就是使用Metadata下的文件。Metadata具体表现为一个个以meta-xxx的文件夹,位于在sources目录下,在meta-xxx文件夹下主要有三种类型的文件夹:classes、conf和recipes。这三个文件夹下分别存储不同的文件:
classes
:classes文件夹下主要存放的是.bbclass文件,.bbclass文件保存了通用的函数或变量,使其能够在其他recipes中通过inherit关键字引用。
conf
:conf文件夹下主要存放layer.conf、conf/distro/distro.conf以及distro.conf中包含的inc文件。这些文件主要用于定义当前layer的一些基本信息。如:使用哪些.bb文件等。
recipes
:meta-xxx文件夹下有许多的recipes文件夹,recipes文件夹下主要存放.bb、.bbapped文件,.bb、.bbapped主要定义了构建系统所使用到的软件包、源代码、补丁文件
以及这些软件包、源代码的配置、编译、安装方法。
如下所使用软件如内核文件从哪个地方SRC_URI获取并参与系统构建。do_install()
告诉linux内核去安装在哪些位置,把相应头文件安装在哪个地方去。
Yocto在构建系统image文件时,需要使用到一些第三方软件包或源码等,这些软件包或源码就叫做sources files,例如:bluez-5.37.tar.xz、connman-1.31.tar.xz等。通常sources files有三种来源:Upstream Project Release、Local Projects、SCMs。一般来说,对于参与系统构建过程中一些稳定发布版的第三方软件,通常采用压缩包(tarballs)的方式。对于需要在构建系统过程中不断修改调试的第三方软件,通常采用通过SCM(例如git)管理软件源码的方式,参与到系统构建过程中。
在每个recipe中存在一个SRC_URI变量,该变量定义了recipe所使用到的软件包或源码地址。BitBake就是通过SRC_URI所指向的地址获取相应的软件包或源码的。 需要注意的是,Yocto提供了DL_DIR变量,用于指定下载的source files存放地址,构建系统搜索source files时,BitBake首先搜索download路径下是否有相应的source files,如果没有,再在通过其他路径搜索。通过这种机制,可以减少了由于网络原因导致的构建时间过长。
Upstream project releases
:其他项目软件包通常以存档文件的方式存在(tarball、zip文件)。Local Projects
:本地提供的而一些软件包。SCM(Source Control Manageers)
:通过Git等版本管理工具获取的软件包等。当采用SCM获取源码时,BitBake在构建系统过程中的do_fetch任务时,将根据recipe中定义的SRC_URI变量以及SRCREV变量,通过SCM工具克隆或Check Out源码参与构建系统。
生成的中间文件类型是由build/local.conf文件中的PACKAGE_CLASSES变量确定的,如:ipk、rpm等。最终BitBake会将这些中间文件生成最终需要使用的image文件,其中有几个文件夹下的内容是需要了解下:DEPLOY_DIR:指的是build/tmp/deploy,在该路径下存放最终生成的嵌入式Linux镜像文件。 bitbake是会调用do_package_write打包生成最终img文件。
BitBake(蓝色)是构建系统的工具。BitBake根据用户的配置信息,自动的从不同的地方获取软件包或源文件,将其按照一定的规则构建出最终使用的Image文件(嵌入式Linux发行版)。BitBake的工作过程中,是以一个个task的形式存在的,主要包括:Source Fetching、Patching、Configuration andCompilation、Package Splitting、Image Generation、SDK Generation(可选)。
Source Fetching
:BitBake工作的第一步就是获取源文件。BitBake会根据Recipe中定义的SRC_URI找到相应的源文件,将其下载并解压。该过程主要在build/tmp/work目录下完成。
TMPDIR:构建系统过程中使用到的临时文件存放的地方,通常来说,就是build/tmp路径
PACKAGE_ARCH:构建系统所使用的架构,如:cortexa7hf-neon、x86_64等
TARGET_OS:目标操作系统,如:linux-gnueabi、linux等
PN:安装包名称
PV:安装包版本号
PR:安装包修正版本号
Patching
:一旦获取并解压缩了源代码,BitBake就会定位补丁文件(如果有)并将它们应用到源文件中,BitBake通过SRC_URI变量找到补丁文件(.patch或.diff)。BitBake按照查找补丁的顺序为单个Recipe查找并应用多个补丁。
Configuration and Compilation
:修补源代码后,BitBake将执行配置和编译源代码的任务,主要包括三个Tasks:这三个Task所对应的方法,在对应的Recipe中的.bb或.bbappend文件中都可以redifine:
do _configure
:不同的source code配置不同,BitBake会根据recipe中.bb或.bbappend文件中定义的配置方法进行配置。当然也支持使用autotools。
do_compile
:配置完成后,就开始执行编译过程。
do_install
:编译完成后,开始执行安装过程。将安装在image路径下。
Package Splitting
:在配置并编译了源代码之后,OpenEmbedded构建系统将分析结果并将输出拆分为软件包。分析过程涉及以下各项:拆分出调试信息,查看包之间的共享库依赖关系,以及包之间的关系。do_packagedata任务根据分析结果创建软件包,以便OpenEmbedded可以生成最终软件包。
Image Generation
:拆分软件包并将其存储在Package Feeds区域(也就是bulid/tmp路径下),OpenEmbedded将使用BitBake生成根文件系统镜像。
Image文件生成过程包括多个阶段,并取决于多个任务和变量。do_rootfs任务
创建Image文件所使用的根文件系统(文件和目录结构),do_rootfs任务使用几个关键变量来确定创建实际安装软件包列表:
IMAGE_INSTALL
:列出要安装的基本程序包。
PACKAGE_EXCLUDE
:指定不应安装的软件包。
IMAGE_FEATURES
:指定要包含在image文件中的功能。 这些功能大多数都映射到其他软件包进行安装。
PACKAGE_CLASSES
:指定要使用的软件包,并且确定软件包在Package Feeds中的位置。
IMAGE_LINGUAS
:确定要安装的语言支持包。
PACKAGE_INSTALL
:最终安装到Image文件中的软件包列表。
BitBake通过变量IMAGE_ROOTFS指向构造的根文件系统的位置,并根据PACKAGE_INSTALL变量指定的最终安装的软件包列表,从而创建最终的根文件系统。在生成的根文件系统目录下,manifest文件(.manifest)列出了根文件系统中所安装的软件。
SDK Generation
:OpenEmbedded构建系统使用BitBake生成两个软件开发工具包(SDK)安装程序脚本,包括标准的SDK和可扩展的SDK。可以通过生成的SDK安装脚本,安装相应的SDK。
OpenEmbedded构建系统生成的image是可以在目标设备上启动的BootLoader、Linux Kernel、Device Tree、根文件系统:
生成的文件位于:build/tmp/deploy/images/machine/ 文件夹下。主要包含:kernel-image(内核文件)。root-filesystem-image(根文件系统文件)。BootLoader(boot文件)。
构建系统的同时,还可以构建应用软件开发SDK。根据是否构建标准SDK(例如,bitbake -c populate_sdk)或可扩展的SDK(例如bitbake -c populate_sdk_ext映像名称),SDK生成过程会有所不同。
输出的形式是自解压SDK安装程序( .sh)。当运行SDK安装程序( .sh)时将安装该SDK。该SDK由交叉开发工具链,库、头文件以及一个SDK环境设置脚本组成。 运行此安装程序基本上可以进行设置交叉编译环境。 SDK对应的交叉编译环境主要运行在主机上,用于编译目标文件。 另一方面,库和头文件视为“目标”部分,是为目标硬件平台构建的,在目标硬件平台上运行时,需要将这些库和头文件拷贝至目前硬件平台的系统中。
Yocto的开发一般包括:创建Layers、添加新的软件包、扩展或定制系统镜像以及移植到新的硬件平台(增加新的MACHINE)等。
Yocto使用的是OpenEmbeded来构建系统,并且支持以Metadata的形式来组织管理构建系统所使用的软件包、源代码、配置信息等。Metadata一定程度上可以理解为Layers
,实际上就是一个个的文件夹(这些文件夹通常以meta-xxx的形式命名)。采用Layers的方式管理源数据,有利于保持模块化的设计方式,一个Layer包含了一些特定功能所需要的源数据,各Layer之间互不干扰,当所构建的系统需要的功能发生变化时,只需要修改该功能对应的Layer即可,保持了功能的独立性及模块化设计。
1.
查看已存在的Layers:通常来说,http://layers.openembedded.org/layerindex/layers/ 列出了目前已经存在的公共的开放的Metadata,当需要创建新的Layer时,可以先在该网站上查看下是否已经有了现成的Metadata可供使用,如果有,直接使用即可。如果没有,就需要自己新创建。
2.
创建一个文件夹,用来存放Layer里的数据,通常将该文件夹命名为meta-xxx。例如:meta-mylayer、meta-GUI_XYZ、meta-mymachine等。
3.
创建Layer配置文件。在新创建的Layer文件夹下(例如:meta-mylayer)创建conf/layer.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"
LAYERVERSION_mylayer = "3
. BBPATH
:将新增加的Layer路径增加至全局变量bbPATH中,BitBake在构建系统时,会根据该变量找到相对应的Layer。
. BBFILES
:将新增加的Layer中的Recipe文件(即:.bb或.bbappend文件)增加至全局变量bbFILES中,BitBake在构建系统时,会根据该变量找到对应的recipe文件。
. BBFILE_COLLECTIONS
:将layer名字追加到bbFILE_COLLECTIONS变量,即将Layer的文件夹名字meta-xxx中的xxx赋值给bbFILE_COLLECTIONS 即可。
. BBFILE_PATTERN
:bbFILE_PATTERN变量为正则表达式,用来匹配bbFILES所在的层,按照基本框架修改即可。
. BBFILE_PRIORITY
:Layer的优先级。当不同的Layer中定义了相同的recipe时,将按照bbFILE_PRIORITY所对应的高优先级使用相对应的recipe文件。
. LAYERVERSION
:定义了Layer的版本信息。
4.
增加内容。根据Layer的类型,有的Layer会增加machine和distro配置,因此,需要在Layer下的conf/machine/文件中添加机器配置,在该层的conf/distro/文件中添加发行版配置。
考虑到创建的Layers易于维护,且不会影响到其他Layer,创建Layers时,应该遵循一些原则:避免覆盖其他Layer中的recipe。也就是说,尽量不要将其他Layer中的整个recipe复制到新创建的Layer中,并对其进行修改。而是采用追加文件.bbappend文件的方式,覆盖仅需要修改的部分。
避免重复包含文件。对于需要包含文件的recipe,使用.bbappend文件或者使用相对于原始Layer的相对路径在进行应用,例如:使用require recipes-core/package/file.inc代替require file.inc。
创建了新的Layer需要使能之后才能参与到系统的构建过程中。在build/conf/bblayers.conf中定义了参与构建系统使用到的Layers。对于iMX6ULL,Freescale官方提供了imx-setup-release.sh脚本用于修改build/conf/bblayers.conf文件,在初始化Yocto构建目录时,调用imx-setup-release.sh脚本。因此,修改imx-setup-release.sh脚本即可,修改方式如下:
新增加的echo "bbLAYERS += " ${BSPDIR}/sources/meta-bird-imx6ull “” >> $BUILD_DIR/conf/bblayers.conf就是将build/conf/bblayers.conf中的bbLAYERS变量增加新增的meta-bird-imx6ull。
用于将Metadata附加到其他recipes的recipes称为BitBake附加文件。 BitBake附加文件使用.bbappend文件类型后缀,而要附加Metadata的相应的recipes则使用.bb文件类型后缀。通过.bbappend文件,可以使得创建的Layer在不拷贝其他recipe到新建的Layer中的情况下,以附加或改写的方式改变其他Layer中的内容。
直观来看,就是新建的Layer中的.bbappend文件,与需要修改或附件额外内容的.bb文件处于不同的Layer。 附件文件(.bbappend)必须和对应的recipes(.bb)文件名(或文件名与版本号)一致。在构建系统过程中,当BitBake检测到某个.bbappend文件没有对应的.bb文件时,将会报错。
每一个Layer都分配了一个优先级。当在不同的Layer中,出现了同样的recipe时,Layer中分配的优先级的值越大,将优先使用该Layer中的recipe。优先级的值同样会影响到.bbappend文件。如BBFILE_PRIORITY_mylayer = “5”。 需要注意的是:有可能会出现低版本但是拥有高优先级的recipe优先执行的情况。
BitBake提供了Layer管理工具,用来查看Layers的一些基本信息。使用方式如下: $ bitbake-layers command [arguments]
可以使用的命令如下:
help:帮助命令。
show-layers: 显示当前配置的Layer。
show-recipes: 显示可用的recipes以及recipes提供的layers。
show-overlayed: 显示覆盖的recipes。高优先级Layer中的recipe将覆盖其他低优先级Layer中相同的recipes。
show-appends: 显示.bbappend文件,以及对应的recipe文件。
show-cross-depends: 显示不同Layer中recipes的依赖关系。
在Layer中,增加相应的COPYING.MIT文件和README文件是比较推荐的做法。
实际工程应用中,需要根据不同的需求定制化系统。该小节概要性的描述了定制化系统的几种方法,先对定制化系统的方法有个整体性的认识,后续章节会对定制化系统的详细步骤进行讲解。Yocto提供了几种定制化系统的方法,可以根据实际应用场景选择不同的方法。
通过直接修改build/conf路径下的local.conf配置文件增加软件包是最简单的定制系统的方法之一。同时由于是直接修改local.conf文件,这种方法一般来说仅适用于在系统image文件中增加软件包。当使用local.conf文件中的变量增加软件包时,需要注意的是,增加的软件包对于所有的系统image文件都有效。
例如在local.conf文件中增加如下语句,将在生成的系统image文件中安装“strace”软件:IMAGE_INSTALL_append = " strace"
(注:等号与软件包名“strace”之间的空格是必须的)。
同样的,修改local.conf中的IMAGE_INSTALL_append将影响所有的image文件。如果需要只针对某一特定的image文件有效,可以通过扩展语句的方式实现,如:IMAGE_INSTALL_append_pn-core-image-minimal = " strace"
,采用该方式,新增加的strace软件只对core-image-minimal 系统image文件有效。
另一种增加软件包的方法是通过IMAGE_FEATURES、EXTRA_IMAGE_FEATURES变量。尽管IMAGE_FEATURES、EXTRA_IMAGE_FEATURES这两个变量在用法上几乎一致,但是,在实际使用过程中,IMAGE_FEATURES一般用于recipes内,而EXTRA_IMAGE_FEATURES一般用于build/conf路径下的local.conf文件中。总的来说,这两个变量最终都是通过修改IMAGE_INSTALL变量来实现的,该方法在实际过程中并不常用
。
比较常用的一种定制系统镜像的方法是使用.bb文件。可以通过创建一个recipe来定义镜像文件需要增加的软件包。例如在新创建的.bb文件中,增加如下代码:IMAGE_INSTALL = "packagegroup-core-x11-base package1 package2" , inherit core-image
另一种方法,是通过在已经存在的系统镜像文件上进行修改。例如:如果想构建一个基于core-image-sato的系统镜像文件,但是,需要额外的增加strace软件包,可以通过拷贝/sources/poky/meta/recipes-sato/images/core-image-sato.bb文件,将其命名为一个新的.bb文件,然后在新的.bb文件中通过增加以下代码,实现strace软件包的增加:IMAGE_INSTALL += "strace"
(推荐使用这种方法)。
对于复杂的应用,可以使用package groups的方式定制系统镜像。例如:/sources/poky/meta/recipes-core/packagegroups/packagegroup-base.bb文件。
一般来说主机名和系统中配置的主机名(/etc/hostname)是一致的。例如:如果MACHINE等于“qemux86”,那么写入/etc/hostnam的主机名就是“qemux86”。可以通过修改Recipe base-files中的hostname变量来实现自定义主机名。例如,可以在某一个.bbappend文件中使用如下代码:hostname=“myhostname”,或者在配置文件中使用如下代码:hostname_pn-base-files = “myhostname”。
Metadata(Layer)是由一些Recipes组成的。从形式上来看,Recipes是在metadata文件夹下的一些文件夹(同样的惯例以recipes-xxx命名)。recipes-xxx文件夹中的recipes(.bb文件)是Yocto工程的最基础组成部分。OpenEmbedded构建系统使用的软件包等组件都是在recipe中定义的。
有两种比较简便易行的创建新的recipes的方法:
recipetool:Yocto提供的工具,基于源文件自动创建基础recipe。
Exitsing Recipes:在一个功能需求相似的已有recipe基础上修改。
教程中着重讲解第二种方式。通常,recipe中定义了一些变量用于定义需要使用的软件包,其基本框架如下:
DESCRIPTION = ""
HOMEPAGE = ""
LICENSE = ""
SECTION = ""
DEPENDS = ""
LIC_FILES_CHKSUM = ""
SRC_URI = ""
创建了基础的recipes之后,需要按照一定的目录框架将recipes放在合适的位置,以确保OpenEmbedded构建系统时能够找到。OpenEmbedded是通过Layer(meta-xxx文件夹)下的conf/layer.conf中的变量BBFILES找到构建过程中所使用的recipes。其典型的应用如下:BBFILES += "${LAYERDIR}/recipes-//.bb \ ${LAYERDIR}/recipes-//.bbappend"
,因此必须确保新创建的recipe在layer中的正确路径。 此外对于recipe文件的命名,也应该按照一定的规则:basename_version.bb,使用小写字母字符,并且不包括保留的后缀-native,-cross,-initial或-dev。
对于新创建的recipe,往往需要不断的修改编译、反复迭代才能逐步实现完善最终的功能。在使用fls-setup-release.sh脚本初始化Yocto构建目录后,将自动进入build目录,在该路径下,通过如下命令即可编译recipe:$ bitbake basename,其中basename是recipe的文件名。在编译过程中,OpenEmbedded编译系统会为每一个recipe创建一个临时的文件夹,用来存放解压文件、日志文件等。每一个recipe的临时文件夹都按照如下的方式组织:
BASE_WORKDIR ?= "${TMPDIR}/work"
WORKDIR = "${BASE_WORKDIR}/${MULTIMACH_TARGET_SYS}/${PN}/${EXTENDPE}${PV}-${PR}"
例如:假设生成的系统架构为qemux86-poky-linux,recipe文件为foo_1.3.0.bb ,那么,将生成如下的文件:
/build/tmp/work/qemux86-poky-linux/foo/1.3.0-r0,该路径下还可看到image、packages-spilt和temp等文件夹。编译之后,可以通过查看这些文件夹里的内容确定编译过程是否正确。
构建系统的过程,实际上是将一些软件源码编译成系统镜像文件的过程,因此recipe的第一步是定义如何获取相关的软件源码。在recipe中,通过SRC_URI变量定义了软件源码的位置。BitBake编译系统镜像文件的过程可以分为几个任务分步完成的,其中一个任务do_fetch会根据SRC_URI变量值的前缀确定使用哪个fetcher从什么地方获取软件源码。获取源码结束后,do_patch任务也会根据SRC_URI变量值来打补丁。
recipe中的SRC_URI定义了软件源码的唯一地址。推荐在SRC_URI变量中定义的软件源码地址包含${PV}的方式,以便在获取软件源码过程中使用recipe文件名中定义的版本,同时,后续当需要升级软件版本时,只需要将recipe文件名进行版本号升级即可。例如:meta/recipes-devtools/cdrtools/cdrtoolsnative_3.01a20.bb的recipe中,SRC_URI变量值使用了“PV”值。
SRC_URI = "ftp://ftp.berlios.de/pub/cdrecord/alpha/cdrtools-${PV}.tar.bz2"
还可以通过SCM(Source Control Managers)获取软件源码,例如Git。对于Git来说,还需要在recipe中定义SRCREV和SRCPV变量值,例如:meta/recipeskernel/blktrace/blktrace_git.bb:
SRCREV = "d6918c8832793b4205ed3bfede78c2f915c23385"
PR = "r6"
PV = "1.0.5+git${SRCPV}"
SRC_URI = "git://git.kernel.dk/blktrace.git \
file://ldflags.patch"
其中SRCPV = “${@bb.fetch2.get_srcrev(d)}”,此外如果SRC_URI指向的软件源码地址不是从SCM,而是远程服务器或其他地址的软件源码包,则需要定义相对应的软件源码包校验值,以便BitBake在编译时通过校验值确定软件包的完整性。例如:
SRC_URI = "${DEBIAN_MIRROR}/main/a/apmd/apmd_3.2.2.orig.tar.gz;name=tarball \
${DEBIAN_MIRROR}/main/a/apmd/apmd_${PV}.diff.gz;name=patch
SRC_URI[tarball.md5sum] = "b1e6309e8331e0f4e6efd311c2d97fa8"
SRC_URI[tarball.sha256sum] = "7f7d9f60b7766b852881d40b8ff91d8e39fccb0d1d913102a5c75a2dbb52332d"
SRC_URI[patch.md5sum] = "57e1b689264ea80f78353519eece0c92"
SRC_URI[patch.sha256sum] = "7905ff96be93d725544d0040e425c42f9c05580db3c272f11cff75b9aa89d430"
如果获取的源码是压缩包的形式,在编译过程中,do_unpack任务会将压缩包进行解压。
有时在获取了软件源码之后,需要进行打补丁。在SRC_URI中以.patch、.diff或者是这些后缀的压缩包(如:diff.gz)都是补丁代码。在执行do_patch任务时,会自动的应用补丁。
在recipe中,需要包含LICENSE和LIC_FILES_CHKSUM变量。例如:
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=xxx"
LICENSE变量确定了软件采用的license,通常来说,可以在软件包的说明,例如COPYING、LICENSE、README等文件中找到对应软件包的License定义,也有可能会在软件源码文件的头部找到相关的信息。
大多数软件在编译前,提供了一些方式用于配置软件。通常来说,采用带有参数选项的脚本或配置文件是比较典型的方式。在OpenEmbedded编译过程中同样如此。其中,软件配置的主要一部分是检测软件编译过程中的依赖关系,可以通过recipe文件中的DEPENDS变量值,指定该软件包的依赖项,这些依赖项通常会在软件包的描述文档中有所涉及。 一般来说,可以将软件包的配置项分为以下三类:
1.
Autotools:对于提供了configure.ac文件的软件包,一般采用的是Autotools工具进行配置,对于这种情况,直接修改configure.ac文件即可。但是需要注意的是,由于使用了Autotools,需要在recipe中引入autotools class。并且在recipe中不需要在包含do_configure任务。
2.
CMake:对于提供了CMakeLists.txt文件的软件包,一般采用的是CMake工具进行配置,对于这种软件包,只需要直接修改CMakeLists.txt配置文件即可。同样的,由于使用了CMake,因此,需要在recipe中引入cmake class。并且在recipe中不需要在包含do_configure任务。
3.
Other:对于没有采用Autotools或CMake的软件包,并且需要进行配置的话,则需要在recipe中提供do_configure任务,用于编译前配置软件包。当然,如果软件包不需要进行任何的配置除外。
在OpenEmbedded编译完成后,可以通过log.do_configure文件查看软件包的配置项,以确定配置项是否成功。
在获取、解压、配置软件源码之后,BitBake通过do_compile任务自动开始编译recipe。
Linux下安装软件大致过程如下:
1.
建立安装目录
2.
拷贝类库
3.
拷贝可执行程序
4.
根据需要选择性配置和启动服务
在编译recipe过程中的do_install任务,将构建的文件及其层次结构复制到生成的镜像文件相应的位置中,即可实现软件的安装。不同的软件编译方式,其安装方式也会有所不同:
1.
Autotools以及CMake:如果使用的是Autotools或者CMake编译软件,则OpenEmbedded构建系统会自动使用Autotools或者CMake中的安装方式进行软件的安装,因此,不需要在recipe文件中增加do_install函数;但是,如果需要在安装软件增加额外的文件(这些文件未被Autotools或CMake在安装过程中使用),则可以在recipe文件中增加do_install_append函数来进行安装,安装方式和手动安装一致。
2.
手动安装:在recipe文件中,通过定义do_install函数,可以用来安装相应的软件。在do_install函数中,必须先使用install -d命令,来创建一个安装目录,然后就可以使用install命令来手动将编译好的软件安装(复制)到对应的文件夹中。关于install更多的方法,可以参见http://www.gnu.org/software/coreutils/manual/html_node/install-invocation.html
可以通过在recipe中增加一些定义,用来安装一些需要在系统开始运行时或者在后台一直运行的进程服务。当需要增加系统服务,可以通过在recipe中使用do_install_append函数来安装相应的服务。当然,如果在recipe已经存在了do_install函数,那么在do_install中实现系统服务的安装也是一种更好的选择。 OpenEmbedded提供了两种方式用于启动系统服务:
SysVinit
:SysVinit是一种系统和服务管理器,用来管理系统初始化过程,控制着系统基础功能。Linux内核启动之后,最开始调用的就是初始化程序。要想通过SysVinit使能系统服务,在recipe中需要引入update-rc.d,用来实现安全的安装软件包,同时,还需要设置INITSCRIPT_PACKAGES、INITSCRIPT_NAME以及INITSCRIPT_PARAMS变量。
systemd
:systemd(System Management Daemon)取代了SysVinit,用来提供系统服务的更高阶管理。可以通过http://freedesktop.org/wiki/Software/systemd/ 获取更多关于systemd的信息。同样的,要想使用systemd来使能系统服务,需要在recipe中引入systemd。使用方法可以参见systemd.bbclass.。
在实际项目中,一款嵌入式产品往往具有不同的硬件平台和软件需求,因此需要对嵌入式Linux系统进行定制,以满足不同的产品需求。之前的章节中基于Freescale官方提供的例程,构建了运行于imx6ull14x14evk硬件平台上的fsl-imx-fb发行版本,以此熟悉了Yocto的基本原理和工作流程。后续我们将基于Freescale官方的imx6ull14x14evk硬件平台的fsl-imx-fb发行版本,定制化自己的嵌入式Linux系统。一个完整的嵌入式Linux发行版包括U-Boot、Linux Kernel、Device Tree、rootfs。因此,定制化嵌入式Linux系统,将分为三个部分:U-Boot移植、Linux Kernel移植、构建rootfs。(Linux Kernel编译过程中,将同时生成Device Tree)。
Yocto是通过Metadata(Layers)的方式,确定构建嵌入式Linux系统的所需要的信息。Yocto和Freescale官方提供了很多的Metadata,在定制嵌入式Linux系统时,一般不会直接更改Yocto或Freescale官方提供的Metadata,而是通过创建新的Metadata,以.bb或.bbappend的方式定制自己的嵌入式Linux系统。采用Metadata的最大好处是使得软件功能模块化,把某一功能使用到的软件包或源码放在同一个Layer中,将使得当需要改变某一功能时,只需要改动相应的Metadata,而不会影响到其他功能。
在sources目录下,创建一个文件夹,例如:meta-bird-imx6ull,用于存放自定义的Metadata,所有对于定制化嵌入式Linux系统所需的配置文件、源文件等都将存放在该目录下。在基于Freescale官方提供的fsl-arm-yocto-bsp Yocto项目构建嵌入式Linux系统发行版时,第一步是使用Freescale提供的imx-setup-release.sh初始化构建环境。在使用imx-setup-release.sh脚本时,采用的是如下命令:DISTRO=fsl-imx-fb MACHINE=imx6ull14x14evk source imx-setup-release.sh -b build
。
其中参数fsl-imx-fb对应Linux发行版,imx6ull14x14evk对应Linux硬件平台。他们分别对应位于/sources/meta-imx路径下的meta-sdk/conf/distro下fsl-imx-fb.conf以及meta-bsp/conf/machine/imx6ull14x14evk.conf。因此需要在这两个文件的基础上,通过修改一定的设置,用于构建定制化的嵌入式Linux系统。在meta-bird-imx6ull文件夹中,需要按照Yocto定义的框架,创建一些文件,用于配置嵌入式Linux发行版的构建过程。教程中将以MACHINE=imx6ull-bird-dk,DISTRO=bird-imx-fb为例,构建系统。
在/sources/meta-bird-imx6ull路径下,创建一个conf文件夹,用于存放配置文件。在conf文件夹下,依次创建distro和machine文件夹。如下图所示:
在Yocto构建嵌入式Linux系统过程中,通过Layer(meta-xxx文件夹)的方式定义了构建系统所使用的配置文件、源文件等,创建好文件夹(meta-bird-imx6ull)后,通过修改layer.conf文件,将新增加的meta-bird-imx6ull加入到Yocto构建系统过程中。具体来说,将/sources/meta-imx/meta-bsp/conf路径下的layer.conf文件拷贝至/sources/meta-bird-imx6ull/conf路径下,并按照下图所示修改:
修改了BBFILE_xxx变量,用于告诉BitBake构建系统时,采用meta-bird-imx6ull文件夹下的.bb文件。其中,BBFILE_COLLECTIONS += "bird-imx6ull"中的"bird-imx6ull"必须和meta-bird-imx6ull文件夹的后缀bird-imx6ull一致。
对于新创建的Layer(meta-bird-imx6ull文件夹),是通过meta-bird-imx6ull/conf路径下的layer.conf配置文件配置的,在layer.conf文件中,主要定义了一些变量的值,如下:
BBPATH
:将当前Layer的路径增加到变量BBPATH中。
BBFILES
:在当前Layer(meta-bird-imx6ull)中,有许多的recipes,在recipes中又有各种的.bb或.bbappend文件,这些.bb或.bbappend文件用于定义了参与构建系统过程的软件的基本信息(来源、配置等)。
BBFILE_COLLECTTIONS
:该变量用于定义新增加的layer。
BBFILE_PATTERN
:该变量用于定义bbFILES所定义的值的匹配路径。
BBFILE_PRIORITY
:该变量用于定义Layer的优先级。当有多个相同的recipe存在于多个Layers中时,将用优先级高的那一个。
此外,在layer.coonf文件中还定义了一些其他的变量,用于控制系统的构建过程,在该文件中有许多与mx6不相关的其他型号的配置变量,可以将其移除,同时需要注意的是,目前在我们构建的系统中,去掉了optee相关的功能,因此,需要将layer.conf中与optee相关的部分去掉,去掉后的layer.conf文件如下所示:
# We have a conf and classes directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"
# We have a packages directory, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "bird-imx6ull"
BBFILE_PATTERN_bird-imx6ull := "^${LAYERDIR}/"
BBFILE_PRIORITY_bird-imx6ull = "9"
LAYERSERIES_COMPAT_bird-imx6ull = "warrior zeus"
HOSTTOOLS_NONFATAL_append = " bc rsync xxd"
# optee is no longer a valid distro feature. Use machine feature to remove, like this:
MACHINE_FEATURES_remove = "optee"
MACHINE_FEATURES_remove = "optee-client"
MACHINE_FEATURES_remove = "optee-os"
MACHINE_FEATURES_remove = "optee-test"
# DEPRECATED: The ability to remove optee from the build is deprecated and
# will be removed in some future release.
DISTRO_FEATURES_FILTER_NATIVESDK += "wayland"
MACHINE_USES_VIVANTE_KERNEL_DRIVER_MODULE ?= "0"
MACHINE_SOCARCH_FILTER_append_imxgpu = " opencv"
MACHINE_SOCARCH_FILTER_remove = " imx-parser alsa-lib gstreamer1.0"
# Use latest SDMA firmware from firmware-imx instead of upstream linux-firmware
MACHINE_FIRMWARE_remove_mx6 = "linux-firmware-imx-sdma-imx6q"
MACHINE_FIRMWARE_append_mx6 = " firmware-imx-sdma firmware-imx-regulatory"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'bcm4339', 'linux-firmware-bcm4339', '', d)}"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'bcm43430', 'linux-firmware-bcm43430', '', d)}"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'bcm43455', 'linux-firmware-bcm43455', '', d)}"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'bcm4356', 'linux-firmware-bcm4356-pcie', '', d)}"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'bcm4359', 'linux-firmware-bcm4359-pcie', '', d)}"
MACHINE_FIRMWARE_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'nxp8987', 'linux-firmware-nxp8987', '', d)}"
# Extra Marvell Wi-Fi & BTE driver and firmware
MACHINE_EXTRA_RRECOMMENDS_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'mrvl8997', 'packagegroup-imx-mrvl8997', '', d)}"
# Extra NXP Wlan SDK
MACHINE_EXTRA_RRECOMMENDS_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'nxp8987', 'nxp-wlan-sdk', '', d)}"
MACHINE_GSTREAMER_1_0_PLUGIN_mx6ul ?= "imx-gst1.0-plugin"
PREFERRED_VERSION_weston_mx6 ?= "8.0.0.imx"
PREFERRED_VERSION_wayland-protocols_mx6 = "1.18.imx"
PREFERRED_VERSION_libdrm_mx6 ?= "2.4.99.imx"
PREFERRED_VERSION_isp-imx ?= "4.2.2.2"
PREFERRED_VERSION_basler-camera ?= "4.2.2.2"
SOC_DEFAULT_IMAGE_FSTYPES_remove = "wic.gz"
SOC_DEFAULT_IMAGE_FSTYPES_append = " wic.bz2 tar.bz2"
# Remove from upstream
SDCARD_ROOTFS = "NO_LONGER_USED"
IMAGE_BOOT_FILES_append = " \
${@bb.utils.contains('COMBINED_FEATURES', 'xen', 'xen', '', d)} \
"
IMAGE_INSTALL_append = " \
${@bb.utils.contains('COMBINED_FEATURES', 'jailhouse', 'jailhouse', '', d)} \
${@bb.utils.contains('COMBINED_FEATURES', 'xen', 'imx-xen-base imx-xen-hypervisor', '', d)} \
"
MACHINE_FEATURES_append_imx = " nxp8987"
我们是在Freescale官方imx6ull14x14evk硬件平台基础上修改,因此将/sources/meta-imx/meta-bsp/conf/machine路径下的imx6ull14x14evk.conf文件拷贝至/sources/meta-bird-imx6ull/machine路径下,并将其重命名为imx6ull-bird-dk.conf,作为我们构建系统所使用的硬件平台的配置文件。在imx6ull-bird-dk.conf文件中主要由以下几部分构成:
include文件:在imx6ull-bird-dk.conf文件中,通过include关键字引用了imx-base.inc和tune-cortexa7.inc文件,如下图所示:
其中imx-base.inc文件
位于/sources/meta-freescale/conf/machine/include路径下,主要定义了一些imx系列CPU的默认配置参数,如U-BOOT的入口地址、默认的Linux内核文件定义等。imx6ull属于cortexA7系列的内核,因此引用了tune-cortexa7.inc文件
,该文件位于/sources/poky/meta/conf/machine/include路径下,主要定义了一些与cortexA7架构内核相关的定义,对于tune-cortexa7.inc, 我们不需要进行修改。对于imx-base.inc文件,定义了系统构建过程中使用的一些配置信息,我们需要根据实际使用情况进行相应的修改。复制/sources/meta-freescale/conf/machine/include路径下的imx-base.inc文件
,拷贝至/sources/meta-bird-imx6ull/conf/machine/include路径下
,将其重命名为imx-bird-base.inc
。
将imx6ull-bird-dk.conf文件中的include conf/machine/include/imx-base.inc
修改为include conf/machine/include/imx-bird-base.inc
。同样的在imx-bird-base.inc文件中定义了需要其他芯片imx7等构建过程相关的配置信息,可以将其移除,并且删除imx-bird-base.inc文件中与optee相关的配置信息,修改后的imx-bird-base.inc文件如下所示:
# Provides the i.MX common settings
include conf/machine/include/fsl-default-settings.inc
include conf/machine/include/fsl-default-versions.inc
require conf/machine/include/utilities.inc
# Set specific make target and binary suffix
IMX_DEFAULT_BOOTLOADER = "u-boot-fslc"
IMX_DEFAULT_BOOTLOADER_mx8 = "u-boot-imx"
PREFERRED_PROVIDER_u-boot ??= "${IMX_DEFAULT_BOOTLOADER}"
PREFERRED_PROVIDER_virtual/bootloader ??= "${IMX_DEFAULT_BOOTLOADER}"
PREFERRED_PROVIDER_u-boot-mxsboot-native ??= "u-boot-fslc-mxsboot-native"
UBOOT_BINARY ?= "u-boot.${UBOOT_SUFFIX}"
UBOOT_MAKE_TARGET ?= "u-boot.${UBOOT_SUFFIX}"
UBOOT_SUFFIX ?= "imx"
UBOOT_ENTRYPOINT_mx6ul = "0x10008000"
UBOOT_ENTRYPOINT_mx6ull = "0x10008000"
UBOOT_ENTRYPOINT_vf = "0x80008000"
PREFERRED_PROVIDER_virtual/xserver = "xserver-xorg"
XSERVER_DRIVER = "xf86-video-fbdev"
XSERVER_DRIVER_imxgpu2d = "xf86-video-imx-vivante"
XSERVER_DRIVER_vf = "xf86-video-modesetting"
XSERVER_DRIVER_append_mx8 = " xf86-video-modesetting"
XSERVER_DRIVER_use-mainline-bsp = "xf86-video-armada"
XSERVER = "xserver-xorg \
xf86-input-evdev \
${XSERVER_DRIVER}"
# Ship kernel modules
MACHINE_EXTRA_RRECOMMENDS = "kernel-modules"
# Tunes for hard/soft float-point selection. Note that we allow building for
# thumb support giving distros the chance to enable thumb by setting
# ARM_INSTRUCTION_SET = "thumb"
#
# handled by software
# DEFAULTTUNE_mx6 ?= "cortexa9t-neon"
# handled by hardware
DEFAULTTUNE_mx6ul ?= "cortexa7thf-neon"
DEFAULTTUNE_mx6ull ?= "cortexa7thf-neon"
INHERIT += "machine-overrides-extender"
MACHINEOVERRIDES_EXTENDER_mx6ul = "imxfbdev:imxpxp"
MACHINEOVERRIDES_EXTENDER_mx6ull = "imxfbdev:imxpxp:imxepdc"
MACHINEOVERRIDES_EXTENDER_FILTER_OUT_use-mainline-bsp = " \
mx6ul \
mx6ull \
"
# Sub-architecture support
MACHINE_SOCARCH_SUFFIX ?= ""
MACHINE_SOCARCH_SUFFIX_mx6ul = "-mx6ul"
MACHINE_SOCARCH_SUFFIX_mx6ull = "-mx6ul"
MACHINE_SOCARCH_SUFFIX_use-mainline-bsp = "-imx"
MACHINE_ARCH_FILTER = "virtual/kernel"
MACHINE_SOCARCH_FILTER_append_imx = " \
alsa-lib \
gstreamer1.0 \
weston \
"
MACHINE_SOCARCH_FILTER_append_imxvpu = " \
imx-codec \
imx-parser \
imx-vpuwrap \
libimxvpuapi \
virtual/imxvpu \
"
MACHINE_SOCARCH_FILTER_append_imxgpu = " \
virtual/egl \
virtual/mesa \
virtual/libopenvg \
libdrm \
cairo \
libgal-imx \
pango \
"
MACHINE_SOCARCH_FILTER_append_imxgpu2d = " \
virtual/libg2d \
"
MACHINE_SOCARCH_FILTER_append_imxgpu3d = " \
virtual/libgl \
virtual/libgles1 \
virtual/libgles2 \
"
MACHINE_SOCARCH_FILTER_append_use-mainline-bsp = " \
virtual/egl \
virtual/libopenvg \
virtual/libg2d \
virtual/libgl \
virtual/libgles1 \
virtual/libgles2 \
virtual/mesa \
cairo \
pango \
qtbase \
"
MACHINE_SOCARCH_FILTER_append_mx6q = " \
virtual/opencl-icd \
opencl-headers \
"
MACHINE_SOCARCH_FILTER_append_mx8 = " \
virtual/opencl-icd \
opencl-headers \
"
MACHINE_SOCARCH_FILTER_append_mx8qm = " \
virtual/libopenvx \
"
INHERIT += "fsl-dynamic-packagearch"
SIGGEN_EXCLUDE_SAFE_RECIPE_DEPS_append = " \
imx-gpu-viv->kernel-module-imx-gpu-viv \
libimxvpuapi->virtual/imxvpu \
imx-vpuwrap->virtual/imxvpu \
imx-codec->virtual/imxvpu \
imx-test->virtual/imxvpu \
"
# Firmware
MACHINE_FIRMWARE ?= ""
MACHINE_FIRMWARE_append_mx6ull = " firmware-imx-epdc"
MACHINE_FIRMWARE_append_use-mainline-bsp = " linux-firmware-imx-sdma-imx6q linux-firmware-imx-sdma-imx7d firmware-imx-vpu-imx6q firmware-imx-vpu-imx6d"
# FIXME: Needs addition of firmware-imx of official BSPs
#MACHINE_FIRMWARE_append_mx27 = " firmware-imx-vpu-imx27"
MACHINE_EXTRA_RRECOMMENDS += "${MACHINE_FIRMWARE}"
# Extra audio support
MACHINE_EXTRA_RRECOMMENDS_append_mx6 = " ${@bb.utils.contains('DISTRO_FEATURES', 'alsa', 'imx-alsa-plugins', '', d)}"
# Extra QCA Wi-Fi & BTE driver and firmware
MACHINE_EXTRA_RRECOMMENDS_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'qca6174', 'packagegroup-fsl-qca6174', '', d)}"
MACHINE_EXTRA_RRECOMMENDS_append = " ${@bb.utils.contains('MACHINE_FEATURES', 'qca9377', 'packagegroup-fsl-qca9377', '', d)}"
# Extra udev rules
MACHINE_EXTRA_RRECOMMENDS += "udev-rules-imx"
# GStreamer 1.0 plugins
MACHINE_GSTREAMER_1_0_PLUGIN ?= ""
MACHINE_GSTREAMER_1_0_PLUGIN_mx6ul ?= "gstreamer1.0-plugins-imx-meta"
MACHINE_GSTREAMER_1_0_PLUGIN_mx6ull ?= "gstreamer1.0-plugins-imx-meta"
# Determines if the SoC has support for Vivante kernel driver
SOC_HAS_VIVANTE_KERNEL_DRIVER_SUPPORT = "0"
SOC_HAS_VIVANTE_KERNEL_DRIVER_SUPPORT_imxgpu = "1"
# Handle Vivante kernel driver setting:
# 0 - machine does not have Vivante GPU driver support
# 1 - machine has Vivante GPU driver support
MACHINE_HAS_VIVANTE_KERNEL_DRIVER_SUPPORT ?= "${SOC_HAS_VIVANTE_KERNEL_DRIVER_SUPPORT}"
# Graphics libraries
PREFERRED_PROVIDER_virtual/egl ?= "mesa"
PREFERRED_PROVIDER_virtual/libgl ?= "mesa"
PREFERRED_PROVIDER_virtual/libgles1 ?= "mesa"
PREFERRED_PROVIDER_virtual/libgles2 ?= "mesa"
PREFERRED_PROVIDER_virtual/egl_imxgpu ?= "imx-gpu-viv"
PREFERRED_PROVIDER_virtual/libgl_imxgpu3d ?= "imx-gpu-viv"
PREFERRED_PROVIDER_virtual/libgles1_imxgpu3d ?= "imx-gpu-viv"
PREFERRED_PROVIDER_virtual/libgles2_imxgpu3d ?= "imx-gpu-viv"
PREFERRED_PROVIDER_virtual/libg2d ?= "imx-gpu-g2d"
PREFERRED_PROVIDER_virtual/libg2d_imxdpu ?= "imx-dpu-g2d"
PREFERRED_VERSION_weston_mx6 ?= "5.0.0.imx"
PREFERRED_VERSION_wayland-protocols_mx6 ?= "1.17.imx"
# Use i.MX libdrm Version
PREFERRED_VERSION_libdrm_mx6 ?= "2.4.91.imx"
# Handle default kernel
IMX_DEFAULT_KERNEL = "linux-imx"
IMX_DEFAULT_KERNEL_mx6ul = "linux-fslc-imx"
IMX_DEFAULT_KERNEL_mx6ull = "linux-fslc-imx"
IMX_DEFAULT_KERNEL_use-mainline-bsp = "linux-fslc"
PREFERRED_PROVIDER_virtual/kernel ??= "${IMX_DEFAULT_KERNEL}"
SOC_DEFAULT_IMAGE_FSTYPES = "wic.bmap wic.gz"
SOC_DEFAULT_IMAGE_FSTYPES_mxs = "uboot-mxsboot-sdcard wic.gz"
# Do not update fstab file when using wic images
WIC_CREATE_EXTRA_ARGS ?= "--no-fstab-update"
IMAGE_FSTYPES ?= "${SOC_DEFAULT_IMAGE_FSTYPES}"
IMAGE_BOOT_FILES ?= " \
${KERNEL_IMAGETYPE} \
${@make_dtb_boot_files(d)} \
"
WKS_FILE_DEPENDS ?= " \
virtual/bootloader \
\
e2fsprogs-native \
bmap-tools-native \
"
WKS_FILE_DEPENDS_append_mx8 = " imx-boot "
SOC_DEFAULT_WKS_FILE ?= "imx-uboot-bootpart.wks.in"
WKS_FILE ?= "${SOC_DEFAULT_WKS_FILE}"
# Certain machines override the default fsl u-boot with the
# fslc u-boot. To restore the fsl u-boot, add use-fsl-bsp like this:
# MACHINEOVERRIDES_prepend_imx6ulevk = "use-fsl-bsp:"
UBOOT_MAKE_TARGET_use-fsl-bsp_mx6 = "u-boot.imx"
UBOOT_SUFFIX_use-fsl-bsp_mx6 = "imx"
SPL_BINARY_use-fsl-bsp_mx6 = ""
WKS_FILE_use-fsl-bsp_mx6 = "imx-uboot-bootpart.wks.in"
SERIAL_CONSOLES = "115200;ttymxc0"
SERIAL_CONSOLES_mxs = "115200;ttyAMA0"
KERNEL_IMAGETYPE = "zImage"
KERNEL_IMAGETYPE_aarch64 = "Image"
MACHINE_FEATURES = "usbgadget usbhost vfat alsa touchscreen"
# Add the ability to specify _imx machines
MACHINEOVERRIDES =. "imx:"
内核设备树定义文件
:在imx6ull-bird-dk.conf文件中,通过变量KERNEL_DEVICETREE定义了Linux内核在编译过程中生成的设备树文件。当需要修改Linux内核在编译过程中生成的设备树文件时,除了需要提供相对于的.dtb文件外,还需要修改KERNEL_DEVICETREE变量值。
U-BOOT的配置
:在imx6ull-bird-dk.conf文件中,通过配置UBOOT_CONFIG变量,定义了U-Boot在编译过程中所使用的配置文件。
在imx6ull14x14evk.conf配置文件中,官方支持了optee的功能,关于optee功能的配置,需要修改/sources/meta-freescale/recipes-security/optee-imx路径下的optee-os_3.2.0.imx.bb文件,在目前我们的应用中,暂时用不到optee功能,因此先将其屏蔽,不参与嵌入式Linux系统镜像文件的构建过程,屏蔽optee之后的imx6ull-bird-dk.conf文件如下: 关于imx6ull-bird-dk.conf文件内容修改在后面U-Boot移植、Linux Kernel移植过程中会详细描述。
distro定义了嵌入式Linux发行版的功能等特性。同样的,我们在官方提供的fsl-imx-fb版本上进行修改。将/sources/meta-imx/meta-sdk/conf/distro下的fsl-imx-fb.conf文件拷贝至/sources/meta-bird-imx6ull/conf/distro/路径下,并将其重命名为bird-imx-fb.conf,并按照下图所示修改:
在bird-imx-fb.conf文件中,通过include conf/distro/include/fsl-imx-base.inc以及include conf/distro/include/fsl-imx-preferred-env.inc包含了fsl-imx-base.inc和fsl-imx-preferred-env.inc
两个文件,这两个文件比较重要,定义了对应linux发行版的相关配置。
将/sources/meta-imx/meta-sdk/conf/distro/include/路径下的fsl-imx-base.inc和fsl-imx-preferred-env.inc
两个文件拷贝至/sources/meta-bird-imx6ull/conf/distro/include/路径下,并分别将其重命名为:bird-imx-base.inc和bird-imx-preferred-env.inc
。
同时将bird-imx-fb.conf文件中的include conf/distro/include/fsl-imx-base.inc
修改为include conf/distro/include/bird-imx-base.inc
;将include conf/distro/include/fsl-imx-preferred-env.inc
修改为include conf/distro/include/bird-imx-preferred-env.inc
。
machine和distro分别定义了定制化嵌入式Linux系统的硬件和发行版特征,除此之外,构建的系统中所需要的软件包、软件源码等还需要在recipes中添加。该小节以recipes-test为例,创建一个recipe,用以描述recipe的过程。后续在实际使用过程中,将根据需求,创建不同的recipe,以实现增减第三方软件包或自己开发的软件,用来构建最终的嵌入式Linux系统。
在/sources/meta-bird-imx6ull路径下,创建文件夹recipes-test,recipes-test文件夹中将用于存放需要使用到的软件包(实际上是一些.bb、.bbappend等文件)。创建文件夹recipes-test后,在/sources/meta-bird-imx6ull/recipes-test路径下创建文件夹test,并在test文件夹中创建printfhello.bb文件。在printfhello.bb文件中,输入以下信息:
# Copyright (C) 2020-2036 XXXX Semiconductor
DESCRPITION = "Prints Hello World"
LICENSE = "GPLv2+"
LIC_FILES_CHKSUM = "file://Licenses/README;md5=a2c678cfd4a4d97135585cad908541c6"
PN = "printfhello"
PV = "1"
addtask TestFun
python do_TestFun(){
bb.plain("********************");
bb.plain("* *");
bb.plain("* Hello, World! *");
bb.plain("* *");
bb.plain("********************");
}
在printfhello.bb文件中,提供了recipe的描述,包括:名字、版本,并且重写了do_TestFun任务。在构建过程中,当执行了recipes-test中的printfhello.bb文件时,将会通过执行重写的do_TestFun任务,输出一些打印信息。 至此,创建Metadata基本完成,后面章节将对创建的Metadata进行验证。需要特别注意的是,创建的Metadata整体文件架构有严格的要求,须按照下图所示的文件架构进行创建:
新创建的Metadata需要在imx-setup-release.sh中将其使能,才能参与到最终的嵌入式Linux发行版的构建。在imx-setup-release.sh脚本中,增加meta-bird-imx6ull即可,如下图所示:
在前面小节中,我们创建了以MACHINE=imx6ull-bird-dk,DISTRO=bird-imx-fb为例的Metadata。创建Metadata后,需要对新创建的Metadata进行测试,确定新创建的Metadata是否符合要求。
在使用imx-setup-release.sh脚本初始化Yocto构建目录时,imx-setup-release.sh脚本通过调用setup-environment脚本,查找当前支持的machine。因此在/fsl-release-yocto路径下,输入 ./setup-environment -h命令,查看setup-environment脚本帮助信息,该信息列出了Yocto路径下支持的MACHINE。可以看到新增加的machine imx6ull-bird-dk,如下图所示:
在/fsl-release-yocto下,运行imx-setup-release.sh脚本。该脚本用于初始化Yocto构建目录,命令如下:DISTRO=bird-imx-fb MACHINE=imx6ull-bird-dk source imx-setup-release.sh -b build
,运行该脚本后,将会根据bird-imx-fb和imx6ull-birk-dk
找到对用的bird-imx-fb.conf和imx6ull-bird-dk.conf
。如下图所示:
查看/fsl-release-yocto/build/conf下的bblayers.conf文件,将看到新增加的bbLAYERS,如下图所示:
查看/fsl-release-yocto/build/conf下的local.conf文件,将看到新增加的machine和distro,如下图所示:
运行imx-setup-release.sh脚本后,会自动生成一个build文件夹,并自动进入该文件夹。进入build路径下,运行bitbake命令:bitbake imx-image-multimedia
,至此由于我们之前新创建的machine(imx6ull-bird-dk.conf)和distro(bird-imx-fb.conf)
都是直接拷贝Freescale官方提供的imx6ull14x14evk.conf和fsl-imx-fb.con
f文件,所以将构建出和官方一致的嵌入式Linux发行版。后面将分别对imx6ull-bird-dk.conf、bird-imx-fb.conf以及recipe中的.bb等文件进行修改,真正的构建一个完整的定制化的嵌入式Linux系统。同时在/fsl-release-yocto/build/tmp/deploy/images/imx6ull-bird-dk路径下,可以看到生成了相应的image文件:
此外,我们还需要验证新增加的recipe是否正确。在新增加的recipe中,打印出了相关的测试信息,因此,可以通过该测试信息是否正确打印来确定新增加的recipe是否正确。在/fsl-release-yocto/build路径下,使用如下命令:bitbake printfhello -c TestFun。即可调用recipe printfhello中的TestFun函数,输出如下信息:
在使用bitbake imx-image-multimedia命令开始构建系统时,可以看到将会先通过网络连接至bitbake服务器做一些验证准备工作,同时,在Bitbake构建系统过程中,会根据.bb文件中定义的资源路径下载相关的源码,进行系统构建。通常来说,构建嵌入式Linux系统是一个不断修改不断迭代的过程,要是每次构建系统都重新连接bitbake服务器、下载一些相关源码,对于开发效率来说影响很大,特别是网络条件不好时。
因此当通过bitbake imx-image-multimedia命令完成一次系统构建后,构建系统所需要的软件源码等都已经下载至本地的/Yocto/fsl-yocto-release/downloads路径下,也就是说所有参与构建嵌入式系统所需的资源都已经下载至了本地,我们要做的只是在对本地资源进行修改的情况下,可以采用离线构建系统的方式,具体来说通过修改imx-setup-release.sh文件,设置BB_NO_NETWORK变量为1即可,如下所示:
一个完整的嵌入式Linux发行版包括U-Boot
、Linux Kernel
、Device Tree(Linux Kernel编译时相应的Device Tree也会编译出来)
以及Rootfs
。Linux系统的启动,需要一个BootLoader程序。U-Boot就是BootLoader的一种。通常来说,CPU芯片上电以后先运行一段BootLoader程序。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND,NOR FLASH, SD, MMC 等)
拷贝到 DDR 中,最后启动Linux内核。 一般来说对于U-Boot的移植,主要会涉及到:DDR初始化,以太网功能。
U-Boot是一个遵循GPL协议的开源软件,官方提供了针对不同厂家CPU不同版本的U-Boot。各个CPU厂家从U-Boot官方下载某一特定版本的U-Boot,CPU厂商(如NXP)根据自己的CPU芯片基于该版本维护一个版本的U-Boot
。然后基于各厂商CPU的开发板或自己设计的板卡,需要根据CPU厂商维护的U-Boot做相应的修改,以适应自己的板卡。具体关系如下:
在实际项目中,我们通常会参考半导体厂商针对所使用CPU的评估板进行相关的修改(硬件/软件)制作自己产品所使用的硬件平台。因此对于U-Boot,大多数情况下是在基于半导体厂商维护的U-Boot代码,进行相应的调整(适配),使其能够在产品使用的硬件平台上正确的运行。
对于imx6ull,教程中采用的是NXP官方维护的U-Boot版本是imx_v2020.04_5.4.47_2.2.0,所以我们将在imx_v2020.04_5.4.47_2.2.0版本上进行修改。其下载地址为git://source.codeaurora.org/external/imx/uboot-imx.git,分支为imx_v2020.04_5.4.47_2.2.0。
U-Boot的最主要目的是启动Linux内核
,但除此之外,还可以集成一些其他基础功能,目前的U-Boot已经支持液晶屏、网络、 USB 等高级功能。 就像PC上的BIOS一样,可以直接进入BIOS进行一些配置操作。因此U-Boot中也会涉及到一些外设驱动,这也就是U-Boot移植过程中需要涉及到的工作。
在U-Boot移植(硬件适配)过程中,需要修改相应的U-Boot源码,同样我们不会直接在Yocto中提供的recipe中直接修改,而是在我们新创建的metadata中创建新的recipe的方式来对U-Boot软件编译过程进行配置。
U-Boot的配置属于distro中的内容。在/sources/meta-bird-imx6ull/conf/distro路径下的bird-imx-fb.conf中,通过include conf/distro/include/bird-imx-preferred-env.inc的方式,引用了bird-imx-preferred-env.inc文件,在该文件中,通过PREFERRED_PROVIDER_virtual/bootloader_imx = "u-boot-imx"变量定义了U-Boot的provider。
可以看出imx6ull的provider是u-boot-imx,实际上对应的是/sources/meta-imx/meta-bsp/recipes-bsp/u-boot/路径下的u-boot-imx_2020.04.bb文件。因此创建如下路径:/fsl-release-yocto/sources/meta-bird-imx6ull/recipes-bsp/u-boot/
,并将/sources/meta-imx/meta-bsp/recipes-bsp/u-boot/路径下的u-boot-imx_2020.04.bb文件及该路径下的其他文件拷贝至/fsl-release-yocto/sources/meta-bird-imx6ull/recipes-bsp/u-boot/
路径下,将其重命名为:u-boot-bird_2020.04.bb。
同时将/sources/meta-bird-imx6ull/conf/distro/include/路径下的bird-imx-preferred-env.inc中的PREFERRED_PROVIDER_virtual/bootloader_imx = "u-boot-imx"修改为PREFERRED_PROVIDER_virtual/bootloader_imx = “u-boot-bird”,修改后的bird-imx-preferred-env.inc如下:
修改后用命令bitbake imx-image-multimedia重新编译,可以看到如下编译过程:
如下两个文件是可直接下载到开发板上运行的文件:
对于U-Boot的移植或者说是硬件平台的适配,更多的是需要修改U-Boot源码(相关驱动代码:如EMMC、SD、网口、LCD等),使其能工作于我们自己设计的硬件平台。理论上来说,不同的硬件平台所对应的相关驱动是不一样的,这也导致了不同的硬件平台所使用的U-Boot也是不一样的。
但是实际过程中,往往在设计硬件平台的时候会参考NXP官方提供的EVK开发板,同时,对于一个CPU,所使用的硬件外设接口相差不大,因此,我们可以在基于官方平台提供的U-Boot版本上做相应的修改即可得到适合自己设计硬件平台的U-Boot。
同样的,在修改U-Boot源码之前,我们需要将从NXP官方下载的U-Boot源码放在本地,并且将OpenEmbedded编译所使用的U-Boot软件包源码指向我们本地存放的U-Boot,这样,就可以实现只更改本地存储的U-Boot代码,而不至于影响到其他项目。将从NXP官网下载的imx_v2020.04_5.4.47_2.2.0版本解压至/Linux/fsl-release-yocto/bird-imx-uboot路径下,如下图所示:
uboot源码已经下载到本地,在构建的路径下进行相应编译。
将U-Boot源码存放在/Linux/fsl-release-yocto/bird-imx-uboot路径之后,同样的,在本地采用Git管理U-Boot源码,同时,修改/fsl-release-yocto/sources/meta-bird-imx6ull/recipes-bsp/u-boot/u-boot-bird_2020.04.bb文件,将其中的SRC_URI指向本地存放U-Boot的路径。
LICENSE = "GPLv2+"
LIC_FILES_CHKSUM = "file://Licenses/gpl-2.0.txt;md5=b234ee4d69f5fce4486a80fdaf4a4263"
SRCBRANCH = "master"
UBOOT_SRC ?= "git:${BSPDIR}/bird-imx-uboot;protocol=file"
SRC_URI = "${UBOOT_SRC};branch=${SRCBRANCH}"
SRCREV = "${AUTOREV}"
#LICENSE = "GPLv2+"
#LIC_FILES_CHKSUM = "file://Licenses/gpl-2.0.txt;md5=b234ee4d69f5fce4486a80fdaf4a4263"
#NXP_REPO_MIRROR ?= "nxp/"
#SRCBRANCH = "${NXP_REPO_MIRROR}imx_v2016.03_4.1.15_2.0.0_ga"
#UBOOT_SRC ?= "git://source.codeaurora.org/external/imx/uboot-imx.git;protocol=https"
#SRC_URI = "${UBOOT_SRC};branch=${SRCBRANCH}"
#SRCREV = "a57b13b942d59719e3621179e98bd8a0ab235088"
其中,LIC_FILES_CHKSUM的md5值和SRCREV的值需要根据实际情况修改,LIC_FILES_CHKSUM的md5值在编译过程中会自动计算,如果出现LIC_FILES_CHKSUM的md5值不匹配的错误,根据错误信息中提供的新的md5值修改LIC_FILES_CHKSUM的md5值即可。
SRCREV的值指定了所使用代码分支下的版本,可以通过bird-imx-uboot下使用git log查看(commit id),也可以将SRCREV设置为SRCREV="${AUTOREV}"使用代码分支下的最新版本。
u-boot-bird_2020.04.bb文件用于配置在bird-imx-fb发行版中u-boot的配置。在u-boot-bird_2020.04.bb文件中,通过require u-boot-common.inc引用了u-boot-common.inc文件,在u-boot-common.inc文件中,定义了u-boot的获取地址等,但是在实际编译过程中,会在u-boot-bird_2020.04.bb文件中对u-boot获取的地址及版本号对应的变量UBOOT_SRC、SRCBRANCH重新赋值,因此,u-boot-common.inc文件中的内容,保持原样即可。
同样的在u-boot-bird_2020.04.bb文件中,同样通过require recipes-bsp/u-boot/u-boot.inc引用了u-boot.inc文件,该文件实际上对应的是/sources/poky/meta/recipes-bsp/u-boot路径下的u-boot.inc文件,在u-boot.inc文件中定义了些与u-boot编译相关的变量值,我们不需要修改,保持原样即可。
如下之前编译过了,直接用source。
通过修改U-Boot recipe,将OpenEmbedded构建系统使用的U-Boot源码指向了本地U-Boot存放地址,因此编译过程中将编译本地存放的U-Boot源码。在实际工程应用中,需要修改U-Boot源码中的相关配置或驱动代码,使其能在相对应的硬件平台上正常运行。往往这是一个反复迭代、需要多次修改编译的过程。
采用如下两种方式都可以进行编译:编译整个系统:bitbake imx-image-multimedia
单独编译U-Boot:bitbake -c compile -f u-boot-bird
部署编译生成的U-Boot镜像:bitbake -c deploy -f u-boot-bird
U-Boot是一个大型复杂的裸机程序。U-Boot的编译,主要是使用gcc交叉编译工具,将U-Boot源码编译为可以在ARM芯片上运行的可执行文件(u-boot-imx.bin、u-boot-imx.imx等文件)。其功能实现和详细的编译过程是相对复杂的过程,但是对于大多数应用场景而言,并不需要我们很复杂的修改U-Boot源码,及掌握U-Boot源码编译的详细过程,我们需要的只是知道U-Boot的工作大体流程及编译过程,目的是为我们后面修改U-Boot的基础配置以及修改U-Boot中涉及到的驱动(ETH【gpio口,单双网口】、SD、Nand、EMMC等)代码而已,因此,在教程中,只会涉及到U-Boot的基本框架及编译过程,不会很深入的研究整个U-Boot。
对于Yocto,U-Boot的编译过程可以分为两部分:U-Boot recipe编译及U-Boot源码编译。
OpenEmbedded构建嵌入式Linux系统时,会根据U-Boot所对应的recipe文件(如u-boot-bird_2020.04.bb)中定义的配置项进行U-Boot的编译。使用单独编译U-Boot命令编译U-Boot recipe,可以看到编译过程如下:
编译过程中,OpenEmbedded先是构建出编译U-Boot源码需要使用的gcc交叉编译工具,最后再编译u-boot-bird_2020.04.bb。该小节主要描述u-boot-bird_2020.04.bb的编译过程。
1.u-boot-bird_2020.04.bb
:定义了一些全局变量,OpenEmbedded使用这些全局变量编译U-Boot。其中比较重要的几个变量值:SRCBRANCH、UBOOT_SRC、SRC_URI、SRCREV定义了获取U-Boot源码的地址;LICENSE、LIC_FILES_CHKSUM定义了License相关信息。同时,在u-boot-bird_2020.04.bb文件一开始,通过require recipes-bsp/u-boot/u-boot-bird.inc文件,u-boot-bird.inc是一个比较重要的文件,u-boot-bird.inc文件中定义了一些与U-Boot编译相关的信息。
2.u-boot-bird.inc
:u-boot-bird_2020.04.bb通过require关键字引用了u-boot-bird.inc文件,在u-boot-bird.inc文件中,定义的全局变量及重构了一些构建方法同样对于OpenEmbedded编译U-Boot有效。
全局变量:
SRCBRANCH = "master"
UBOOT_SRC、SRC_URI、SRCREV:U-Boot源码存放地址。
UBOOT_SUFFIX、UBOOT_IMAGE、UBOOT_BINARY:U-Boot生成文件格式定义。
UBOOT_MAKE_TARGET:U-Boot编译target,在后面U-Boot的makefile编译中使用该变量值。
UBOOT_ELF ?= ""
UBOOT_ELF_SUFFIX、UBOOT_ELF_IMAGE、UBOOT_ELF_BINARY、UBOOT_ELF_SYMLINK:U-Boot输出elf格式文件定义。
重构方法: do_compile():OpenEmbedded在编译U-Boot时,会通过do_compile task调用do_compile()编译U-Boot。在u-boot-bird_2020.04.bb文件中,重写了do_compile(),如下:
do_compile () {
if [ "${@bb.utils.contains('DISTRO_FEATURES', 'ld-is-gold', 'ld-is-gold', '', d)}" = "ld-is-gold" ] ; then
sed -i 's/$(CROSS_COMPILE)ld$/$(CROSS_COMPILE)ld.bfd/g' config.mk
fi
unset LDFLAGS
unset CFLAGS
unset CPPFLAGS
if [ ! -e ${B}/.scmversion -a ! -e ${S}/.scmversion ]
then
echo ${UBOOT_LOCALVERSION} > ${B}/.scmversion
echo ${UBOOT_LOCALVERSION} > ${S}/.scmversion
fi
if [ "x${UBOOT_CONFIG}" != "x" ]
then
for config in ${UBOOT_MACHINE}; do
i=`expr $i + 1`;
for type in ${UBOOT_CONFIG}; do
j=`expr $j + 1`;
if [ $j -eq $i ]
then
oe_runmake O=${config} ${config}
oe_runmake O=${config} ${UBOOT_MAKE_TARGET}
cp ${S}/${config}/${UBOOT_BINARY} ${S}/${config}/u-boot-${type}.${UBOOT_SUFFIX}
fi
done
unset j
done
unset i
else
oe_runmake ${UBOOT_MACHINE}
oe_runmake ${UBOOT_MAKE_TARGET}
fi
}
其中,do_compile()中第18~25行,依次取出UBOOT_CONFIG变量所对应文件中的配置,通过oe_runmake 命令编译U-Boot源码文件。UBOOT_CONFIG变量在/fsl-release-yocto/sources/meta-bird-imx6ull/conf/machine路径下的imx6ull-bird-dk.conf文件中定义,如下所示:
UBOOT_CONFIG ??= "sd"
UBOOT_CONFIG[sd] = "mx6ull_14x14_evk_config,sdcard"
UBOOT_CONFIG[emmc] = "mx6ull_14x14_evk_emmc_config,sdcard"
UBOOT_CONFIG[nand] = "mx6ull_14x14_evk_nand_config,ubifs"
UBOOT_CONFIG[qspi1] = "mx6ull_14x14_evk_qspi1_config"
UBOOT_CONFIG[mfgtool] = "mx6ull_14x14_evk_config"
可以看出,目前使用的是sd卡启动方式,使用的是mx6ull_14x14_evk_config配置文件。因此,相当于在do_compile()函数中,使用了如下命令编译U-Boot源码:make mx6ull_14x14_evk_config,make all
将使用U-Boot源码路径下的makefile,通过gcc交叉编译器arm-poky-linux-gnueabi-gcc编译U-Boot源码,生成目标文件。
在OpenEmbedded编译U-Boot recipe文件u-boot-bird_2020.04.bb的过程中,最终会调用类似:make mx6ull_14x14_evk_config以及make all的命令,使用U-Boot顶层makefile(U-Boot源码路径下的makefile文件)编译U-Boot源码生成所需要的目标文件。
1.make mx6ull_14x14_evk_config
:
该命令将会通过调用U-Boot顶层makefile,按照mx6ull_14x14_evk_config文件中的配置项对U-Boot功能进行配置,并且在U-Boot源码编译工作路径(/fsl-release-yocto/build/tmp/work/imx6ull_bird_dk-poky-linux-gnueabi/u-boot-bird/2016.03-r0/git/mx6ull_14x14_evk_config)下生成.config文件,如下图所示:
在.config文件中,定义了U-Boot功能状态(开启/关闭),在编译U-Boot源码时,将根据.config中相关功能状态,编译相对应的U-Boot软件功能。对于.config文件的配置,除了来自make mx6ull_14x14_evk_config命令中指定的mx6ull_14x14_evk_config文件外,还可以通过menuconfig工具进行配置。关于menuconfig工具配置.config的过程,在后续章节中会进行描述。
2.make all
:
该命令通过调用U-Boot顶层makefile,使用gcc交叉编译器arm-poky-linux-gnueabi-gcc编译U-Boot源码,生成u-boot.bin和u-boot.imx文件,同时,可以通过bitbake -c deploy -f u-boot-bird命令将生成的u-boot.bin文件等安装(“复制”)至安装路径下,如:/fsl-release-yocto/build/tmp/deploy/images/imx6ull-bird-dk,如下图所示:
在/fsl-release-yocto/build/tmp/work/imx6ull_bird_dk-poky-linux-gnueabi/u-boot-bird/2016.03-r0/git/mx6ull_14x14_evk_config路径下也会生成相应的目标文件: u-boot.bin,u-boot-sd.imx
U-Boot实际上是一个裸机程序,在U-Boot的调试测试中,将生成的u-boot.bin文件烧写到SD卡中,设置imx6ull从SD卡启动(设置引脚),当imx6ull上电后,芯片内部的boot rom程序将SD卡中的u-boot.imx文件拷贝到链接地址处,就可以开始运行U-Boot了。但是从u-boot.bin转换为u-boot.imx,并且正确的烧录至SD卡,还需要相应的转换。正点原子提供了imxdownload软件,用于将编译出来的.bin文件烧写到SD卡中。因此,教程中采用正点原子的imxdownload软件烧写的方式进行U-Boot的调试。 imxdownload软件只能在Ubuntu下使用,使用步骤如下:
1.
Ubuntu下创建一个目录,专门用于.bin文件的烧写,如:/Linux/download。将imxdownload软件拷贝至该路径下,并赋予其可执行权限。
2.
将需要烧录的.bin文件拷贝至该路径下,例如:u-boot.bin。(需要烧写的bin文件需要与imxdownload软件在同一路径下)。
3.
插入SD卡,其连接到Ubuntu,在Ubuntu中,使用ls /dev/sd*确定插入的SD卡设备。例如:sdc。
4.
使用imxdownload向SD卡烧写bin文件,命令格式如下:./imxdownload u-boot.bin /dev/sdb
5.
烧写完成后,将SD卡插入嵌入式Linux板卡,配置从SD卡启动的方式,断电复位板卡即可。
从嵌入式Linux硬件板卡串口输出上电信息,可以看出,新的u-boot编译时间与实际修改U-Boot后编译的时间一致,因此,可以确定实现了通过新建U-Boot recipe的方式,实现了Freescale官方提供的基于mx6ull_evk板卡设置的U-Boot编译过程,后续需要做的,就是修改U-Boot源码或相应的配置文件,编译生成适合于定义的嵌入式Linux硬件平台的U-Boot。
U-Boot启动后,会输出一些信息,这些信息如下所示:第一行
:输出U-Boot的版本号、U-Boot源码版本控制信息(master+gad23b9f4)和编译时间。
第二行
:输出CPU信息,包括CPU型号(IMX6uLL)、版本号(1.0)、主频(528MHz)以及当前运行频率(396MHz)。
第三行
:输出CPU工作温度范围及当前CPU温度。
第四行
:是复位原因,当前复位原因是POR,表示是通过拉低imx6ull芯片上的POR_B引脚复位系统。
第五行
:是板子名字,当前板子名字为MX6ULL 14x14 EVK。
第六行
:提示DRAM大小。
第七行
:表示当前有两个MMC/SD卡控制器:FSL_SDHC(0)和 FSL_SDHC(1)。对于教程使用的EMMC 核心板上 FSL_SDHC(0)接的 SD(TF)卡,FSL_SDHC(1)接的 EMMC。