拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

yocto: 16-Package_RDEPENDS

yocto: 16-Package_RDEPENDS

第6课:Package / Dependency / RDEPENDS

摘要:本课深入讲解 Yocto 的 Package 机制,包括 Recipe 如何拆分为多个 Package、Package 的生成流程、FILES 变量分配文件到不同 Package,以及编译时依赖(DEPENDS)和运行时依赖(RDEPENDS)的区别与作用。通过 hello-script 实验,你将亲身体验 RDEPENDS 如何自动安装运行时依赖到最终镜像,并掌握 packages-split 目录分析和 oe-pkgdata-util 工具的使用。

这是 Yocto 学习路线里非常重要的一课。到目前为止,你已经掌握了:
1.Layer (meta-myproduct)
2.Recipe (.bb)
3.do_install
4.systemd service
5.image recipe (myproduct-image)
6.将文件安装到 rootfs

接下来学习 Package / Dependency / RDEPENDS,就是理解 Yocto 如何把一个 recipe 拆成
package,以及 package 之间如何自动安装依赖。


一、为什么需要 Package?
假设你写了一个 recipe: hello.bb
里面安装了: /usr/bin/hello
编译结束以后,并不是直接进入 image。
Yocto 会先产生 package。
例如: hello
然后 image 再决定是否安装这个 package。
整个流程

Recipe ▼ do_install ▼${D}▼ do_package ▼ ipk/rpm/deb package ▼ Image
所以: .bb ↓ Package ↓ Image

这一层就是今天要学的。


二、Package 长什么样?
例如: hello.bb
编译后: tmp/deploy/ipk/
会看到: hello_1.0-r0.ipk
或者

tmp/deploy/rpm/ hello-1.0.rpm

或者

tmp/deploy/deb/ hello_1.0.deb

Yocto 默认由: PACKAGE_CLASSES
决定。

例如: PACKAGE_CLASSES = “package_ipk”


三、一个 recipe 可以产生多个 package
这是 Yocto 最大特色之一。
例如: nano.bb
最后可能产生

nanonano-doc nano-dev nano-dbg nano-staticdev

为什么?
因为:
程序 nano 放一起。
文档 /usr/share/doc 放一起。
头文件: /usr/include 放一起。
调试信息: .debug 放一起。
所以:
一个 Recipe ≠ 一个 Package
而是

Recipe ↓ 多个 Package

四、PACKAGES
例如

PACKAGES="\${PN}\${PN}-dev \${PN}-dbg \ "

其中: PN 就是 package name。
例如

hello.bbPN=hello

所以: ${PN} 就是 hello


五、FILES
FILES 决定: 哪些文件属于哪个 package。
例如: FILES:${PN} += “/usr/bin/hello”
表示: hello package 包含 /usr/bin/hello

例如: FILES:${PN}-dev += “/usr/include” 表示 hello-dev 包含 /usr/include


六、什么是 Dependency?
有两种:
Build Dependency 和 Runtime Dependency

这是初学者最容易混淆的地方。


Build Dependency
使用 DEPENDS
例如: DEPENDS += “openssl”
意思:

编译 hello 之前 先编译 openssl

注意:
这是编译机上的依赖。

不是 rootfs。


Runtime Dependency
使用 RDEPENDS
例如: RDEPENDS:${PN} += “bash”
表示运行 hello
需要 bash。
因此 image 会自动安装 bash。
所以:

DEPENDS 影响 bitbake 编译顺序

而
RDEPENDS

影响 image 安装哪些 package


七、举例理解
例如 : myscript.sh
内容:

#!/bin/bashechohello

recipe

SRC_URI+="file://myscript.sh"do_install(){install-d ${D}${bindir}install-m755${WORKDIR}/myscript.sh \ ${D}${bindir}/myscript}

如果 image 没有 bash
运行: myscript
会看到
/bin/bash

No such file
因此需要: RDEPENDS:${PN} += “bash”

这样 image 自动安装 bash


八、查看 package 包含哪些文件
编译结束以后:tmp/work/…/packages-split/
例如

packages-split/ hello/ usr/bin/hello hello-dev/ usr/include hello-dbg/ usr/lib/.debug

这是理解 package 最好的目录。

建议以后经常看。


九、查看 package 依赖
可以查看 pkgdata:oe-pkgdata-util list-pkg-files hello
查看 package 文件:oe-pkgdata-util find-path /usr/bin/hello
查看 package 运行依赖:oe-pkgdata-util read-value RDEPENDS hello

这些命令对分析依赖非常有帮助。


十、与你当前学习最相关的实践
建议不要直接学习复杂的软件包,而是继续使用你已经建立的 meta-myproduct 学习环境,做两个最小实验:
实验 1:体验 RDEPENDS

- 新建一个 hello-script.bb,安装一个#!/bin/bash 的脚本。- 先不写 RDEPENDS:${PN}+="bash",观察运行失败。 - 再加入 RDEPENDS,重新构建 image,验证bash会自动进入 rootfs。

实验 2:体验多个 Package

  • 在同一个 recipe 中安装一个程序和一个 README。

  • 将 README 放入 ${PN}-doc,程序放入 ${PN}。

  • 查看 tmp/work/…/packages-split/,确认生成了两个 package,并观察各自包含的文件。


推荐掌握顺序
按照你目前的 Yocto 学习路线,我建议按下面的顺序继续:
1.Package 的生成流程(Recipe → Package → Image)
2.FILES:PN的作用3.DEPENDS(编译时依赖)4.RDEPENDS:{PN} 的作用 3.DEPENDS(编译时依赖) 4.RDEPENDS:PN的作用3.DEPENDS(编译时依赖)4.RDEPENDS:{PN}(运行时依赖)
5.packages-split 目录分析
6.oe-pkgdata-util 分析 package 和依赖

学完这一课后,你就具备了阅读大多数官方 .bb 文件的基础,下一步可以学习 Packagegroup(软件包集合),以及
IMAGE_INSTALL 与 packagegroup 的关系,这也是构建完整产品镜像时最常用的机制。


实验1
最终希望验证:

hello-script.bb │ ├── 安装 /usr/bin/hello-script │ ├── 不写 RDEPENDS │ │ │ └── 运行失败(找不到 bash) │ └── 加入 RDEPENDS:${PN}+="bash"│ └── image 自动安装bash

Step 1 建立 recipe 目录
进入你的 layer: cd ~/yocto/meta-myproduct
创建 recipe: mkdir -p recipes-test/hello-script/files
确认目录: find recipes-test
应该看到

recipes-test/ └── hello-script └── files

Step 2 编写脚本
进入: cd recipes-test/hello-script/files

建立: nano hello-script
内容:

#!/bin/bashecho"Hello from Bash!"echo"Shell =$0"

保存。
然后赋予可执行权限(方便本地测试,Yocto 安装时也会设置权限):chmod +x hello-script
验证:cat hello-script
应该看到

#!/bin/bashecho"Hello from Bash!"echo"Shell =$0"

Step 3 编写 hello-script.bb
回到 recipe : cd …
建立recipe: nano hello-script.bb
内容:

SUMMARY="Simple bash script for RDEPENDS demo"LICENSE="MIT"SRC_URI="file://hello-script"S="${WORKDIR}"do_install(){install-d ${D}${bindir}install-m0755${WORKDIR}/hello-script ${D}${bindir}/hello-script}#RDEPENDS:${PN}+="bash"

注意:
这里故意不写

RDEPENDS:${PN}+="bash"

因为我们要先观察失败。


Step 4 把 package 加进 image
打开: meta-myproduct/recipes-core/images/myproduct-image.bb
找到: IMAGE_INSTALL += “…”
加入: IMAGE_INSTALL += “hello-script”
例如

IMAGE_INSTALL+="\ hello-script \ "

到这里暂停
现在你的 layer 应该像这样:

meta-myproduct/ recipes-test/ └── hello-script ├── hello-script.bb └── files └── hello-script

以及

recipes-core/images/ └── myproduct-image.bb

里面已经有: IMAGE_INSTALL += “hello-script”

Step 5 编译 hello-script
先不要编整个 image。
先验证 recipe 是否正确。
执行:
cd ~/yocto/build-rpi2
bitbake hello-script
如果成功,会看到类似:
NOTE: Tasks Summary:
Attempted xxx tasks

没有 ERROR 即表示 recipe 正常。


Step 6 检查 package 是否产生
执行:find tmp/deploy -name “hello-script”
应该能看到类似:

tmp/deploy/ipk/... hello-script_1.0-r0_cortexa7t2hf-neon-vfpv4.ipk

(如果你的 PACKAGE_CLASSES 是 rpm 或 deb,则扩展名会不同。)


Step 7 查看 packages-split
这是今天最重要的一步。
执行:find tmp/work -path “hello-script” -path “packages-split” -type d
应该会得到类似:…/hello-script/1.0/packages-split
进入:

cd<刚才输出的packages-split目录>tree

你应该看到类似:

packages-split └── hello-script └── usr └── bin └── hello-script

这一步非常关键,因为它说明:

Recipe ↓ do_install ↓${D}↓ do_package ↓ packages-split ↓ ipk

你已经亲眼看到 Recipe 被拆成 Package 了。


Step 8 查看 Package 内容

再执行:oe-pkgdata-util list-pkg-files hello-script
如果成功,会列出类似:
hello-script:
/usr/bin/hello-script

这说明 package 中确实只有这个脚本。


暂时不要编 image
我们现在的目标是先确认:
✅ recipe 能编译
✅ package 已生成
✅ package 里面包含 /usr/bin/hello-script
确认这些以后,再进入第二阶段:

验证没有 RDEPENDS 时,为什么运行会失败。


我们已经验证了什么?
① Recipe 编译成功 ✅

bitbake hello-script

没有任何 ERROR,说明:

- hello-script.bb 正确 - do_install()正确 - package 成功生成

② RPM package 已生成 ✅
你这里看到:tmp/deploy/rpm/…/hello-script-1.0-r0…rpm
说明你的系统使用的是: PACKAGE_CLASSES = “package_rpm”

所以生成的是 RPM,而不是 IPK。


③ package 已拆分成功 ✅
你看到:

packages-split/ hello-script hello-script-dev hello-script-doc hello-script-dbg

…
这正是 Yocto 的标准行为。
虽然你的 recipe 很简单,-dev、-doc 等 package 基本是空的,但 Yocto 仍然会创建这些 package。
这说明:

Recipe ↓ do_install ↓${D}↓ do_package ↓ packages-split

你已经亲眼看到了。


④ package 中确实有脚本 ✅
你执行:oe-pkgdata-util list-pkg-files hello-script
得到: /usr/bin/hello.sh
这里我要指出一个小细节。
我们确认 package 没问题后,就开始真正的 RDEPENDS 实验。
现在进入真正的 RDEPENDS 实验

终于到了今天最重要的部分。


Step 9 构建 image
重新编译 image:

cd~/yocto/build-rpi2 bitbake myproduct-image

成功以后,烧录 SD 卡。


Step 10 在 Raspberry Pi 上验证
启动 Pi。
先确认脚本存在:which hello.sh
或者: ls -l /usr/bin/hello.sh

应该能看到:/usr/bin/hello.sh


然后运行:hello.sh

或者: /usr/bin/hello.sh


Step 11 观察结果
我们这次故意没有写
RDEPENDS:${PN} += “bash”
因此,要验证一个问题:
Image 里面有没有 bash?
先执行:which bash
再执行:ls -l /bin/bash

然后运行:hello.sh


有两种可能
情况 A(我们希望看到)

/bin/bash: No suchfileor directory

这说明:
Image 里没有 bash。
脚本因为 shebang

#!/bin/bash

无法启动。
这就是为什么需要

RDEPENDS:${PN}+="bash"

情况 B
如果运行成功,例如:

Hello from Bash!

说明:
你的 image 已经因为其它 package 安装了 bash。
这种情况也很常见,例如:

openssh

或者某些 packagegroup 已经依赖 bash。
那我们就不能证明 RDEPENDS 的作用。
不过不用担心,我们仍然可以验证:

hello-script │ └── 是否声明bash为运行依赖

并通过修改 recipe 观察依赖变化。


下一步
请先完成:bitbake myproduct-image
烧录并启动 Raspberry Pi,然后把下面四个命令的输出贴给我:

whichbashls-l/bin/bashwhichhello.sh hello.sh

根据结果,我们再进行 添加 RDEPENDS:${PN} += “bash” 前后的对比实验。这是理解 RDEPENDS 的关键一步。

返回列表