第4章:Recipe编写入门
好,咱们今天聊聊Recipe怎么写。说实话,很多刚接触Yocto的朋友,第一反应就是——这玩意儿不就是个菜谱吗?嗯,你还真说对了。Recipe就是告诉BitBake怎么把源代码变成你想要的软件包。我最早写Recipe的时候,也踩过不少坑,今天就把这些经验分享给你。
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}
}
你看,是不是很直观?每个部分各司其职。我在项目中见过有人把几百行的Recipe写得乱七八糟,其实完全没必要。保持结构清晰,后面维护起来才省心。
4.2 LICENSE与LIC_FILES_CHKSUM
许可证这块,很多人容易忽略。但我要说,这恰恰是最容易出问题的地方。
LICENSE:声明你的软件使用什么许可证。常见的比如MIT、GPLv2、Apache-2.0等。如果你用了多个许可证,可以用竖线(|)或与号(&)组合:
LICENSE = "GPLv2 & MIT"
LIC_FILES_CHKSUM:这个更关键。它告诉BitBake去检查许可证文件的校验和。为什么要这么做?说白了,就是防止有人偷偷改了许可证内容,你还没发现。
格式是这样的:
LIC_FILES_CHKSUM = "file://LICENSE;md5=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
如果你有多个许可证文件,可以这样写:
LIC_FILES_CHKSUM = "file://LICENSE;md5=xxx \
file://COPYING;md5=yyy"
4.3 SRC_URI详解
SRC_URI,说白了就是告诉BitBake:你的源代码在哪儿。这个变量非常灵活,支持多种协议。
| 协议 | 示例 | 说明 |
|---|---|---|
| 本地文件 | file://hello.c | 从本地meta层获取 |
| HTTP/HTTPS | https://example.com/source.tar.gz | 从网络下载 |
| Git | git://github.com/user/repo.git | 从Git仓库克隆 |
| SVN | svn://example.com/repo | 从SVN仓库获取 |
我个人最常用的是Git协议。但要注意,Git仓库需要指定分支和提交ID:
SRC_URI = "git://github.com/user/hello.git;branch=main;protocol=https"
SRCREV = "a1b2c3d4e5f6..."
SRC_URI还有一些常用参数:
- branch:指定分支
- protocol:指定协议(https、ssh等)
- subdir:解压到子目录
- name:给这个源起个名字,方便引用
4.4 do_compile与do_install
这两个任务是Recipe的核心。你想想看,编译和安装,不就是构建软件包的两个关键步骤吗?
do_compile:负责编译源代码。默认情况下,BitBake会执行make。但如果你用的是其他构建系统,就需要自己写:
do_compile() {
# 对于CMake项目
cmake ${S}
make
# 或者对于简单的C程序
${CC} ${CFLAGS} ${LDFLAGS} main.c -o myapp
}
do_install:负责把编译好的文件安装到目标目录。注意,这里的安装不是装到你的开发机上,而是装到一个临时目录(${D}),后面打包时会用到:
do_install() {
# 创建必要的目录
install -d ${D}${bindir}
install -d ${D}${sysconfdir}
# 安装二进制文件
install -m 0755 myapp ${D}${bindir}
# 安装配置文件
install -m 0644 myapp.conf ${D}${sysconfdir}
}
避坑指南:我曾经犯过一个错误——在do_install里直接写死了路径,比如/usr/bin。结果换了个架构,路径就变了。记住,永远使用${D}、${bindir}这些变量,不要写死路径。
4.5 常用变量:PN、PV、PR
这三个变量,你几乎在每个Recipe里都会见到。它们构成了软件包的基本标识。
| 变量 | 含义 | 示例 |
|---|---|---|
| PN | 包名(Package Name) | hello-world |
| PV | 包版本(Package Version) | 1.0.0 |
| PR | 包修订号(Package Revision) | r0 |
PN:通常由Recipe文件名决定。比如hello-world_1.0.0.bb,PN就是hello-world。当然,你也可以在Recipe里显式设置:
PN = "my-hello"
PV:版本号。同样可以从文件名推断,也可以手动指定:
PV = "2.0.1"
PR:这个变量很多人容易忽略。它用来表示Recipe本身的修订次数。比如你改了Recipe的编译选项,但软件版本没变,这时候就应该增加PR:
PR = "r1"
我的习惯:每次修改Recipe的逻辑(不是软件版本升级),我都会把PR加1。这样BitBake就知道这个包需要重新构建了。否则,你改了Recipe但PR没变,BitBake可能认为包已经是最新的,不会重新编译。
这三个变量组合起来,就构成了一个唯一的包标识:${PN}-${PV}-${PR}。比如hello-world-1.0.0-r0。在部署和版本管理时,这个标识非常有用。
小结
嗯,Recipe编写入门就讲到这里。说白了,Recipe就是告诉Yocto怎么把你的代码变成可运行的软件包。LICENSE和LIC_FILES_CHKSUM是法律保障,SRC_URI是源码来源,do_compile和do_install是核心构建逻辑,PN、PV、PR是版本标识。把这几个点搞清楚了,写Recipe就不是什么难事。
下一章,我们会深入聊聊依赖管理。到时候你会发现,Recipe之间的依赖关系,其实比你想的要复杂得多。