yocto(二)——bitbake工作流程

  • Post author:
  • Post category:其他


本文参考yocto官方手册,如有理解不当之处,欢迎留言指出。

项目概述和概念手册:https://docs.yoctoproject.org/overview-manual/index.html

项目参考手册:https://docs.yoctoproject.org/ref-manual/index.html



yocto项目的厨师——bitbake

​ bitbake是OpenEmbedded构建系统的引擎,通过解析一系列配置文件(主要为recipes,即bb/bbappend文件)来创建任务列表,并根据依赖关系依次执行。通过bitbake -c listtasks xxx(模块名或映像名)命令可以查看编译一个模块或整个映像所需任务名称。编译一个模块/映像的主要执行过程如下(内核除外):

在这里插入图片描述

​ 下面按四个阶段来讲解bitbake的执行过程及涉及的变量,其中第四阶段(上图标黄的两任务)不是编译每个模块都有的。



源码获取及处理

​ 这个阶段包含三个任务,分别为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"


S

​ 解压后的配方源代码所在路径,该变量位于配方文件中(如有需要可在此文件中修改)。默认情况下,此目录为

${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

目录。



源码配置、源码编译及成果物安装

​ 源代码打好补丁后,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


总结

:源码配置、源码编译及成果物安装阶段就是引用依赖(如果有)完成源码配置、编译及成果物安装,安装的成果物可能是目标设备使用的,也可能是其他模块所需依赖。



包拆分处理

​ 在配置、编译和安装完成后,构建系统分析结果并将包拆分处理,比如将文件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 区域,同时生成包元数据,最后将其他配方可能用到的文件放置于文件共享区(为其他配方提供依赖)。



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}"

下篇文章再见啦~~~~



版权声明:本文为zz2633105原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。