第4章:Recipe编写入门
好,咱们今天聊聊Recipe。这是Yocto里最基础、也最核心的东西。说白了,Recipe就是一份“菜谱”,告诉BitBake怎么把源码变成你想要的软件包。
我记得刚接触Yocto那会儿,看着一堆.bb文件,心里直犯嘀咕:这玩意儿到底怎么写的?后来摸爬滚打了一阵子,才慢慢摸出门道。今天我就把这点经验分享给你。
4.1 Recipe文件结构
一个典型的Recipe文件,其实没那么复杂。它主要由几部分组成:元数据、任务函数、还有各种变量。我习惯把它想象成一张“配料表+操作步骤”。
来看个最简单的例子:
DESCRIPTION = "一个简单的Hello World程序"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://LICENSE;md5=xxxx"
SRC_URI = "file://hello.c"
S = "${WORKDIR}"
do_compile() {
${CC} ${CFLAGS} ${LDFLAGS} hello.c -o hello
}
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}
}
你看,结构很清晰:
- 头部:描述、许可证、源码位置
- 源码获取:SRC_URI告诉系统去哪儿拿代码
- 编译任务:do_compile里写怎么编译
- 安装任务:do_install里写怎么装到目标系统
4.2 SRC_URI与源码获取
SRC_URI这个变量,可以说是Recipe的“命门”。它决定了你的源码从哪儿来。Yocto支持好几种方式:
| 协议 | 示例 | 说明 |
|---|---|---|
| file:// | file://hello.c | 本地文件,放在Recipe同目录或Files目录 |
| http:// | http://example.com/foo.tar.gz | 从网络下载 |
| git:// | git://github.com/user/repo.git | 从Git仓库拉取 |
| https:// | https://github.com/user/repo.git | HTTPS方式下载 |
这里有个坑,我得提醒你。用git://协议时,有些公司防火墙会拦。我遇到过好几次,明明代码在GitHub上,就是拉不下来。后来我统一改成https://,世界就清净了。
另外,SRC_URI还支持一些参数,比如:
SRC_URI = "git://github.com/user/repo.git;branch=main;protocol=https"
这里指定了分支和协议。我个人建议,能指定分支就指定,免得拉错代码。
4.3 do_compile与do_install
这两个任务,是Recipe的“灵魂”。do_compile负责编译,do_install负责安装。
do_compile:
默认情况下,Yocto会调用Makefile。但如果你没有Makefile,就得自己写编译命令。就像刚才那个例子:
do_compile() {
${CC} ${CFLAGS} ${LDFLAGS} hello.c -o hello
}
这里用了${CC}、${CFLAGS}这些变量。它们是由Yocto自动设置的,分别代表编译器、编译选项、链接选项。你想想看,如果硬编码gcc,那换ARM平台时怎么办?用变量就灵活多了。
do_install:
这个任务负责把编译好的文件装到目标目录。注意,这里的“安装”不是装到你电脑上,而是装到一个临时目录(${D}),最后打包成IPK或RPM。
do_install() {
install -d ${D}${bindir}
install -m 0755 hello ${D}${bindir}
}
install -d是创建目录,install -m是复制文件并设置权限。${bindir}通常就是/usr/bin。
4.4 常用变量
Yocto里变量多如牛毛,但常用的就那么几个。我列个表,你记一下:
| 变量名 | 含义 | 典型值 |
|---|---|---|
| ${WORKDIR} | 工作目录,所有操作都在这里进行 | /build/tmp/work/... |
| ${S} | 源码目录,默认等于${WORKDIR} | ${WORKDIR} |
| ${D} | 目标目录,安装时用 | ${WORKDIR}/image |
| ${bindir} | 二进制文件目录 | /usr/bin |
| ${libdir} | 库文件目录 | /usr/lib |
| ${sysconfdir} | 配置文件目录 | /etc |
| ${PN} | 包名,就是Recipe文件名去掉.bb | hello |
| ${PV} | 版本号 | 1.0 |
嗯,这里要特别说一下${S}。如果你的源码是tar.gz包,解压后可能有个子目录。比如你下载了foo-1.0.tar.gz,解压后是foo-1.0/目录。这时你得设置:
S = "${WORKDIR}/foo-1.0"
不然Yocto找不到源码,编译会失败。我刚开始就栽在这上面,折腾了好久才发现是S没设对。
4.5 一个完整的Recipe示例
说了这么多,咱们来个完整的例子。假设我们要写一个叫“myapp”的程序,从GitHub拉代码:
SUMMARY = "我的第一个Yocto应用"
DESCRIPTION = "这是一个用Yocto Recipe构建的示例程序"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://COPYING;md5=xxxx"
SRC_URI = "git://github.com/myuser/myapp.git;branch=main;protocol=https"
SRCREV = "a1b2c3d4e5f6..."
S = "${WORKDIR}/git"
inherit autotools
do_install_append() {
# 额外安装一个配置文件
install -d ${D}${sysconfdir}
install -m 0644 ${S}/myapp.conf ${D}${sysconfdir}/
}
这个例子用了inherit autotools,意思是继承autotools的编译流程。这样你就不用自己写do_compile了,autotools会自动处理configure、make、make install那一套。
好了,Recipe入门就讲这么多。说白了,Recipe就是告诉Yocto三件事:源码在哪儿、怎么编译、怎么安装。掌握了这个思路,后面再复杂的Recipe,你也能看懂。
下一章,咱们聊聊如何调试Recipe。写Recipe难免出错,学会调试能省不少时间。