3、版本锁定策略:PREFERRED_VERSION的用法,强制指定特定版本,处理多版本共存问题
包依赖冲突,说白了就是「A要1.0,B要2.0,两边互不相让」。我在嵌入式项目里见过太多次这种场面了——编译到一半突然报错,说某个库版本不对,然后整个构建就卡在那里。嗯,这时候你就需要一把「锁」,把版本死死钉住。
Yocto 里这把锁,就是 PREFERRED_VERSION。
3.1 什么是 PREFERRED_VERSION?
它就是一个变量。你告诉 BitBake:「这个包,我就要这个版本,别的版本别给我乱来。」
语法很简单:
PREFERRED_VERSION_pkgname = "版本号"
举个例子:
PREFERRED_VERSION_openssl = "1.1.1"
这样,不管其他配方怎么依赖 openssl,BitBake 都只会选 1.1.1 这个版本。
核心要点:PREFERRED_VERSION 只影响「选择哪个配方」,不影响配方内部的构建逻辑。
3.2 什么时候需要用?
我个人习惯,在以下三种场景里一定会用:
- 安全补丁锁定——某个版本有已知漏洞,必须用打了补丁的特定版本
- ABI 兼容性——两个库必须用同一套 ABI 编译,否则链接时崩溃
- 多版本共存——系统里同时需要两个版本,比如 openssl 1.0 和 1.1
我在项目中遇到过最典型的情况:一个老旧的驱动模块只认 openssl 1.0,但新加的加密服务需要 openssl 1.1。两个版本都得留着,怎么办?
答案就是:用 PREFERRED_VERSION 分别指定。
3.3 多版本共存的实战配置
假设你的 layer 里有这两个配方:
openssl_1.0.2.bbopenssl_1.1.1.bb
在 local.conf 或 distro.conf 里这样写:
# 默认用 1.1.1
PREFERRED_VERSION_openssl = "1.1.1"
# 但某个老驱动需要 1.0.2
PREFERRED_VERSION_openssl:pn:old-driver = "1.0.2"
这里用了 :pn: 覆盖语法,意思是「只针对 old-driver 这个包,openssl 用 1.0.2」。其他包还是用 1.1.1。
小技巧:你可以用 bitbake -s | grep openssl 查看当前所有可用的 openssl 版本,以及哪个被选中了。
3.4 版本号匹配规则
版本号不是随便写的。Yocto 有一套自己的比较逻辑:
| 写法 | 含义 | 示例 |
|---|---|---|
1.1.1 |
精确匹配 | 只选 1.1.1 |
1.1.% |
通配符匹配 | 1.1.0、1.1.1、1.1.2 都行 |
1.1.1+git% |
匹配 git 版本 | 1.1.1+gitAUTOINC+abcdef1 |
我个人建议:尽量用精确匹配。通配符虽然方便,但容易引入意外版本。我曾经因为用了 1.1.%,结果新拉取的 1.1.3 改了 API,编译直接炸了。嗯,从那以后我再也不敢偷懒了。
3.5 优先级与冲突处理
如果多个地方都设置了 PREFERRED_VERSION,优先级是这样的:
local.conf中的设置(最高)distro.conf中的设置machine.conf中的设置- 配方自带的
DEFAULT_PREFERENCE(最低)
你想想看,如果 distro.conf 里锁了 openssl 1.1.1,但 local.conf 里又写了 1.0.2,那最终用的是 1.0.2。因为 local.conf 优先级最高。
注意:PREFERRED_VERSION 只解决「选哪个版本」的问题。如果两个版本在文件系统里冲突(比如都安装同一个路径),你还需要用 PACKAGE_PREPROCESS_FUNCS 或 ALTERNATIVE 机制来处理。
3.6 实战:用 SVG 图理解版本锁定流程
下面这张图,是我自己画的一个简化流程。你看一眼就明白了:
说白了,BitBake 拿到多个版本时,先看有没有 PREFERRED_VERSION。有,就听你的;没有,就按 DEFAULT_PREFERENCE 和版本号大小自己选。
3.7 避坑指南
我踩过几个坑,写出来给你提个醒:
- 版本号写错——比如写了
1.1.1但配方里实际是1.1.1-r0,匹配不上。用bitbake -s确认一下。 - 覆盖语法不对——
:pn:是硬覆盖,_是软覆盖。搞混了可能不生效。 - 忘记清理缓存——改了
PREFERRED_VERSION后,最好bitbake -c cleanall pkgname一下,否则旧版本可能还在 sstate 缓存里。
一句话总结:PREFERRED_VERSION 就是你的「版本保险丝」。用得好,冲突全消;用不好,编译报错。我个人建议,每个项目开始时就定好版本锁定策略,别等到冲突了再临时抱佛脚。