第1课从零写第一个 hello-yocto.bb我们先做一个极简单的程序Hello Yocto!最终目标是摘要本教程手把手教你从零开始创建第一个 Yocto 自定义应用hello-yocto。你将学习如何创建自定义 layer 和 recipe理解关键变量如SRC_URI、S、WORKDIR、D、bindir以及do_compile和do_install任务并最终将应用打包进镜像在 Raspberry Pi 2 上运行。通过这个完整的流程你将掌握 Yocto 构建自定义软件包的核心概念和步骤。rootraspberrypi2:~# hello-yoctoHello Yocto!先不要碰 Poky 原始目录你的工程大概是~/yocto/ ├── poky/ └── build-rpi2/我们自己创建一个 layer# in ~/yocto/meta-myhello/ ├── conf/ │ └── layer.conf └── recipes-example/ └── hello-yocto/ ├── hello-yocto.bb └── hello.c这就是 Yocto 最基本的自定义 layer recipe 结构。执行cd~/yocto bitbake-layers create-layer meta-myhello然后bitbake-layers add-layer …/meta-myhello注意你现在是在~/yocto/build-rpi2里面所以bitbake-layers add-layer …/meta-myhello应该能看到类似NOTE: Adding layer../meta-myhello检查bitbake-layers show-layers应该出现meta meta-poky meta-yocto-bsp meta-raspberrypi meta-myhello2. 创建第一个 recipe进入cd ~/yocto/meta-myhello创建目录mkdir -p recipes-example/hello-yocto然后cd recipes-example/hello-yocto创建touchhello-yocto.bbtouchhello.c现在ls应该是hello-yocto.bb hello.c3. 先写 C 程序编辑nano hello.c写#includestdio.hintmain(void){printf(Hello Yocto!\n);return0;}这部分跟 Yocto 没什么关系。它就是普通 Linux C 程序。4. 第一版 hello-yocto.bb现在编辑nano hello-yocto.bb先写这一版SUMMARYA simple Hello Yocto programDESCRIPTIONThe first custom application built with YoctoLICENSEMITSRC_URIfile://hello.cS${WORKDIR}do_compile(){${CC}${CFLAGS}${LDFLAGS}hello.c-o hello-yocto}do_install(){install-d ${D}${bindir}install-m0755hello-yocto ${D}${bindir}/hello-yocto}这就是我们第一个真正自己写的 recipe。先别急着背。我们逐行拆。5. SUMMARYSUMMARYA simple Hello Yocto program这是 recipe 的简短说明。可以理解成PNhello-yocto SUMMARY这个东西是什么检查bitbake -e hello-yocto | grep ‘^SUMMARY’应该看到SUMMARY“A simple Hello Yocto program”DESCRIPTIONDESCRIPTION第一个使用 Yocto 构建的自定义应用程序比 SUMMARY 更详细。你可以把它理解成SUMMARY 一句话简介 DESCRIPTION 更完整的说明LICENSEfiles/ ├── hello.c └── LICENSEcd~/yocto/meta-myhello/recipes-example/hello-yoctocatfiles/LICENSEEOF MIT License Copyright (c) 2026 Yocto Learning Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. EOF自己计算 checksum~/yocto/meta-myhello/recipes-example/hello-yocto md5sum files/LICENSE 例如会得到 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx files/LICENSE把前面的 32 位字符串复制过来。LICENSEMITLICENSEMITLIC_FILES_CHKSUMfile://LICENSE;md5f4fa7fd56aac72279ad21a112915ca87SRC_URIfile://hello.c \ file://LICENSE这里不是说Yocto 必须使用 MIT。而是在告诉 Yocto这个 recipe 所构建的软件采用什么许可证。我们这个练习程序用 MIT 最简单。但是这里马上会产生一个问题既然说 LICENSE 是 MIT那么 MIT license 文件在哪里严格来说真正规范的 recipe 还应该提供 LIC_FILES_CHKSUM。我们第一版先把重点放在 recipe 的执行机制上。后面我们会专门学习LICENSE LIC_FILES_CHKSUM8. SRC_URI这是非常重要的一行SRC_URI “file://hello.c”意思是我的 source 不需要从网络下载它就在 recipe 的 files/ 搜索路径里。但是这里有个问题。我们现在hello-yocto/ ├── hello-yocto.bb └── hello.c而传统 recipe 通常写成hello-yocto/ ├── hello-yocto.bb └── files/ └── hello.c所以我们现在把 hello.c 移进去mkdirfilesmvhello.c files/最终hello-yocto/ ├── hello-yocto.bb └── files/ └── hello.c这时候SRC_URI “file://hello.c”就非常直观SRC_URI └── file://hello.c ↓ recipes-example/hello-yocto/files/hello.c9. S “${WORKDIR}”这一句非常值得理解S “${WORKDIR}”S 表示Source directory也就是源代码实际展开以后所在的目录。例如 BitBake 工作目录可能类似tmp/work/ └── arm1176jzfshf-vfp-poky-linux-gnueabi/ └── hello-yocto/ └──1.0/ ├── hello.c └──...${WORKDIR}就是 recipe 当前的工作目录。由于我们的源码非常简单hello.c没有hello-1.0/这种 source tree所以S ${WORKDIR}就够了。10. do_compile现在来到真正有意思的地方do_compile(){${CC}${CFLAGS}${LDFLAGS}hello.c-o hello-yocto}这是我们自己定义的 taskdo_compile也就是说BitBake ↓ 执行 do_compile ↓ 调用${CC}↓ 编译 hello.c ↓ 得到 hello-yocto10. do_compile现在来到真正有意思的地方do_compile(){${CC}${CFLAGS}${LDFLAGS}hello.c-o hello-yocto}这是我们自己定义的 taskdo_compile也就是说BitBake ↓ 执行 do_compile ↓ 调用${CC}↓ 编译 hello.c ↓ 得到 hello-yocto${CC}非常重要。它不是简单写死gcc而是${CC}因为 Yocto 是交叉编译系统。你的 build machine 是x86_64 Linux目标机是Raspberry Pi2ARM所以这里实际使用的是x86_64host│ │ cross compiler ↓ ARM executable这就是为什么不能简单gcc hello.c11. do_install再看do_install(){install-d${D}${bindir}install-m0755 hello-yocto${D}${bindir}/hello-yocto}这一段是 Yocto 学习中极其重要的一步。先看第一句install -dD {D}D{bindir}${bindir} 通常是/usr/bin而 ${D} 是安装 staging 的目标根目录。所以最终类似D {D}D{bindir}变成/work/…/image/usr/bin注意不是直接安装到你现在电脑的 /usr/bin。而是${D}└── usr/ └── bin/ └── hello-yocto这正是 Yocto 的 packaging 思维。12. 为什么不能写成 /usr/bin千万不要写do_install(){install-m0755hello-yocto/usr/bin/hello-yocto}因为那是在碰 build host 的 /usr/bin。正确的是D {D}D{bindir}/hello-yocto你应该牢牢记住${D}就是 recipe 的安装临时根目录 / DESTDIR可以把整个过程想象成真正目标 rootfs / ├── bin ├── etc ├── usr │ └── bin │ └── hello-yocto └──... ↑${D}临时模拟 /13. 现在第一次运行 BitBake回到 buildcd ~/yocto/build-rpi2先不要 build。先问 BitBakebitbake -e hello-yocto | grep ‘^PN’应该PN“hello-yocto”再bitbake -e hello-yocto | grep ‘^PV’因为我们没写版本所以会有默认版本。PV“1.0”然后bitbake -c listtasks hello-yocto你应该能看到do_compile do_install do_package do_package_qa…这时你就可以把之前学的 BusyBox 联系起来了hello-yocto.bb ↓ BitBake metadata ↓ tasks ├── do_fetch ├── do_unpack ├── do_patch ├── do_configure ├── do_compile ← 我们写了 ├── do_install ← 我们写了 ├── do_package └──...第一次真正 build执行bitbake hello-yocto如果成功你会看到类似NOTE: Tasks Summary: Attempted … tasks of which … didn’t need to be rerun and all succeeded.这时候不要满足于“编译成功了。”我们马上进入解剖阶段。cxiccyocto:~/yocto/build-rpi2$ bitbake-ehello-yocto|grep-E^(PN|PV|PR|WORKDIR|S|B|D|bindir)B/home/cxicc/yocto/build-rpi2/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello-yocto/1.0D/home/cxicc/yocto/build-rpi2/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello-yocto/1.0/imagePNhello-yoctoPRr0PV1.0S/home/cxicc/yocto/build-rpi2/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello-yocto/1.0WORKDIR/home/cxicc/yocto/build-rpi2/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/hello-yocto/1.015. 看 BitBake 到底把东西放哪里执行bitbake -e hello-yocto | grep ‘^WORKDIR’例如WORKDIR“/home/cxicc/yocto/build-rpi2/tmp/work/…”然后bitbake -e hello-yocto | grep ‘^S’你会发现S“…/hello-yocto/…”再bitbake -e hello-yocto | grep ‘^D’然后进入cd “$(bitbake -e hello-yocto | sed -n s/WORKDIR([”]*)“/\1/p’)”看看find . -maxdepth 3 -type f你会看到 BitBake 实际生成的东西。16. 最关键看 do_install 的结果执行bitbake -e hello-yocto | grep ‘^D’假设得到D“/home/cxicc/yocto/build-rpi2/tmp/work/…/hello-yocto/…/image”那么find “$D” -type f应该看到…/image/usr/bin/hello-yocto这时候整个逻辑就非常清楚了hello.c │ do_compile ↓ hello-yocto │ do_install ↓${D}/usr/bin/hello-yocto │ do_package ↓ package ↓ rootfs ↓ Raspberry Pi17. 现在不要直接修改 image还有一个重要区别。现在bitbake hello-yocto只代表recipe 被成功构建。并不代表hello-yocto已经进入core-image-minimal所以你现在执行bitbake core-image-minimal然后烧 SD 卡进入 Pi hello-yocto很可能得到-sh: hello-yocto: not found这是正常的。因为构建 package和把 package 放进 image是两个不同概念。18. 把 hello-yocto 放进 image打开nano~/yocto/build-rpi2/conf/local.conf加入IMAGE_INSTALL:append hello-yocto注意前面的空格IMAGE_INSTALL:append hello-yocto↑ 有空格然后bitbake core-image-minimal重新生成镜像。bunzip2 -k tmp/deploy/images/raspberrypi2/core-image-minimal-raspberrypi2.rootfs-20260729080920.wic.bz2烧到 SD 卡。sudo ddiftmp/deploy/images/raspberrypi2/core-image-minimal-raspberrypi2.rootfs.wicof/dev/sdbbs4Mstatusprogressconvfsyncsync启动 Raspberry Pi。SSHssh rootPI_IP执行which hello-yocto应该/usr/bin/hello-yocto然后hello-yocto得到Hello Yocto!这就是你的第一个完整 Yocto application。现在我们把整个过程画成一张图你现在真正应该理解的是这个20. 这次你真正学到的不是 C 程序这次最重要的是下面 5 个变量/概念尤其是SRC_URI S D bindir这几个以后会反复出现。21. 下一步不要急着写第二个 recipe按照你之前学习 BusyBox 的方式我建议我们接下来直接解剖这个刚刚写好的 recipe。下一课可以做02hello-yocto.bb 到底是怎么被 BitBake 执行的我们专门做这几个实验bitbake-cfetch hello-yocto bitbake-cunpack hello-yocto bitbake-ccompile hello-yocto bitbake-cinstallhello-yocto然后逐个观察WORKDIR S B D以及bitbake -e hello-yocto去找出 BitBake 最终执行的真实 do_compile() 和 do_install()。这样就能把你前面学的busybox.bb ↓ BitBake metadata ↓ task ↓ 真实执行体和我们自己写的hello-yocto.bb完全连起来。这会是你从“会使用 Yocto”进入“真正理解 BitBake”的关键一步。22. hello-yocto 文件类型cxiccyocto:~/Downloads$ file hello.shhello.sh: POSIX shell script, ASCII text executablecxiccyocto:~/Downloads$ file hello-yoctohello-yocto: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]df86731d4e89eee5b97dd80c60541165aeecf29e, for GNU/Linux 5.15.0, strippedVM Network Bridge Fz ssh connect to Yocto host