yocto菜谱的重要知识
1、每个菜谱在其工作目录中都有两个sysroot,一个用于目标文件(recipe-sysroot),一个用于构建主机的本地文件(recipesysroot-native).
recipe-sysroot的文件是目标系统架构(arm)
recipe-sysroot的文件是构建主机架构(x86)
2、菜谱不能直接填充sysroot目录
应该在${D}目录中的do_install任务期间将文件安装到标准位置
3、可以通过修改SYSROOT_DIRS来修改要填充到sysroot的目录列表
SYSROOT_DIRS变量定义,do_populate_sysroot任务将使用do_install任务安装的文件的子集来自动填充sysroot
例如将opt目录添加到目录列表里
SYSROOT_DIRS += "opt"
4、virtual 提供程序
在构建之前,如果您知道几种不同的菜谱提供相同的功能,则可以使用虚拟提供程序(即virtual/*)作为实际提供程序的占位符,实际的提供者是在构建时确定。
使用虚拟提供程序的常见方案是内核recipes ,假如有3个内核菜谱:PN值分别为 kernel-big、kernel-mid、kernel-small,
这3个菜谱都使用PROVIDES将自己标识为能够提供virtual/kernel
5、内核类提供virtual/kernel的方法
PROVIDES += "${@"virtual/kernel"if (d.getVar("KERNEL_PACKAGE_NAME") == "kernel") else""}"
继承内核类的任何菜谱都可以利用PROVIDES语句,表面自己能够提供virtual/kernel项目.
6、构建镜像需要指定内核菜谱,怎么确定用哪个内核菜谱呢?
使用PREFERRED_PROVIDER 指定哪个菜谱,使用PREFERRED_VERSION 指定菜谱的版本
一个例子:/meta/conf/machine/include/x86-base.inc
PREFERRED_PROVIDER_virtual/kernel ??= "linux-yocto" PREFERRED_VERSION_linux-yocto ??= "5.2%"
另一个例子:meta-ti/conf/machine/include/ti33x.inc
PREFERRED_PROVIDER_virtual/kernel = "linux-ti-staging" PREFERRED_PROVIDER_virtual/bootloader = "u-boot-ti-staging" PREFERRED_PROVIDER_u-boot = "u-boot-ti-staging"
7、当菜谱需要使用virtual提供的依赖项时,不必硬编码需要依赖的菜谱名称,可以使用DEPENDS变量来声明菜谱构建依赖于virtual/kernel
DEPENDS = "virtual/kernel"
8、在构建最终镜像期间, OpenEmbedded构建系统将根据PREFERRED_PROVIDER变量选择virtual/kernel依赖所需的正确recipes
如果要使用kernel-small内核,则可以用下面的方式配置构建环境选择的菜谱
PREFERRED_PROVIDER_virtual/kernel ??= "kernel-small"
9、如果没有被PREFERRED_PROVIDER选择的PROVIDES virtual/* 项目的任何菜谱都不会生成,这提供了选择内核菜谱的机制
10、菜谱发布前需要正确设置版本
例如:irssi_0.8.16-rc1.bb此菜谱处于候选发布阶段(rc1),当正式发布时菜谱更名为irssi_0.8.16.bb
版本从irssi_0.8.16-rc1.bb -> irssi_0.8.16.bb 被看作是构建系统和包管理器的下降,因此产生的程序包将无法正确地触发升级
为了确保版本比较正确,建议的惯例是将菜谱中的PV
设置为 “previous_version +
current_version
”。
您可以使用其他变量,以便可以在其他地方使用当前版本。这是一个例子
REALPV = "0.8.16-rc1" PV = "0.8.15 +${REALPV}"
11、postinst 脚本
主要完成软件包(eg ".deb")安装完成后所需的配置工作。安装程序在目标上安装程序包之后postinst 脚本立即运行。
要向软件包中添加安装后脚本,请将pkg_postinst_PACKAGENAME()函数添加到菜谱文件(.bb),然后将PACKAGENAME替换为您要附加到postinst 脚本的软件包的名称。
要将安装后脚本应用于菜谱的主软件包(通常必需的),请指定用${PN}代替PACKAGENAME.
postinst 格式
pkg_postinst_PACKAGENAME(){ #行执创建根文件系统的命令时,将调用postinst功能中定义的脚本.如果脚本成功,则将该软件包标记为已安装.如果脚本失败,则将包标记为已解压缩,并在再次引导映像时执行脚本. }
有时有必要将postinst脚本的执行延迟到首次启动之前。例如,脚本可能需要在设备本身上执行。若要将脚本执行延迟到启动时间,则必须显式标记postinst才能推迟到目标设备。
您可以使用pkg_postinst_ontarget()或
从pkg_postinst()调用 postinst-intercepts defer_to_first_boot,pkg_postinst()
脚本的任何失败(包括 exit 1)都会在do_rootfs
任务执行期间触发错误.
如果您拥有使用pkg_postinst
功能的菜谱, 并且他们需要使用非标准本机工具,这些工具在rootfs构造过程中具有依赖性,则需要在菜谱中使用PACKAGE_WRITE_DEPS
变量来列出这些工具。
如果不使用此变量,则可能会缺少工具,并且postinst脚本的执行将推迟到首次启动时执行。将脚本推迟到第一次启动是不希望的,并且对于只读rootfs是不可能的。
注意:通过pkg_preinst, pkg_prerm和pkg_postrm分别存在对预安装,预卸载和后卸载脚本的等效支持。这些脚本与pkg_postinst的工作方式完全相同, 不同的是它们在不同的时间运行
另外,由于它们不同的运行时间,它们不适用于在映像创建时像pkg_postinst一样运行。
12、使用本地文件的菜谱文件3中情况
12.1、使用单个hello.c文件
从本地存储的单个文件(例如,在files下)构建应用程序需要菜谱包含SRC_URI
变量中列出的文件 。此外,您需要手动编写 do_compile
和 do_install
任务。
S
变量定义包含源代码的目录,在这种情况下,WORKDIR
目录被设置为 BitBake用于构建的目录。
SUMMARY = "Simple helloworld application" SECTION = "examples" LICENSE = "MIT" LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI = "file://helloworld.c" S = "${WORKDIR}" do_compile() { ${CC} helloworld.c -o helloworld } do_install() { install -d ${D}${bindir} install -m 0755 helloworld ${D}${bindir} }
默认情况下,helloworld,
helloworld-dbg,
helloworld-dev 包会被构建
12.2、自动工具包
使用 Autotools 的应用程序(例如:autoconf 和
automake
)需要一个在SRC_URI中列出了源归档文件的菜谱,并且该菜谱还继承了autotools类,该类包含构建基于Autotool的应用程序所需的所有步骤的定义
构建结果将自动打包。并且,如果应用程序使用NLS进行本地化,则会生成带有本地信息的程序包(每种语言一个程序包)。
以下是一个示例:(hello_2.3.bb
)
SUMMARY = "GNU Helloworld application" SECTION = "examples" LICENSE = "GPLv2+" LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe" SRC_URI = "${GNU_MIRROR}/hello/hello-${PV}.tar.gz" inherit autotools gettext
12.3、基于Makefile的软件包
使用GNU make的应用程序还需要一个菜谱,该菜谱的源归档文件列在SRC_URI中。不需要添加do_compile设置,因为默认情况下BitBake启动make命令来编译应用程序。
如果需要其他make属性, 则应将其存储在EXTRA_OEMAKE或PACKAGECONFIG_CONFARGS变量中。BitBake将这些选项传递到GNU make调用中。
注意, 仍然需要do_install任务。否则,默认情况下BitBake运行一个空的do_install任务.。
某些应用程序可能需要额外的参数才能传递给编译器。例如,应用程序可能需要附加头文件路径,您可以通过添加到CFLAGS变量来完成此操作.
下面的示例显示了这一点:
CFLAGS_prepend = "-I ${S}/include "
在下面这个例子中,mtd-utils是一个makefile-base的包
SUMMARY = "Tools for managing memory technology devices" SECTION = "base" DEPENDS = "zlib lzo e2fsprogs util-linux" HOMEPAGE = "http://www.linux-mtd.infradead.org/" LICENSE = "GPLv2+" LIC_FILES_CHKSUM = "file://COPYING;md5=0636e73ff0215e8d672dc4c32c317bb3 \ file://include/common.h;beginline=1;endline=17;md5=ba05b07912a44ea2bf81ce409380049c" # Use the latest version at 26 Oct, 2013 SRCREV = "9f107132a6a073cce37434ca9cda6917dd8d866b" SRC_URI = "git://git.infradead.org/mtd-utils.git \ file://add-exclusion-to-mkfs-jffs2-git-2.patch \ " PV = "1.5.1+git${SRCPV}" S = "${WORKDIR}/git" EXTRA_OEMAKE = "'CC=${CC}' 'RANLIB=${RANLIB}' 'AR=${AR}' 'CFLAGS=${CFLAGS} -I${S}/include -DWITHOUT_XATTR' 'BUILDDIR=${S}'" do_install () { oe_runmake install DESTDIR=${D} SBINDIR=${sbindir} MANDIR=${mandir} INCLUDEDIR=${includedir} } PACKAGES =+ "mtd-utils-jffs2 mtd-utils-ubifs mtd-utils-misc" FILES_mtd-utils-jffs2 = "${sbindir}/mkfs.jffs2 ${sbindir}/jffs2dump ${sbindir}/jffs2reader ${sbindir}/sumtool" FILES_mtd-utils-ubifs = "${sbindir}/mkfs.ubifs ${sbindir}/ubi*" FILES_mtd-utils-misc = "${sbindir}/nftl* ${sbindir}/ftl* ${sbindir}/rfd* ${sbindir}/doc* ${sbindir}/serve_image ${sbindir}/recv_image" PARALLEL_MAKE = "" BBCLASSEXTEND = "native"
13、将应用程序拆分为多个程序包
可以使用变量PACKAGES和FILES将应用程序拆分为多个程序包
以下是使用libxpm
配方的示例。默认情况下,此配方会生成一个包含程序库和一些二进制文件的包
require xorg-lib-common.inc SUMMARY = "Xpm: X Pixmap extension library" LICENSE = "BSD" LIC_FILES_CHKSUM = "file://COPYING;md5=51f4270b012ecd4ab1a164f5f4ed6cf7" DEPENDS += "libxext libsm libxt" PE = "1" XORG_PN = "libXpm" PACKAGES =+ "sxpm cxpm" FILES_cxpm = "${bindir}/cxpm" FILES_sxpm = "${bindir}/sxpm"
在这个的示例中,我们希望将sxpm
和cxpm
二进制文件分别打包。由于 默认情况下bindir
会打包到主程序 PN
包中,因此我们在PACKAGES
变量之前加上了前缀,以便将其他程序包名称添加到列表的开头。
这将导致FILES_*
变量定义哪些文件和目录被包含进哪些程序包的信息。较早版本的软件包包含的文件被较早版本的软件包跳过。因此,主PN
软件包不包括上面列出的文件。
14、打包外部生成的二进制文件
有时,您需要向镜像中添加预编译的二进制文件。例如,假设存在专有代码的二进制文件,这些二进制代码是由公司的特定部门创建的。
公司需要将这些二进制文件用作要使用OpenEmbedded构建系统构建的映像的一部分。
因为您只有二进制文件,而没有源代码,所以您不能使用期望获取SRC_URI中指定的源,然后进行编译的典型菜谱.
14.1、一种方法是打包二进制文件,然后将其安装为映像的一部分。通常,打包二进制文件不是一个好主意,因为,它可能会阻碍复制生成文件的能力,并可能导致将来与ABI的兼容性问题。但是,有时您别无选择
14.2、最简单的解决方案是创建一个使用bin_package类的菜谱,并确保您使用默认位置生成构件
在大多数情况下,bin_package
该类负责“跳过”配置和编译步骤,并进行设置以从适当的区域获取软件包。
特别是bin_pacgage这个类在do_configure
和 do_compile 任务中都设置
noexec。
设置
FILES_${PN}为
"/" 以便他选择所有的文件,并设置一个do_install任务,该任务将所有文件从${S}复制到${ D}
当提取到${S}中的文件已经按照应在目标上的布局方式进行布局时, bin_package类可以很好地工作
14.3、如果无法使用bin_package类,则需要确保您执行以下操作
14.3.1、创建一个菜谱,使其中do_configure和do_compile任务不起作用:
通常只要不在菜谱中定义这些任务就足够了,因为除非在$(S}中找到Makefile,否则默认实现不执行任何操作
如果${S}可能包含一个Makefile,或者你继承了一个用自定义版本替换do_configure和do_compile的类,那么你可以使用[
noexec
]标志,将任务转变为(no-ops)无操作
如下所示:
do_configure[noexec] = "1" do_compile[noexec] = "1"
14.3.2、与 deleting the tasks 任务不同,noexec标志会将依赖关系链从do_fetch, do_unpack和do_patch任务保留到do_install任务
14.3.3、确保您的do_install任务正确安装了二进制文件
14.3.4、确保您将FILES(通常是FILES_${PN})设置为指向已安装的文件,这当然取决于安装它们的位置以及这些文件是否位于默认位置之外的其他位置
15、菜谱的语法
https://www.yoctoproject.org/docs/3.0.2/mega-manual/mega-manual.html#bitbake-user-manual-metadata