4 高级内核概念
4 Yocto Project 内核开发与维护
Yocto Project 提供的内核,即 Yocto Linux 内核,与其他内核一样,基于
https://www.kernel.org 发布的 Linux 内核。在一个主要内核开发周期开始时,
团队会根据发行时间、上游最终版本的预计发布时间和项目功能要求等因素选择
基线内核。通常,该内核处于 Linux 社区开发的最后阶段,即候选发布(rc)
阶段,尚未正式发布。此时团队能够确定,kernel.org 的最终版本会在
Yocto Project 开发窗口的早期发布。
这种平衡让团队尽可能提供最新的 Yocto Linux 内核,同时确保基线内核有 稳定的官方发行版本。
Yocto Linux 内核最终来源于 kernel.org 已发布内核。在此基础上,还会
结合重要的主线新进展、没有替代方案时的非主线开发、板级支持包(BSP)开发
以及自定义功能,形成面向商业发布的 Yocto Project Linux 内核,满足嵌入式
设计者对目标硬件的具体需求。
可在 https://git.yoctoproject.org/ 的 Yocto Project 源码仓库 中找到内核 Web 界面。左侧 "Yocto Linux Kernel" 分组包含为 Yocto Project 发行版开发的多个内核:
linux-yocto-4.1: 用于 Yocto Project 2.0 的稳定内核,基于 Linux 4.1。
linux-yocto-4.4: 用于 Yocto Project 2.1 的稳定内核,基于 Linux 4.4。
linux-yocto-4.6: 不绑定任何 Yocto Project 发行版的临时内核。
linux-yocto-4.8: 用于 Yocto Project 2.2 的稳定内核。
linux-yocto-4.9: 用于 Yocto Project 2.3 的稳定内核,基于 Linux 4.9。
linux-yocto-4.10: 用于 Yocto Project 2.3 的默认稳定内核,基于 Linux 4.10。
linux-yocto-4.12: 用于 Yocto Project 2.4 的默认稳定内核,基于 Linux 4.12。
yocto-kernel-cache:
linux-yocto-cache保存 linux-yocto 内核树的 补丁和配置,开发时很有用。关于这些高级内核元数据,见 “使用高级元数据(yocto-kernel-cache)” 一章。linux-yocto-dev: 基于最新可用上游候选版本的开发内核。
Yocto Linux 内核正式发布后,团队一边继续维护它,一边进入下一开发周期, 也称版本升级(uprev)周期。通过内核版本升级吸收上游功能,是最可持续、最 稳定的方式。从不同内核版本向后移植数百个独立修复和小功能不可持续,也很 容易损害质量。
升级周期中,团队持续分析 Linux 内核开发、BSP 支持和发布时间,选择最合适
的 kernel.org 版本作为后续开发基础,并不断关注社区的重要新功能。
如果大型功能具有显著优势,也会考虑向后移植。用户或社区需求同样可能促使
团队在升级周期中将功能向后移植到基线内核,或创建新功能。
通常,新内核既添加功能,也引入新缺陷。这是上游开发的基本特性,由团队的 内核开发策略加以管理。团队不向已发布的 Yocto Linux 内核移植小功能,只在 完整差距分析后考虑重大技术进步。原因是,从持续演进的内核移植任何中小规模 变更,都容易造成不匹配、不兼容和细微错误。
这些策略形成兼顾稳定与前沿的内核,既向前移植已有功能,也集成重要且关键的 新能力。将 Linux 内核功能移植到 Yocto Linux 内核可视为“微型升级”。多次 微型升级把主线、非主线、BSP 和功能集成的重要进展组合起来,使团队提前了解 新功能并进行有针对性的测试,避免选择下次主要升级时出现意外。这些前沿内核 的质量持续演进,用于最新功能和 BSP 开发。
4 Yocto Linux 内核架构与分支策略
Yocto Project 的重要目标之一,是为开发者提供历史清晰、连续且可见的内核。
所用架构和机制,特别是分支策略,与 kernel.org 的上游开发方式类似。
可以把 Yocto Linux 内核看作基线 Linux 内核,加上在其上按逻辑组织的功能。 团队通过 Git 源码管理系统的分支策略,对这些功能组织和打标签。
备注
Git 很适合本节所述的内核组织目标。它不仅是
kernel.org使用的 源码管理系统,而且日益普及,支持多种工作流程、前端和管理方式。Git 文档见 https://git-scm.com/doc。针对 Yocto Project 的入门介绍见 概述与概念手册的 “Git”。 后者概述 Git,并提供能够开展工作的最小命令集。按项目需求选择使用 Git 的功能即可,无需成为专家。
团队利用 Git 的标签和分支,在功能不再共享、需要隔离的位置创建内核分支。 例如,开发板间的不兼容需要不同功能,就用分支分离;特定内核功能也采用 相同策略。
这种树形架构把功能组织为特定用途、单个内核类型或一组内核类型所需的部分。 用户既可以查看新增功能及其提交,也可以查看基线 Linux 内核的历史。
这种策略还避免在树内重复保存同一功能,只需保存将功能应用到不同内核类型 所需的独特差异。
备注
团队尽量将功能放在所有适用开发板和内核类型都能共享的位置。不过,在 开发周期中或合并大型功能时未必总能做到,此时会使用独立分支合并功能。
BSP 专用代码的处理与内核专用功能类似。有些 BSP 只适合特定内核类型,因此 团队从该类型末尾为所有受支持 BSP 创建分支。在创建 BSP 分支的工具看来, BSP 与普通功能没有本质差异,采用相同分支策略。因此,也无需重复保存 BSP, 只保存它在多个受支持内核间的独特差异。
虽然这种策略可能产生大量分支,但从开发者角度看,存在一条从基线
kernel.org 经选定功能、最终到达 BSP 专用提交的线性路径。内核内部划分
对日常开发是透明的,这条路径就是开发分支,开发者无需知道其他分支。需要
探索时,保留这些分支又很有价值,例如比较两个 BSP 的提交或逐行代码
diff 会非常简单。
下图展示 Yocto Linux 内核的概念结构。
图中的 "Kernel.org Branch Point" 标明创建 Yocto Linux 内核的具体分支点, 也就是基线 Linux 发行版。从这里开始,功能和差异被组织并打标签。
"Yocto Project Baseline Kernel" 包含后续所有内核类型和 BSP 共有的功能。 这样组织后,无需在各分支重复保存公共功能。
基线内核之后的分支点表示各 BSP 和实时内核的特定功能。图中用三个 BSP 分支和一个实时内核分支演示,各自代表相应 BSP 或实时内核的独有能力。
示例中的 "Real-time (rt) Kernel" 分支包含所有实时 Yocto Linux 内核的 公共功能,并进一步派生 BSP 专用实时内核分支。图中展示三个这样的分支, 各自指向适合对应 BSP 的实时内核特定功能。
最终树形结构为开发者提供清晰的标记或分支路径,实际对应满足某组需求的 Yocto Linux 内核。
备注
此图仅用一个通用内核解释概念,没有包含全部受支持内核。该结构代表 Yocto Project 源码仓库, 构建时从中拉取,或在构建前通过克隆特定内核 Git 仓库、下载并解包归档 文件,将其建立在开发主机上。
以结构化源码树处理内核符合社区公认实践。产品附带内核应视为“上游源码”, 由一系列有历史记录和文档说明的提交组成,代表 Yocto Project 内核团队完成 的开发和稳定化工作。
提交仅在产品生命周期的重要发布点变化,因此开发者可以从已发布内核的最后 相关提交建立分支。克隆并构建内核后,源码树就处于这一状态,所以结构对 开发者透明。
4 内核构建文件层级
上游保存全部内核源码,与在开发主机上表示和使用这些代码是两回事。内核源码 仓库概念上包含所有受支持 Yocto Linux 内核所需文件,而开发者只关心自己 正在处理的那个内核,并需要在主机上访问这些文件。
在主机上获取内核源码有几种方式:
通过 devtool 访问: Yocto Project 提供的
devtool是修改内核的 首选方式,见 “内核修改流程”。克隆仓库: 如果经常进行内核开发,通常应建立本地 Yocto Linux 内核 Git 仓库。方法见 “准备内核开发构建主机”。
使用构建产生的临时源码: 如果只想采用传统 BitBake 流程,不用
devtool,为内核制作少量补丁,可以访问构建时提取并使用的临时源码。
BitBake 构建产生的临时内核源码具有特定层级。构建时,系统从 SRC_URI 指向的仓库获取全部所需文件,汇集到临时工作区,再创建特定内核。从这个意义 上说,该过程构造了一棵专用于当前内核的本地源码树,用来生成新内核镜像。
下图展示使用 BitBake 构建内核时在主机上创建的临时文件结构。此 Build Directory 包含构建使用的全部源文件。
架构和分支策略的更多信息见 “Yocto Linux 内核架构与分支策略”。 修改内核的详细示例见 “使用 devtool 修补内核” 和 “使用传统内核开发流程修补内核”。
4 在内核配置审计阶段区分硬件与非硬件功能
本节介绍内核配置审计的一部分,大多数开发者可以忽略。关于 menuconfig、
defconfig 和配置片段等一般信息,见
“配置内核”。
审计的这一阶段会将最终 .config 与系统指定的片段比较。片段可能来自
系统、发行版或用户。不论来源如何,如果特定选项没有进入最终内核配置,
OpenEmbedded 构建系统都会警告。
为避免过多配置警告,默认只报告缺失的“硬件”选项,因为它们可能导致启动 失败,或表明重要硬件不可用。
为区分选项是否属于硬件,yocto-kernel-cache 的内核元数据包含将单个
选项或整组选项归类的文件。例如,假设有以下文件:
yocto-kernel-cache/features/drm-psb/hardware.cfg
yocto-kernel-cache/features/kgdb/hardware.cfg
yocto-kernel-cache/ktypes/base/hardware.cfg
yocto-kernel-cache/bsp/mti-malta32/hardware.cfg
yocto-kernel-cache/bsp/qemu-ppc32/hardware.cfg
yocto-kernel-cache/bsp/qemuarma9/hardware.cfg
yocto-kernel-cache/bsp/mti-malta64/hardware.cfg
yocto-kernel-cache/bsp/arm-versatile-926ejs/hardware.cfg
yocto-kernel-cache/bsp/common-pc/hardware.cfg
yocto-kernel-cache/bsp/common-pc-64/hardware.cfg
yocto-kernel-cache/features/rfkill/non-hardware.cfg
yocto-kernel-cache/ktypes/base/non-hardware.cfg
yocto-kernel-cache/features/aufs/non-hardware.kcf
yocto-kernel-cache/features/ocf/non-hardware.kcf
yocto-kernel-cache/ktypes/base/non-hardware.kcf
yocto-kernel-cache/ktypes/base/hardware.kcf
yocto-kernel-cache/bsp/qemu-ppc32/hardware.kcf
各文件的含义如下:
hardware.kcf:列出仅包含硬件选项的内核 Kconfig 文件。non-hardware.kcf:列出仅包含非硬件选项的内核 Kconfig 文件。hardware.cfg:列出属于硬件的CONFIG_选项,不受其所在 Kconfig 是否被hardware.kcf或non-hardware.kcf分类的影响。non-hardware.cfg:列出不属于硬件的CONFIG_选项,不受其所在 Kconfig 是否被hardware.kcf或non-hardware.kcf分类的影响。
以下是 kernel-cache/bsp/mti-malta32/hardware.cfg 的具体示例:
CONFIG_SERIAL_8250
CONFIG_SERIAL_8250_CONSOLE
CONFIG_SERIAL_8250_NR_UARTS
CONFIG_SERIAL_8250_PCI
CONFIG_SERIAL_CORE
CONFIG_SERIAL_CORE_CONSOLE
CONFIG_VGA_ARB
内核配置审计会自动检测这些文件,因此名称必须与上述完全一致,并将其作为
生成最终 .config 警告的输入。
用户指定的内核元数据仓库或配方空间功能,也可使用这些文件,将 .cfg
中的选项归为硬件或非硬件,避免选项没有进入最终 .config 时产生错误
或警告。