第四章 编译框架入门:理解hb工具链、认识BUILD.gn文件、执行首次全量编译、分析编译输出产物
好,到了这一步,我们终于要开始跟编译系统打交道了。说实话,很多初学者一听到「编译框架」四个字就头大,觉得这东西又深又玄。其实没那么可怕。你想想看,编译说白了就是把我们写的C代码、配置文件,变成能在开发板上跑起来的二进制文件。鸿蒙用的这套工具链叫hb,搭配gn + ninja这套组合拳。我个人觉得,理解它比理解Linux内核的Kbuild要轻松不少。
4.1 hb工具链:鸿蒙的编译管家
hb是鸿蒙专门开发的编译命令行工具。它的全称是HarmonyOS Builder。你不需要记住这个全称,只要知道它是我们操作编译流程的入口就行。
我刚开始接触鸿蒙移植时,第一件事就是确认hb能不能用。怎么确认?很简单:
hb --help
如果系统返回了帮助信息,说明环境没问题。如果提示command not found,那就要回到上一章,检查Python环境和ohos_build的安装情况。
hb的核心命令其实就几个:
| 命令 | 作用 |
|---|---|
hb set |
选择产品/开发板配置 |
hb build |
执行编译 |
hb clean |
清理编译产物 |
hb env |
查看当前编译环境变量 |
嗯,这里要注意:hb set这一步很多人会忽略。我曾经见过一个同事,直接hb build,结果编译出来的是默认的Hi3516DV300的镜像,跟他的板子完全不搭。所以每次编译前,记得先hb set确认一下目标平台。
hb env 查看。它会输出当前的产品名、内核版本、工具链路径等信息。
4.2 认识BUILD.gn文件:编译的「配方」
BUILD.gn文件是鸿蒙编译系统的核心。它用GN(Generate Ninja)语法写成。说白了,它就是告诉编译器:你要编译哪些源文件、链接哪些库、生成什么目标。
我习惯把BUILD.gn比作「菜谱」。菜谱告诉你需要什么食材、怎么切、怎么炒。BUILD.gn告诉你需要哪些.c文件、依赖哪些.h头文件、最终生成一个.bin还是.so。
一个典型的BUILD.gn文件长这样:
import("//build/lite/config/component/lite_component.gni")
ohos_executable("hello_world") {
sources = [
"src/main.c",
"src/utils.c",
]
include_dirs = [
"include",
"//kernel/liteos_a/include",
]
deps = [
"//base/iot_hardware:iot_hardware",
]
}
我来拆解一下:
- ohos_executable:这是鸿蒙定义的一个模板,表示我们要生成一个可执行文件。
- sources:源文件列表。注意路径是相对于当前BUILD.gn文件所在目录的。
- include_dirs:头文件搜索路径。如果漏了某个头文件路径,编译时会报
fatal error: xxx.h: No such file or directory。 - deps:依赖的其他模块。比如你用了鸿蒙的Wi-Fi接口,就要把对应的组件加进来。
include_dirs里少写了一个//。GN的路径写法中,//表示代码根目录,//开头是绝对路径,没有//的是相对路径。这个细节很容易翻车。
4.3 执行首次全量编译
好,理论说完了,我们来动真格的。第一次编译,我建议你执行全量编译。全量编译会从零开始,把所有代码都编译一遍。虽然慢,但能确保整个环境是通的。
步骤很简单:
- 进入代码根目录:
cd ~/openharmony - 选择产品:
hb set,然后选择你的开发板(比如Hi3861或Hi3516) - 执行编译:
hb build -f
这里-f参数表示全量编译(full build)。如果不加,默认是增量编译,只编译修改过的文件。
第一次编译的时间会比较长。我记得我第一次编译Hi3516的镜像,用了将近40分钟。当时我盯着屏幕,看着一行行日志往上滚,心里既期待又忐忑。如果一切顺利,最后你会看到类似这样的输出:
[1/1234] CXX obj/base/startup/init/init.o
[2/1234] CC obj/kernel/liteos_a/kernel.o
...
[1234/1234] STAMP obj/build/lite/ohos.build.stamp
===== build successful =====
看到build successful,恭喜你,编译环境完全没问题。
4.4 分析编译输出产物
编译成功后,产物在哪里?默认情况下,鸿蒙的编译输出放在out/目录下。具体路径取决于你选择的产品。比如:
- Hi3861:
out/hispark_pegasus/wifiiot_hispark_pegasus/ - Hi3516DV300:
out/hispark_taurus/ipcamera_hispark_taurus/
在这个目录里,你会看到一堆文件。我挑几个最重要的说说:
| 文件/目录 | 说明 |
|---|---|
OHOS_Image.bin |
鸿蒙内核镜像,烧录到板子的核心文件 |
rootfs.img |
根文件系统镜像,包含系统服务和用户程序 |
userfs.img |
用户数据分区镜像 |
*.bin / *.elf |
各个组件的可执行文件或符号文件 |
build.log |
完整的编译日志,排查问题时很有用 |
你可能会问:我怎么知道哪个文件是干什么的?嗯,有个小技巧:用file命令查看文件类型。比如:
file out/hispark_pegasus/wifiiot_hispark_pegasus/OHOS_Image.bin
它会告诉你这个文件是二进制数据、ELF文件还是其他格式。这在我们后续做烧录和调试时非常有用。
build.log的大小。如果日志文件特别小,说明编译可能没跑完就结束了。正常的全量编译日志应该有几千行。另外,out/目录下的*.ninja文件也值得关注,它们记录了编译的依赖关系图,有时候能帮你理解为什么某个文件被重新编译了。
好了,这一章的内容就到这里。你掌握了hb的基本用法,看懂了BUILD.gn的骨架,也完成了第一次全量编译。接下来,我们就可以开始真正的移植工作了。下一章,我们会聊聊如何为新的开发板创建产品目录和配置文件——这一步,是移植的起点。