ARTICLE DETAIL

资讯详情

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

yocto: 02-BitBake拆解

yocto: 02-BitBake拆解 请先检查面三个命令的输出ls -lh tmp/deploy/images/raspberrypi2/zImage大量 .dtb大量 .dtbocore-image-minimal-raspberrypi2.rootfs-…ext3core-image-minimal-raspberrypi2.rootfs-…tar.bz2core-image-minimal-raspberrypi2.rootfs-…wic.bz2.wic.bmapmodules-…tgz…bitbake -e core-image-minimal | grep ‘^IMAGE_FSTYPES’bitbake -e core-image-minimal | grep ‘^MACHINE’bitbake -e core-image-minimal | grep ‘^MACHINE’MACHINE“raspberrypi2”也就是说你的 bitbake core-image-minimal 已经成功完成并且已经进入了我们之前说的“开始真正理解 BitBake 到底在干什么”的阶段。下一步最值得做的不是继续盲目编译而是沿着这条线理解MACHINE raspberrypi2▼core-image-minimal▼BitBake 解析 recipe / class / config▼建立 task 依赖图▼do_fetchdo_unpackdo_patchdo_configuredo_compiledo_installdo_package…▼rootfs▼image generation▼tmp/deploy/images/raspberrypi2/尤其建议我们下一步直接研究bitbake -g core-image-minimal然后看看生成的task-depends.dot pn-buildlist这会比继续看 ls 更接近 BitBake 的核心机制它究竟如何从一个 core-image-minimal推导出这么多任务和依赖关系。Loading cache: 100% |####################################################| Time: 0:00:01Loaded 1923 entries from dependency cache.NOTE: Resolving any missing task queue dependenciesNOTE: PN build list saved to ‘pn-buildlist’NOTE: Task dependencies saved to ‘task-depends.dot’非常好。你现在拿到的这两个文件实际上就是第一次真正“看见 BitBake 大脑”。你不要把它们当成两个需要“读完”的文件而要把它们当成两个不同视角pn-buildlist↓BitBake 决定我要构建哪些“配方/包”task-depends.dot↓BitBake 决定这些配方具体要执行哪些 tasktask 之间谁依赖谁你这次的两个文件正好可以拿来做一次完整的 BitBake 学习。下面我建议你按这个顺序学。1. 先看 pn-buildlist理解 BitBake 的构建清单你的pn-buildlist文件列出了 236 个条目这正是 BitBake 为构建core-image-minimal所规划的全部“配方目标”。文件的开头几行通常是这样的core-image-minimal quilt-native patch-native pseudo-native linux-raspberrypi xz-native cross-localedef-native qemuwrapper-cross...这里需要建立一个关键认知BitBake 并不是简单地“编译一个 core-image-minimal”。更准确的构建过程是bitbake core-image-minimal ▼ 明确要构建的目标target ▼ 递归解析其所有依赖 ├── linux-raspberrypi内核 ├── glibcC库 ├── busybox基础工具集 ├── gcc编译器 ├── ... ▼ 继续展开这些依赖的依赖 ▼ 最终得到 236 个需要处理的配方Package Name即 PN因此pn-buildlist可以理解为BitBake 为了完成core-image-minimal这个最终目标所必须涉及的所有配方列表。它回答了“要构建什么”WHAT的问题。2. 第一个非常重要的发现-native你这个文件特别适合学习一个 Yocto 初学者很容易困惑的问题。例如quilt-native patch-native pseudo-native xz-native qemuwrapper-cross...gcc-cross-arm...python3-native...为什么这么多 -native你可以先建立一个非常重要的认识quilt-native不是给 Raspberry Pi 运行的 quilt。而是而quilt则属于目标系统侧的东西。所以可以暂时记住python3-native python3以及gcc-cross-arm gcc-runtime gcc这已经开始涉及 Yocto 最核心的Build / Host / Target 三元关系不过这里我们暂时不要跳太远。3. 然后看 task-depends.dot这个文件比 pn-buildlist 更重要。你的文件有15,894 lines大小约1.3 MB所以千万不要试图从第一行读到最后一行。它实际上是一个 Graphviz DOT 图。开头digraph depends {然后你会看到这种东西acl-native.do_compile[labelacl-native do_compile :2.3.2-r0 virtual:native:/home/cxicc/yocto/poky/meta/recipes-support/attr/acl_2.3.2.bb]acl-native.do_compile-acl-native.do_configure这就是 BitBake 的核心。4. 先学会看懂一个节点比如acl-native.do_compile拆开acl-native│└── PNdo_compile│└── task所以acl-native.do_compile就是对 acl-native 这个 recipe 执行 do_compile task。再看acl-native.do_configureacl-native.do_compileacl-native.do_installacl-native.do_patchacl-native.do_unpackacl-native.do_fetch你现在已经可以看到一个非常典型的生命周期do_fetch↓do_unpack↓do_patch↓do_configure↓do_compile↓do_install这就是你之前问我的BitBake 到底在干什么现在终于可以从真实数据里面看到它了。5. - 是最值得你学习的符号比如你的文件中“acl-native.do_compile” - “acl-native.do_configure”可以先读成acl-native.do_compile↓acl-native.do_configure也就是do_compile 依赖 do_configure。所以do_configure必须先完成。于是 BitBake 可以建立do_configure↓do_compile再比如“acl-native.do_install” - “acl-native.do_compile”于是do_configure↓do_compile↓do_install6. 这时候你就会发现BitBake 不是 Make这是一个特别重要的学习点。如果你以前使用 Makemake脑子里可能是源代码↓编译↓链接↓程序但 BitBake 的世界更像它实际上是在管理一个巨大的 Task Dependency Graph。这正是 task-depends.dot 存在的意义。7. 你现在应该重点研究 core-image-minimal不要从 acl 开始学。因为 acl 对你现在来说只是一个普通 package无法帮助你理解整个 image。我们应该从core-image-minimal开始向下追。你现在可以在 task-depends.dot 里面搜索core-image-minimal.do_你会发现很多类似core-image-minimal.do_rootfs core-image-minimal.do_image core-image-minimal.do_image_wic...这才是我们真正应该研究的地方。8. 你会看到一个非常关键的链条条你最终要慢慢建立这样的 mental modelbitbake core-image-minimal▼core-image-minimal▼do_rootfs▼把 packages 装进 rootfs▼do_image▼生成 image▼do_image_wic▼.wic / .wic.bz2这和你刚才的实际输出正好对应core-image-minimal-raspberrypi2.rootfs.wic.bz2你已经不是“猜”它怎么来的了。你可以从task-depends.dot反向追踪它。9. pn-buildlist 和 task-depends.dot 要配合看这是今天最重要的一点。你可以把它们想成pn-buildlist回答有哪些东西参与了这次构建例如linux-raspberrypi glibc busybox gcc coreutils...task-depends.dot回答这些东西具体怎么一步一步构建例如linux-raspberrypi.do_fetch↓linux-raspberrypi.do_unpack↓linux-raspberrypi.do_patch↓linux-raspberrypi.do_configure↓linux-raspberrypi.do_compile↓linux-raspberrypi.do_install所以pn-buildlist WHATtask-depends.dot HOW这个理解非常重要。10. 还有一个非常有意思的地方你可以注意这个acl-native.do_compile和acl.do_compile它们是两个不同的节点。你的 task-depends.dot 里面确实同时存在acl-native.do_compile和acl.do_compile这说明 BitBake 的世界不是简单的recipe → compile而是recipecontextvarianttask最终形成一个具体 task。这就是以后理解virtual:nativecrossnativetargetsysrootrecipe-sysrootrecipe-sysroot-native的入口。11. 我建议你现在不要看整个 DOT我们进行一次非常小的实验。你在~/yocto/build-rpi2执行grep ‘core-image-minimal.do_’ task-depends.dot看结果然后再执行grep ‘core-image-minimal.do_’ task-depends.dot | grep ‘-’看结果我们下一步就只研究这几个节点我会带你从真实的 task-depends.dot 一步一步追core-image-minimal↓do_rootfs↓do_image↓do_image_wic↓最终 .wic.bz2然后再把其中一个 package比如busybox拉出来core-image-minimal↓package↓busybox↓busybox.do_fetch↓busybox.do_unpack↓busybox.do_patch↓busybox.do_configure↓busybox.do_compile↓busybox.do_install↓…这样学比看 Yocto 文档里的抽象定义有效得多因为我们是在“解剖你刚刚自己构建出来的系统”。你现在已经有 pn-buildlist 和 task-depends.dot 了下一步就从 core-image-minimal.do_* 开始。12. 理解core-image-minimal.do_xxx第一步Image 是怎么生成的先搜索grep “core-image-minimal.do_” task-depends.dot你应该会看到类似不同版本略有差异core-image-minimal.do_rootfscore-image-minimal.do_imagecore-image-minimal.do_image_completecore-image-minimal.do_image_wiccore-image-minimal.do_build…这几个 task 就回答了最终的 .wic.bz2 是怎么来的例如do_rootfs▼生成 root filesystem▼do_image▼▼do_image_wic▼生成 .wic▼压缩成 .wic.bz2你最终在 tmp/deploy/images/raspberrypi2/ 看到的文件就是这几个 task 的产物。第二步rootfs 里面为什么会有 busybox继续搜索grep “busybox.do_” task-depends.dot你会看到busybox.do_fetchbusybox.do_unpackbusybox.do_patchbusybox.do_configurebusybox.do_compilebusybox.do_installbusybox.do_package…这里就回答了第二个问题一个 package 是怎样被构建出来的它几乎都有同样的生命周期do_fetch▼下载源码▼do_unpack▼do_patch▼do_configure▼do_compile▼do_install▼do_package你会发现所有 recipe 基本都遵循这个流程。第三步BitBake 是怎么知道先编 busybox再生成 rootfs这时候看箭头。例如core-image-minimal.do_rootfs^busybox.do_package_write_ipk不同发行版可能是 rpm、deb、ipk。这说明busybox▼do_package▼包已经生成▼core-image-minimal.do_rootfs所以rootfs 不会直接编译 busybox。而是busybox.bb▼编译▼生成 package▼rootfs 安装 package这就是 Linux 发行版的思想。第四步为什么要有 native例如patch-nativepseudo-nativequilt-native再搜索patch-native.do_compile你会发现它们也有do_fetchdo_unpackdo_compile但是最后不会进入 rootfs。为什么因为Build PC ────────────── patch-native quilt-native pseudo-native这些程序是给 BitBake 自己用的。而不是Raspberry Pi ────────────── busybox bash systemd这是 Yocto 最重要的思想之一构建环境和目标环境是分开的。第五步学习依赖图而不是文件很多新人会犯一个错误去看 task-depends.dot 一共有多少万行。其实应该反过来。每次只回答一个问题。例如busybox 为什么会先编查busybox.do_compilerootfs 为什么等 busybox查core-image-minimal.do_rootfskernel 为什么先于 image查linux-raspberrypi.do_deployimage 为什么依赖 kernel查core-image-minimal.do_image这样学一个星期以后你就能看懂任何 BitBake 图。我建议我们做一个解剖实验不要再同时研究 236 个 recipe。我们只解剖 一个最重要的 recipebusybox.bb。它几乎包含了 BitBake 的所有核心机制busybox.bb▼inherit …▼do_fetch▼do_unpack▼do_patch▼do_configure▼do_compile▼do_install▼do_package在这个过程中我们还能顺便学习.bb 文件是怎么定义任务的inherit 到底做了什么do_compile 是谁提供的bitbake busybox -e 输出的变量从哪里来task-depends.dot 中这些任务是如何生成的**这条线比直接啃 Yocto 手册更容易建立完整的知识体系。**等真正理解了 busybox.bb 的生命周期再回头看 core-image-minimal整个 BitBake 的工作方式就会变得非常清晰。
返回列表