4. 编译框架解析:hb工具、build.sh与产品配置

编译框架这东西,说白了就是一套“搭积木”的规则。你写好了代码,怎么把它变成能烧录的镜像?OpenHarmony 的编译系统,我刚开始接触时也觉得挺绕的。但摸清楚之后,你会发现它其实很清晰。

今天我们就把它拆开来看。核心就三块:hb 工具(你敲的命令)、build.sh(背后的脚本)、产品配置与 BoardConfig(告诉系统你要给谁编译)。

4.1 hb 工具:你与编译系统的对话窗口

hb 是 OpenHarmony 的编译入口命令。你想想看,一个项目有成百上千个模块,总不能每次都手动调用编译器吧?hb 就是那个帮你打理一切的管家。

它的工作流程其实很简单:

  1. 解析你给的参数(比如 hb build -f)
  2. 读取产品配置(你要编译哪个开发板?)
  3. 调用 GN + Ninja 完成真正的编译

核心命令速查表

命令 作用 我常用的场景
hb set 选择产品与编译目标 第一次搭建环境时必用
hb build 执行编译 日常开发,加 -f 全量编译
hb build -T <target> 编译指定模块 只改了一个驱动,不想等全量编译
hb clean 清理编译产物 遇到奇怪错误时,先 clean 再 build

小技巧:我个人习惯在项目根目录下直接敲 hb set,它会弹出一个交互式菜单让你选产品。但如果你在 CI 环境里,可以用 hb set --product rk3568 直接指定,省去交互步骤。

4.2 build.sh 脚本分析:别被它吓到

很多人一打开 build.sh 就头大,几百行 shell 脚本。其实它就是个“包装器”。

我拆解一下它的核心逻辑:

  • 环境检查:看看 Python、GN、Ninja 装没装,版本对不对。
  • 参数转发:你传进来的 --product-name、--target-cpu 等参数,它原封不动传给 hb。
  • 调用 hb:最后一行核心代码,其实就是 python3 build/hb/main.py 加上你传的参数。

我曾经遇到一个问题:在 Docker 里编译,build.sh 报错说找不到 Python。查了半天,发现是脚本里写死了 python,但 Docker 镜像里只有 python3。改一下软链接就好了。嗯,这种环境问题最坑人。

避坑指南:不要直接修改 build.sh 本身!如果你需要定制编译流程,建议在 ohos_config.json 或产品配置里做文章。我曾经为了加一个编译参数直接改了 build.sh,结果下次 repo sync 时被覆盖了,排查了半天。

4.3 产品配置与 BoardConfig:告诉系统你是谁

这是编译系统里最核心的部分。你想想看,编译系统怎么知道你要给 rk3568 编译,还是给 hi3516 编译?答案就在产品配置里。

产品配置通常放在 vendor/<厂商>/<产品名>/ 目录下。核心文件有两个:

文件 作用 关键内容
config.json 产品级配置 产品名称、版本、子系统列表、组件列表
BoardConfig.mk 板级配置 CPU 架构、内存布局、Bootloader 参数、串口配置

我举个例子,这是 rk3568 的 config.json 片段:

{
  "product_name": "rk3568",
  "version": "3.0",
  "subsystems": [
    {
      "subsystem": "kernel",
      "components": [
        { "component": "linux-5.10", "features": [] }
      ]
    },
    {
      "subsystem": "graphic",
      "components": [
        { "component": "graphic_standard", "features": [] }
      ]
    }
  ]
}

而 BoardConfig.mk 里,你会看到类似这样的内容:

# 芯片架构
TARGET_ARCH := arm64
TARGET_CPU := cortex-a55

# 内存配置
BOARD_KERNEL_BASE := 0x00200000
BOARD_KERNEL_OFFSET := 0x00080000

# 串口调试
BOARD_UART_PORT := 2
BOARD_UART_BAUDRATE := 1500000

关键理解:config.json 决定“我要编译哪些功能模块”,BoardConfig.mk 决定“这些模块在硬件上怎么跑”。两者缺一不可。

4.4 编译目标选择:别每次都全量编译

很多新手一上来就 hb build -f,然后去喝杯咖啡等半小时。其实大部分时候你不需要全量编译。

编译目标的选择,我总结为三个层次:

  • 全量编译:hb build -f,第一次编译或大版本升级时用。
  • 增量编译:直接 hb build,只编译修改过的文件。日常开发首选。
  • 单模块编译:hb build -T <模块名>,只编译你关心的那个模块。比如你只改了图形驱动,就只编 graphic 子系统。

怎么知道模块名叫什么?我教你一个办法:

# 查看所有可编译的模块
hb build -T list

它会列出一大串名字,找到你需要的那个就行。

我的习惯:调试驱动时,我会先 hb build -T kernel 确认内核能编过,再 hb build -T my_driver 单独编驱动模块。这样每次编译不超过 2 分钟,效率高很多。

4.5 知识结构图:编译框架全景

下面这张图,是我梳理的编译框架核心流程。你看一眼,就能明白各个组件之间的关系。

OpenHarmony 编译框架核心流程 用户输入命令 hb 工具解析参数 读取产品配置 config.json + BoardConfig.mk 选择编译目标 全量 / 增量 / 单模块 GN 生成 + Ninja 编译 输出镜像文件 核心:hb 是入口,产品配置决定编译内容,GN/Ninja 负责执行

4.6 常见问题与避坑

最后,分享几个我踩过的坑:

  • hb set 后找不到产品:检查 vendor/ 目录下有没有对应的产品文件夹。我曾经手误删了 vendor/hihope,结果 hb set 列表里空空如也。
  • BoardConfig.mk 修改不生效:记得执行 hb clean 后再编译。GN 会缓存配置,不清理的话它还用旧的。
  • 单模块编译失败:先确认模块名写对了。用 hb build -T list 查一下,别自己猜名字。

重要提醒:如果你修改了 config.json 里的组件列表,一定要全量编译一次。增量编译不会重新生成依赖关系,可能导致链接错误。我因为这个浪费过一整天。

好了,编译框架的核心内容就这些。记住:hb 是入口,配置是灵魂,目标选择是效率。把这三点吃透,编译这块你就基本拿下了。