yocto---学习2-bitbake
作者:互联网
1.yocto项目的厨师——bitbake
bitbake是OpenEmbedded构建系统的引擎,通过解析一系列配置文件(主要为recipes,即bb/bbappend文件)来创建任务列表,并根据依赖关系依次执行。通过bitbake -c listtasks xxx(模块名或映像名)命令可以查看编译一个模块或整个映像所需任务名称。编译一个模块/映像的主要执行过程如下(内核除外):
下面按四个阶段来讲解bitbake的执行过程及涉及的变量,其中第四阶段(上图标黄的两任务)不是编译每个模块都有的。
2.源码获取及处理
这个阶段包含三个任务,分别为do_fetch、do_unpack、do_patch。
原文件来源
yocto编译一个模块所需的源代码或开源组件从哪里获取?
如上图所示,源码可以从上游开源项目(如busybox-1.28.3.tar.bz2)、本地项目(本地源代码)、软件配置管理(如git)中获取。
do_fetch任务:根据配置文件中SRC_URI变量所指定的方式获取源代码。
do_unpack任务:如果源文件需要解压,则该任务会将源码包解压到指定目录下。
do_patch任务:如果对开源项目进行了修改,则这个任务可以为解压后的源码打补丁,比如对linux开源内核源码进行了修改。
这个大阶段涉及的配置变量有以下:
SRC_URI
源文件列表变量,位于配方(recipe)文件中。每个recipe必须有一个指向源的SRC_URI变量。
SRC_URI = "git://github.com/openbmc/linux;protocol=git;branch=${KBRANCH}" #表示从github上下载linux内核源码
SRC_URI += "file://defconfig" #表示从本地目录获取内核默认配置,目录的路径由FILESPATH变量指定
以下列举常用的获取方式,更多的获取方式请参阅SRC_URI。
file://-从本地机器 获取文件,通常是元数据附带的文件(例如补丁、内核配置、uboot配置文件),路径是相对于FILESPATH变量的。构建系统默认在配方同目录下名为“${BP}”、"${BPN}"、"files"的目录下查找指定文件,如需增加额外路径,便通过FILESPATH和FILESEXTRAPATHS指定。
注意:如果源码时本地文件,确保每个文件都使用file://写出,而不是使用指定文件夹方式下载整个文件夹,因为yocto需要单独检查每个文件是否被修改。
bzr://-从 Bazaar 版本控制存储库中获取文件。
git://-从 Git 版本控制存储库中获取文件。
如果是从本地仓库下载,则先配置好本地Git仓库。yocto依赖与git的版本控制,简单来说就是yocto每次编译时候,会去检查软件包的源文件是否修改,只有修改过才会让软件包重新编译,那么对于git仓库就是对比上一次与当次版本差异。所以,对于源码在本地的git仓库的软件包,需要在每次编译前进行以下操作:
git add ./*
git commit -m "test"
这样就可以确保本地git仓库源码修改后能参与yocto工程编译。
svn://-从 Subversion (svn) 版本控制存储库中获取文件。
http://-使用http。
https://-使用https。
DL_DIR
用于指定开源组件包(tar、git等)下载的存放路径,位于编译目标层的conf/local.conf.sample文件中(如有需要可在此文件中修改),这个文件将被解析到build/conf/local.conf文件中,默认情况下该变量指定的目录为build/downloads/,如果多用户在一台编译机器上使用,可以指定一个公共目录,避免重复下载,比如DL_DIR ?= "/opt/downloads",同时修改chmod 777 /opt/downloads即可。
通常一个组件包下载完毕后,在存放目录下会生成一个包名加".done"的文件表示该包下载完成,比如:
root:~/work/open_source/openbmc/build/downloads$ ls busybox-1.32.0.tar.bz2* -l
-rw-r--r-- 1 root root 2439463 Jun 27 2020 busybox-1.32.0.tar.bz2
-rw-r--r-- 1 root root 463 Mar 7 2021 busybox-1.32.0.tar.bz2.done
一个技巧就是某个开源组件一直下载失败,那就从其他地方下载同版本组件拷贝到存放目录下,并复制一个*.done文件改为对应名字即可。
FILESPATH
构建系统搜索本地文件(本地源码、补丁、配置文件等)的目录集合,位于配方(recipe)文件中。在构建过程中,bitbake查找SRC_URI变量的file://语句指定的本地文件时,会依次搜索FILESPATH变量指定的目录集合,该变量的默认值在meta/classes/base.bbclass中定义:
FILESPATH = "${@base_set_filespath(["${FILE_DIRNAME}/${BP}", \
"${FILE_DIRNAME}/${BPN}", "${FILE_DIRNAME}/files"], d)}"
一个简单的示例如下。
SRC_URI += "file://defconfig" #只是将配置文件拷贝到${WORKDIR}目录下
SRC_URI += "file://patch/0001-XXX.patch" #将补丁文件拷贝到${WORKDIR}目录下,并将补丁应用到${S}目录
SRC_URI += "file://patch/0002-XXX.diff" #将补丁文件拷贝到${WORKDIR}目录下,并将补丁应用到${S}目录
SRC_URI += "file://patch/0003-XXX.patch;apply=yes" #将补丁文件拷贝到${WORKDIR}目录下,并将补丁应用到${S}目录,这是显示指定应用补丁
SRC_URI += "file://patch/0004-XXX.patch;apply=no" #将补丁文件拷贝到${WORKDIR}目录下,但不应用补丁
默认情况,构建系统会将file://指定带".diff"或".patch"的补丁文件应用到${S}目录,如果不想使用这个补丁,可以显示指定不应用。
注意:很多时候我们会在配方文件(.bb)中看见如下类似代码。
FILESPATH := "${THISDIR}/../../sources/${PN}:"
这种强制更改FILESPATH变量默认值的方法是不正确的,正确做法是采用FILESEXTRAPATHS变量来扩展搜索目录,比如下面做法:
FILESEXTRAPATHS_prepend := " ${THISDIR}/../../sources/XXX:${THISDIR}/../../sources/YYY:" #同时扩展2个路径
FILESEXTRAPATHS_append := " ${THISDIR}/../EEE:" #尾部的分号必须存在
额外说明一下,在.bbappend文件中只能使用FILESEXTRAPATHS变量。关于"_prepend"和"_append"操作符说明将在后续讲解。
THISDIR
bb或bbappend文件所在目录,位于配方(recipe)文件中。比如某个配方文件位于如下路径:
/work/open_source/openbmc/meta-aspeed/recipes-kernel/linux/linux-aspeed_git.bb
那么在linux-aspeed_%.bbappend配方文件中的${THISDIR}变量值为也包含/work/open_source/openbmc/meta-aspeed/recipes-kernel/linux/。
注意,${THISDIR}变量值是配方文件所在目录,也就是说在bbappend文件中使用${THISDIR}变量,即包含bb文件所在目录,也包含bbappend文件所在目录,比如上面和下面两个目录都包含。
/work/open_source/openbmc/meta-ibm/meta-romulus/recipes-kernel/linux/linux-aspeed_%.bbappend
TMPDIR
此变量是 OpenEmbedded 构建系统用于所有构建输出和中间文件(共享状态缓存除外)的基本目录,位于编译目标层的conf/local.conf.sample文件中(如有需要可在此文件中修改),这个文件将被解析到build/conf/local.conf文件中,默认情况下该变量指定的目录为build/tmp/。
PACKAGE_ARCH
包架构名,位于配方(recipe)文件中(一般不会在配方中自己指定)。查看示例:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^PACKAGE_ARCH
PACKAGE_ARCH="4u_x201"
PACKAGE_ARCHS="all any noarch arm armv4 armv4t armv5 armv5t armv5e armv5te armv6 armv6t 4u_x201"
其中obmc-phosphor-image为映像名(可使用包名),最终该映像就会生成于build\tmp\deploy\images\4u-x201目录中。
TARGET_OS
指定目标的操作系统。对于基于 glibc 的系统(GNU C 库),该变量可以设置为“linux”,对于 musl libc 可以设置为“linux-musl”。对于 ARM/EABI 目标,存在“linux-gnueabi”和“linux-musleabi”可能的值。查看示例:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^TARGET_OS
TARGET_OS="linux-gnueabi"
PN
用于构建包的配方名称或包的名称,该变量位于配方文件中(如有需要可在此文件中修改,一般会自动捕获配方名称)。例如,如果配方名为 expat_2.0.1.bb,则PN默认值为“expat”。这里需要注意一下,包名或配方名称中不能使用下划线_,在yocto下划线为版本分隔符。查看示例:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^PN
PN="obmc-phosphor-image"
PV
配方版本,该变量位于配方文件中(如有需要可在此文件中修改,一般会自动捕获配方版本)。例如,如果配方名为 expat_2.0.1.bb,则 PV 的默认值将为“2.0.1”。查看示例:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^PV
PV="1.0"
PR
配方的修订版本,该变量位于配方文件中(如有需要可在此文件中修改,一般需要手动指定)。此变量的默认值为“r0”,配方的后续修订通常具有值“r1”、“r2”等。当PV增加时,PR通常重置为“r0”。查看示例:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^PR
PR="r0"
BP
该变量的值基本配方名称和版本,但没有任何特殊配方名称后缀(即 -native、lib64- 等)。 BP 由组成为${BPN}-${PV},其查看示例为:
~/work/bmc/build$ bitbake -e obmc-phosphor-image | grep ^BP
BP="obmc-phosphor-image-1.0"
WORKDIR
OpenEmbedded 构建系统在其中构建配方的工作目录的路径名。该目录位于TMPDIR目录下,实际路径基于正在构建的配方和正在构建的系统,默认定义如下:
${TMPDIR}/work/${MULTIMACH_TARGET_SYS}/${PN}/${EXTENDPE}${PV}-${PR}
TMPDIR: 顶层构建输出目录
MULTIMACH_TARGET_SYS: 目标系统标识符,默认值为${PACKAGE_ARCH}${TARGET_VENDOR}-${TARGET_OS},示例值为4u_x201-openbmc-linux-gnueabi或armv6-openbmc-linux-gnueabi,详细请参阅https://www.yoctoproject.org/docs/2.7/ref-manual/ref-manual.html#var-MULTIMACH_TARGET_SYS
PN: 配方名称
EXTENDPE: 扩展前缀 ,如果PE未指定,EXTENDPE`则为空白,大多数食谱通常都是这种情况
PV: 配方版本
PR: 配方修改
BPN
用于构建包的配方名称,它是PN变量的变种,去掉了常用的前缀和后缀,比如nativesdk-、-cross、-native,以及multilib的lib64-和lib32-。
~/work/byobmc/build$ bitbake -e obmc-phosphor-image | grep ^BPN
BPN="obmc-phosphor-image"
解压后的配方源代码所在路径,该变量位于配方文件中(如有需要可在此文件中修改)。默认情况下,此目录为${WORKDIR}/${BPN}-${PV},如果源压缩包将代码提取到名为 ${BPN}-${PV} 以外的任何目录,或者如果源代码是从 SCM(例如 Git 或 Subversion)获取的,则必须在配方中设置 S,以便OpenEmbedded 构建系统知道在哪里可以找到解压的源代码。
假设bb文件中指定源码来源于git,则在 do_fetch 期间,源码将被被克隆到 ${WORKDIR}/git目录中。由于此路径与S的默认值不同,所以必须专门设置,才能定位到源:
SRC_URI = "git://path/to/repo.git"
S = "${WORKDIR}/git"
总结:源码获取及处理阶段就是根据${SRC_URI}变量指定方式来获取源码存放到${WORKDIR}路径,若是压缩包则解压到S路径下,若有补丁文件则应用到S目录。
3.源码配置、源码编译及成果物安装
源代码打好补丁后,bitbake 执行配置和编译源代码的任务。编译完成后,成果物文件将复制到保存区域(暂存)以准备打包:
这个阶段主要包含四个任务,分别为do_prepare_recipe_sysroot、do_configure、do_compile和do_install。
是不是很好奇,突然跑出一个奇怪任务do_prepare_recipe_sysroot?虽然这个任务没有出现在上图中,但它却非常重要。
do_prepare_recipe_sysroot任务
网上大多资料都简要带过这个任务,未能讲明白这个任务是做什么的,但想要了解yocto的配方文件共享机制就必须弄明白这个任务是做什么的!
do_prepare_recipe_sysroot与do_populate_sysroot是staging.bbclass类中关键任务,用于共享配方之间成果物!抛出一个问题思考一下,如果一个配方B需要使用配方A的成果物怎么办(比如头文件、动态/静态链接库、配置文件)?yocto为了解决这种问题,提供了一套配方成果物共享机制,该机制分为两阶段:
第一阶段在A配方构建时完成。A配方在构建时,需要在do_install 任务中将需要共享的文件安装至${D}目录,后续执行的do_populate_sysroot任务将自动拷贝${D}目录下部分子目录到${SYSROOT_DESTDIR},而${SYSROOT_DESTDIR}目录最终会放置到共享区(默认为build/tmp/sysroots-components)暂存,其他配方构建时就可以从共享区拷贝。
那么,${D}目录下哪些子目录会被自动拷贝?自动拷贝的目录由三个变量指定,分别为SYSROOT_DIRS(目标设备需要保存的子目录)、SYSROOT_DIRS_BLACKLIST(目标设备不需要保存的子目录)、SYSROOT_DIRS_NATIVE(本机设备需要保存的目录),以SYSROOT_DIRS变量为例,其默认值为:
SYSROOT_DIRS = " \
${includedir} \
${libdir} \
${base_libdir} \
${nonarch_base_libdir} \
${datadir} \
"
如果需要添加其他额外保存的目录,可以在配方文件中增加SYSROOT_DIRS += “YYY”。
第二阶段在B配方构建时完成。B配方中添加DEPENDS += "A",便可使用A配方的成果物了。bitbake执行构建任务时会保证B配方的do_prepare_recipe_sysroot任务执行前,A配方的成果物已位于build/tmp/sysroots-components中。
do_prepare_recipe_sysroot任务会在${WORKDIR}目录中创建两个sysroot目录并填充(所有依赖拷贝到其中),这两个目录名分别为"recipe-sysroot"和"recipe-sysroot-native"(本机),其中"recipe-sysroot"给目标设备使用,A配方生成的成果物就在里面,另一个"recipe-sysroot-native"是给本机设备使用的。
不知道目标设备与本机设备的差异?简要讲解一下:假设要给arm平台编译flash固件,编译主机是x86平台,那么目标设备就是arm设备,本机设备就是x86编译主机。我们知道为arm设备编译代码需要使用交叉编译链(如arm-linux-gcc),编译链需要使用根文件系统下的各种库(或其他配方生成的头文件及库),因此便设置"recipe-sysroot"为编译器使用的文件系统。注意了,源码编译do_compile任务只是bitbake众多任务当中的一个,那其他任务也需要使用库或工具(如制作文件系统工具、压缩工具、cmake工具)怎么办?所以yocto将本机执行其他任务所需库或工具都放置于"recipe-sysroot-native"!
这里只介绍了构建依赖DEPENDS,但还有一种运行时依赖RDEPENDS,一般情况运行依赖会由构建系统自动添加,详情请参阅RDEPENDS。
do_configure任务
此任务用于完成编译源码前的配置,配置可以来自配方本身,也可以来自继承的类,一般情况我们都会使用autotools(配方中使用inherit autotools)、cmake类(配方中使用inherit cmake)或默认的make(不需要额外配置)。该任务运行时将当前工作目录设置为${B}(一般与${S}相同),该任务有个默认行为,即如果找到一个makefile (makefile, makefile,或GNUmakefile)并且CLEANBROKEN没有设置为“1”,则运行oe_runmake clean。
简单说明一下该任务怎么用:
如果你的软件包编译是基于autotools的,则可以使用EXTRA_OECONF或 PACKAGECONFIG_CONFARGS 变量添加其他配置选项,比如在配方文件中添加如下:
EXTRA_OECONF += "--with-mib-modules="mib" \
--with-openssl=openssl \
--with-default-snmp-version="3" \
--with-logfile="/var/log/snmpd.log" \
--with-persistent-directory="/etc" \
--enable-privacy \
--enable-md5 \
--enable-des \
--prefiex=/xxx/yyy/ \
"
则do_configure任务就如同手动执行./configure ${EXTRA_OECONF} ${PACKAGECONFIG_CONFARGS}一样。
如果你的软件包编译是基于cmake的,则可以使用EXTRA_OECMAKE变量添加其他配置选项,比如在软件包的配方文件添加如下:
EXTRA_OECMAKE = " \
-DBMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE=ON -DBMCWEB_INSECURE_DISABLE_SSL=ON \
-DBMCWEB_ENABLE_DEBUG=ON -DBMCW EB_ENABLE_LOGGING=ON \
"
则do_configure任务就如同手动执行mkdir build/ && cd build/ && cmake ${EXTRA_OECMAKE}一样。
如果你的软件包编译是基于make的,则可以使用EXTRA_OEMAKE变量添加其他配置选项,比如在软件包的配方文件添加如下:
EXTRA_OEMAKE = "INSTALL_PREFIX=${D} OTHERLDFLAGS='${LDFLAGS}' HOST_CPPFLAGS='${BUILD_CPPFLAGS}'"
则do_configure任务相当于只做默认行为(EXTRA_OEMAKE在执行make时才传入)。
do_compile任务
编译源代码。该任务运行时将当前工作目录设置为${B}(一般与${S}相同),该任务有个默认行为,即如果找到一个makefile (makefile, makefile,或GNUmakefile),则运行oe_runmake,若未找到此类文件将不执行任何操作。
如果在执行oe_runmake时需要传入额外编译选项或链接库,则可以使用在配方中以下变量:
CFLAGS += "-I${WORKDIR}/recipe-sysroot/usr/include/xxx -DBMCW=ON" #gcc的编译选项,增加额外头文件检索路径,定义BMCW宏
CXXFLAGS = " -fPIC" #g++的编译选项,告诉编译器产生位置无关代码
LDFLAGS += "-L${WORKDIR}/recipe-sysroot/usr/lib -yyy" #编译器链接选项
注意,如果源码是在${WORKDIR}${BPN}-${PV} 以外的任何目录,需要显性指定S变量值,比如从本地直接获取源码xxx.c和Makefile,则需要在配方中添加S = "${WORKDIR}",这样编译任务才能正常进行。
do_install任务
文件或成果物的安装任务。该任务会将编译目录${B}中需要打包的文件(放到目标设备中去的及其他配方依赖的)复制到保存区${D}中。注意:安装文件时不要把所有者和组ID设置错误,特别是使用cp命令时会保留原始文件的UID和GID,以下是推荐的安全方法:
使用install命令
使用cp命令时加上"--no-preserve=ownership"选项
使用tar命令时加上"--no-same-owner"选项
还记得上面提过的依赖吗?这个任务就是把其他配方所需依赖安装到${D}目录,然后do_populate_sysroot任务才能去${D}目中拷贝。假设A模块执行do_install的一个简单示例:
do_install() {
oe_runmake DESTDIR=${D}${libdir} install #执行Makefile中安装任务(安装.so),传入安装目录
install -m 0644 -d ${D}${includedir}/api #创建头文件目录
install -m 0644 ${S}/api_common.h ${D}${includedir}/api #安装头文件
install -m 0644 ${S}/api_xxx.h ${D}${includedir}/api #安装头文件
}
之后B模块在配方中添加如下:
DEPENDS += " A"
CFLAGS += " -I${WORKDIR}/recipe-sysroot/usr/include/api"
这样B模块就可以使用A模块编译的动态库。
该大阶段涉及但未解释的变量有以下:
B
包构建的编译目录,一般情况${B}与${S}相同,即为${WORKDIR}/${BPN}-${PV}。
D
包构建成果物的安装目录,也称为目标目录。默认情况这个目录为${WORKDIR}/image。
SYSROOT_DESTDIR
指向包构建工作目录下的临时目录,其默认值为${WORKDIR}/sysroot-destdir。
总结:源码配置、源码编译及成果物安装阶段就是引用依赖(如果有)完成源码配置、编译及成果物安装,安装的成果物可能是目标设备使用的,也可能是其他模块所需依赖。
4.包拆分处理
在配置、编译和安装完成后,构建系统分析结果并将包拆分处理,比如将文件stripped后放入packages-split目录:
该阶段分为三个任务,分别为do_package、do_packagedata、do_populate_sysroot。
do_package、do_packagedata任务
do_package和do_packagedata任务组合起来分析在${D}目录中找到的文件,并根据可用的包和文件将它们分成子集。分析处理过程包括以下内容:去除调试符号,查看包之间的共享库依赖关系,以及查看包之间的关系。
do_packagedata任务根据分析创建包元数据放置Package Feeds(即PKGDATA_DIR指定目录)中,这样构建系统就可以从拿到包生成最终的image。
do_populate_sysroot任务
do_populate_sysroot任务在之前已经介绍过。该任务将自动拷贝${D}目录下部分子目录到${SYSROOT_DESTDIR},并将${SYSROOT_DESTDIR}目录内容暂存至共享区(默认为build/tmp/sysroots-components)。自动拷贝的子目录由三个变量指定,分别为SYSROOT_DIRS(目标设备需要保存的子目录)、 SYSROOT_DIRS_BLACKLIST(目标设备不需要保存的子目录)、SYSROOT_DIRS_NATIVE(本机设备需要保存的目录),前面已经简要介绍过它们,详情请点入进官网参看。
该大阶段会涉及到以下变量:
PACKAGE_CLASSES
用于指定构建系统在打包文件时使用何种包管理器,该变量位于编译目标层的conf/local.conf.sample文件中(如有需要可在此文件中修改),这个文件将被解析到build/conf/local.conf文件中,比如设置其值为PACKAGE_CLASSES ?= "package_rpm package_tar"。
PKGD
在将包拆分为单独的包之前,包的目标目录。
PKGDESTWORK
do_package任务用来保存包元数据的临时工作区(即pkgdata)。
PKGDEST
拆分后的包的父目录(即packages-split)。
PKGDATA_DIR
一个共享的全局状态目录,其中包含打包过程中生成的打包元数据。打包过程将元数据从PKGDESTWORK复制到PKGDATA_DIR区域,在那里元数据成为全局可用的。
STAGING_DIR_HOST
要运行组件的系统的系统根路径(即recipe-sysroot),也就是当前配方源码编译时的根文件系统,里面包含配方所需依赖及交叉编译器所需依赖。
STAGING_DIR_NATIVE
为构建主机构建组件时使用的系统根路径(即recipe-sysroot-native)。
STAGING_DIR_TARGET
当构建在系统上执行的组件并为另一台机器生成代码(例如cross-canadian recipes)时使用的 sysroot 路径,一般与STAGING_DIR_HOST一样。
FILES
用于指定包(模块)安装在${D}目录中哪些成果物要打包,该变量位于配方文件中(如有需要可在此文件中修改)。简单来说就是在do_install任务中安装在${D}目录下的文件不会都打包,以rsa模块为例该变量的默认值为:
FILES_rsa="/usr/bin/* /usr/sbin/* /usr/libexec/* /usr/lib/lib*.so.* /etc /com /var /bin/* /sbin/* /lib/*.so.* /lib/udev /usr/lib/udev /lib/udev /usr/lib/udev /usr/share/hikrsa /usr/lib/hikrsa/* /usr/share/pixmaps /usr/share/applications /usr/share/idl /usr/share/omf /usr/share/sounds /usr/lib/bonobo/servers"
也就是说,只要成果物安装在上面这些目录下的都会参与打包,当然如果不放心或需要额外增加文件,可以在配方文件中显性指定:
FILES_${PN} += " \
${sbindir}/rsaverify \
" #${sbindir}默认为/usr/sbin/
总结:包拆分处理阶段就是根据conf配置将${D}目录中成果物打包放置于Package Feeds 区域,同时生成包元数据,最后将其他配方可能用到的文件放置于文件共享区(为其他配方提供依赖)。
5.image生成
注意,这个阶段在一般包(模块)编译过程中不存在!!!可通过bitbake -c listtasks XXX(包名或固件名)命令查看编译任务列表。
一旦软件包被拆分并存储在 Package Feeds 区域中,构建系统将使用 bitbake 生成根文件系统映像(image):
该阶段涉及两个任务,分别为do_rootfs、do_image。
do_rootfs任务
该任务将创建目标设备的根文件系统(将需要打包至目标设备的程序、库、文件等都放置到根文件系统中),这个根文件系统最终打包到image中。do_rootfs任务会通过ROOTFS_POSTPROCESS_COMMAND来优化文件大小(如mklibs过程优化了库的大小,同时prelink优化了共享库的动态链接以减少可执行文件的启动时间),ROOTFS_POSTPROCESS_COMMAND如下:
ROOTFS_POSTPROCESS_COMMAND() {
write_package_manifest; license_create_manifest; ssh_allow_empty_password; ssh_allow_root_login; postinst_enable_logging;
rootfs_update_timestamp ; write_image_test_data ; set_systemd_default_target; systemd_create_users; empty_var_volatile;
remove_etc_version ; set_user_group; sort_passwd; rootfs_reproducible;
}
创建的文件系统所在位置由IMAGE_ROOTFS变量指定,查看示例:
~/work/bmc$ bitbake -e obmc-phosphor-image | grep ^IMAGE_ROOTFS
IMAGE_ROOTFS="~/work/bmc/build/tmp/work/4u_x201-openbmc-linux-gnueabi/obmc-phosphor-image/1.0-r0/rootfs"
如果我们修改了某个程序,但又不想重新烧写整个固件,那就去这个目录下找到程序,再通过TFTP方式(或NFS直接挂载)下载到目标是设备调试即可。
do_image任务
do_image 任务会通过 IMAGE_PREPROCESS_COMMAND 对image进行预处理,主要是优化image大小,IMAGE_PREPROCESS_COMMAND 如下:
IMAGE_PREPROCESS_COMMAND() {
mklibs_optimize_image; prelink_setup; prelink_image; reproducible_final_image_task;
}
构建系统do_image根据需要动态生成支持的 do_image_* 任务,生成的任务类型取决于IMAGE_FSTYPES变量。do_image_* 任务将所有内容转换为一个image文件或一组image文件,并且可以压缩根文件系统image大小,以减小最终烧写到目标设备的image整体大小。用于根文件系统的格式取决于 IMAGE_FSTYPES变量,压缩取决于格式是否支持压缩。
image生成完成后执行最后一个任务do_image_complete,该任务将通过IMAGE_POSTPROCESS_COMMAND完成image的后续处理,默认情况IMAGE_POSTPROCESS_COMMAND为空,查看示例:
~/work/bmc$ bitbake -e obmc-phosphor-image | grep ^IMAGE_POSTPROCESS_COMMAND
IMAGE_POSTPROCESS_COMMAND=""
该大阶段涉及变量如下:
IMAGE_INSTALL
该变量指明Package Feeds 区域安装的基本软件包集中,哪些包(模块)最终要打包到image,该变量一般位于编译目标层的conf/local.conf.sample文件中(如有需要可在此文件中修改),这个文件将被解析到build/conf/layer.conf文件中。注意与FILES差异,FILES是指明软件包内部哪些文件需要参与打包,而IMAGE_INSTALL是指明哪个软件包需要参与打包。
一个简单示例:
IMAGE_INSTALL_append += ”rsa"
PACKAGE_EXCLUDE
指定不应安装到image中的包。
IMAGE_FEATURES
指定要包含在图像中的特征,大多数这些功能映射到其他安装包(未能弄明白具体作用)。
IMAGE_LINGUAS
确定安装附加语言支持包的语言,该变量一般位于编译目标层的conf/local.conf.sample文件中(如有需要可在此文件中修改),这个文件将被解析到build/conf/layer.conf文件中。默认情况下为:
~/work/bmc$ bitbake -e rsa | grep ^IMAGE_LINGUAS
IMAGE_LINGUAS="en-us en-gb"
PACKAGE_INSTALL
传递给包管理器以安装到映像中的包的最终列表。
DEPLOY_DIR
最终image和SDK输出的目录,默认值为build/tmp/deploy/。
总结:image生成生成阶段就是创建目标设备的根文件系统,并将需要打包至目标设备的程序、库、文件等都放置到根文件系统中,然后对文件和整个文件系统进行优化压缩,最终生成image。
简单示例
以api.bb的配方为例,其内容如下:
SUMMARY = "This is an example"
SECTION = "Examples"
HOMEPAGE = "http://www.xxx.com.cn/"
PR = "r1" #修订版本
#PV = "1.0" #这里不用指定配方版本,因为配方api.bb本身就不带版本,所以默认PV就是1.0
LICENSE = "MIT" #许可证类型
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" #校验许可证
FILESPATH := "${THISDIR}/../../sources/${PN}:" #本地文件搜索路径,PN默认为配方名称,即api
#此配方所依赖的其他配方
DEPENDS += "audit"
DEPENDS += "phosphor-ipmi-host"
#由于源码下载的目录是${WORKDIR},而非${WORKDIR}/${BPN}-${PV},因此需设置S,否则编译失败
S = "${WORKDIR}"
#指定需要下载的文件
SRC_URI += "\
file://Makefile \
file://make.libs \
file://api_common.h \
file://api_common.c \
file://api_ethernet.c \
file://api_ethernet.h \
"
#增加额外文件
SRC_URI += " \
file://api_systems.c \
file://api_systems.h \
"
#追加额外路径下的文件,还记得之前提过吗?尽量不要直接改变FILESPATH变量的值,所以下面方法虽然可用,但不是合理的,正确做法是使用FILESEXTRAPATHS变量
FILESPATH_append := "${THISDIR}/../../../meta-common/sources/host-ipmid/ipmi/:" #换成FILESEXTRAPATHS_append
SRC_URI_append = " \
file://sharememory.c \
"
#传入参数
TARGET_CC_ARCH += "${LDFLAGS}"
EXTRA_OEMAKE = " 'RECIPE_SYSROOT=${RECIPE_SYSROOT}' "
CFLAGS_prepend = "-I${WORKDIR}/recipe-sysroot/usr/include/audit "
#这里注意没有出现do_configure、do_compile任务,故默认执行构建系统的do_configure、do_compile任务
#在本配方基于make构建包,所以do_configure任务相当于啥也没干,do_compile任务则执行oe_runmake并传入参数
#重载do_install任务,即构建系统原始的do_install任务不再执行,转而执行以下do_install任务
do_install() {
oe_runmake DESTDIR=${D}${libdir} install #执行Makefile文件中的安装任务,并传入安装目录
install -m 0644 -d ${D}${includedir}/api
install -m 0644 ${S}/api_common.h ${D}${includedir}/api
install -m 0644 ${S}/api_common.c ${D}${includedir}/api #不仅可以安装头文件,c文件也可以给其他模块使用,但这不是合理的方式
install -m 0644 ${S}/api_ethernet.h ${D}${includedir}/api
install -m 0644 ${S}/api_systems.h ${D}${includedir}/api
}
#FILES变量默认会加上${includedir}和${libdir}目录,所以下面语句可以不要
#FILES_${PN} += "${includedir}/api"
#FILES_${PN} += "${libdir}"
本公司成本价甩卖工控主板,欢迎大家选购:
PCIE总线转八串口卡,PCIE总线转IO卡,瑞芯微3568板卡,寒武纪CE3226摄像头板卡,龙芯CPCI板卡,龙芯3A4000工控板卡,龙芯3A5000工控板卡,海光3250工控板卡,飞腾FT-2000/4板卡
联系方式:
电话、微信:15918785568 罗生
Email:13279654@qq.com
公众号:开发之美
————————————————
版权声明:本文为CSDN博主「caodongwang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zz2633105/article/details/122336873
标签:yocto,do,文件,image,bitbake,---,任务,配方,目录 来源: https://www.cnblogs.com/loongson-artc-lyc/p/16377158.html