Recipe深度解剖:Recipe文件结构、SRC_URI、DEPENDS、do_compile、do_install等核心任务
各位同学,今天我们来聊聊Recipe。说白了,Recipe就是Yocto项目的“灵魂”。你想想看,一个嵌入式系统里那么多软件包,怎么编译?怎么安装?怎么打包?全靠这个小小的.bb文件来指挥。
我记得刚接触Yocto那会儿,打开一个Recipe文件,看到一堆变量和函数,说实话有点懵。但后来做多了就发现,它的结构其实非常清晰。今天我就带大家把Recipe的骨架拆开,看看里面到底装了些什么。
Recipe文件的基本结构
一个标准的Recipe文件,通常长这样:
DESCRIPTION = "这是一个示例驱动"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://COPYING;md5=xxx"
SRC_URI = "file://mydriver.c \
file://Makefile \
file://0001-fix-bug.patch"
DEPENDS = "virtual/kernel"
S = "${WORKDIR}"
inherit module
do_compile() {
oe_runmake
}
do_install() {
install -d ${D}${base_libdir}/modules/${KERNEL_VERSION}/extra
install -m 0644 ${S}/mydriver.ko ${D}${base_libdir}/modules/${KERNEL_VERSION}/extra/
}
嗯,看着是不是有点眼熟?其实Recipe就是一段BitBake能理解的脚本。它告诉系统:你要从哪里拿源码、依赖谁、怎么编译、装到哪里去。
SRC_URI:源码从哪里来
SRC_URI这个变量,我习惯叫它“资源定位器”。它告诉BitBake去哪里拿源码。可以是本地文件、Git仓库、HTTP下载,甚至是补丁文件。
| 协议类型 | 示例 | 说明 |
|---|---|---|
| file:// | file://mydriver.c | 本地文件,放在Files目录下 |
| git:// | git://github.com/xxx/driver.git | Git仓库 |
| http:// | http://example.com/source.tar.gz | HTTP下载 |
| ftp:// | ftp://server.com/package.tar.bz2 | FTP下载 |
DEPENDS:依赖关系管理
DEPENDS这个变量,说白了就是告诉系统:“我编译之前,你得先把这些东西准备好”。对于驱动开发来说,最常见的依赖就是virtual/kernel。
为什么会这样?因为驱动要调用内核的头文件和API。没有内核源码,驱动根本编译不过去。
DEPENDS = "virtual/kernel"
# 或者更具体一点
DEPENDS = "linux-yocto"
do_compile:编译的核心战场
do_compile这个任务,是Recipe里最核心的部分。默认情况下,BitBake会执行oe_runmake,但很多时候我们需要自定义。
我个人习惯这样写:
do_compile() {
# 先清理一下
make clean
# 传入内核构建目录
oe_runmake KERNEL_SRC=${STAGING_KERNEL_DIR} \
KERNEL_PATH=${STAGING_KERNEL_DIR} \
CC="${KERNEL_CC}" \
LD="${KERNEL_LD}"
}
这里有几个关键变量:
- STAGING_KERNEL_DIR:内核源码的暂存目录
- KERNEL_CC:内核用的交叉编译器
- KERNEL_LD:内核用的链接器
我记得有一次,一个同事直接用了系统的gcc来编译驱动,结果在目标板上加载时报错“invalid module format”。嗯,这就是典型的编译器和内核不匹配的问题。
do_install:安装的艺术
编译完了,东西放哪?这就是do_install的任务。对于驱动来说,通常要安装到内核模块目录下。
do_install() {
# 创建目标目录
install -d ${D}${base_libdir}/modules/${KERNEL_VERSION}/extra
# 安装驱动模块
install -m 0644 ${B}/mydriver.ko \
${D}${base_libdir}/modules/${KERNEL_VERSION}/extra/
# 如果有配置文件,也一并安装
if [ -f ${S}/mydriver.conf ]; then
install -d ${D}${sysconfdir}/modprobe.d
install -m 0644 ${S}/mydriver.conf \
${D}${sysconfdir}/modprobe.d/
fi
}
知识体系总览
下面这张图,是我自己总结的Recipe核心逻辑。你看一眼就能明白整个流程:
避坑指南
最后,我分享几个实战中踩过的坑:
- SRC_URI路径问题:我曾经把file://写成http://,结果BitBake一直尝试联网下载,等了半天超时报错。
- DEPENDS循环依赖:A依赖B,B依赖A,BitBake直接罢工。解决办法是拆包或者用PACKAGE_CONFIG。
- do_install权限问题:驱动模块一定要用0644权限,可执行权限会导致内核拒绝加载。
- KERNEL_VERSION不匹配:编译时用的内核版本和运行时不一致,模块加载会报错。建议在Recipe里加个检查。
好了,Recipe的核心内容就这些。你想想看,其实Recipe没那么神秘,就是告诉系统:源码在哪、依赖谁、怎么编译、装到哪。把这四件事搞清楚了,写Recipe就跟喝水一样简单。