山东大学 2023 级软件工程创新实训项目博客。

上一篇完成了环境、源码结构和基础知识准备。这一阶段的目标,是把“看得懂一些源码”推进到真正可执行的工程闭环:

获取源码 → 准备预编译工具 → 全量构建 → 生成镜像 → 烧录设备 → 建立测试基线

这条链路一旦跑通,后面每一项外设修改才有可靠落点。否则代码即使改对了,也可能没有被编译、没有进入镜像,或者烧录后无法判断到底使用的是新产物还是旧文件。

获取 OpenHarmony 6.1 RISC-V 源码

OpenHarmony 由大量 Git 仓库组成,因此使用 repo 管理清单和同步过程。当前项目使用进迭时空/如意社区提供的 OpenHarmony 6.1 RISC-V 分支。

初始化示例:

repo init \
  -u https://code.openruyi.cn/risc-verse/ruyi-desktop-os/manifest.git \
  -b OpenHarmony-v6.1-Release-RISC-V \
  --no-repo-verify

同步源码:

repo sync -c -j4 --retry-fetches=100 --fail-fast
repo forall -c 'git lfs pull'

这里最容易忽略的是:repo sync 命令结束,不一定等于所有仓库和 Git LFS 大文件都完整。后续出现头文件、二进制或模型文件缺失时,应该先核对对应子仓库状态,而不是立刻在代码中“造一个文件”绕过错误。

如果某个子仓库同步不完整,可以进入该目录单独检查远端、分支和 LFS:

git status
git remote -v
git branch -a
git lfs pull

项目初期确实遇到过仓库访问方式、令牌权限和个别子仓库不完整的问题。最终改用可访问的 HTTPS manifest,并针对缺失仓库重新同步,才得到可持续构建的源码树。

安装依赖与预编译工具

MUSEPaper2 的板级说明给出了 Ubuntu 22.04 所需的软件包,包括编译器基础工具、Java、Python、Node.js、文件系统工具、设备树工具和 ccache 等。

安装系统依赖后,还需要在源码根目录下载 OpenHarmony 的预编译工具:

bash build/prebuilts_download.sh

预编译目录中包含 Clang/LLVM、GN、Ninja、Node.js 以及构建脚本依赖的其他二进制工具。它们与源码分支需要匹配,因此不建议随意使用系统里另一个版本的工具替代。

第一次全量构建

进入源码根目录,执行 MUSEPaper2 产品构建:

./build.sh \
  --product-name musepaper2 \
  --ccache \
  --no-prebuilt-sdk

参数含义:

  • --product-name musepaper2:选择 MUSEPaper2 产品配置;
  • --ccache:启用编译缓存,后续增量构建速度会明显提高;
  • --no-prebuilt-sdk:从当前源码构建所需 SDK,而不是完全依赖预置 SDK。

构建过程并不是简单地把所有 .cpp 文件编译一遍。它大致经历:

  1. 解析产品与部件配置;
  2. GN 生成 Ninja 构建图;
  3. Ninja 编译内核、系统部件、HDF/HDI、应用和工具;
  4. 把模块安装到 system、vendor 等临时目录;
  5. 生成各分区镜像和安装清单;
  6. 执行依赖、权限、SELinux、NOTICE 等检查。

因此报错时不能只看一行 FAILED,还要确认失败发生在哪个阶段。

初期遇到的典型问题

1. 子仓库内容不完整

构建曾出现类似错误:

fatal error: 'v1_1/display_composer_type.h' file not found
fatal error: cannot find include path for ...

这类问题首先应该确认目标文件本应由哪个仓库提供,再检查该仓库是否同步完整。对于 Git LFS 管理的文件,还要执行 git lfs pull

2. 头文件依赖没有显式声明

也遇到过:

error: 'uint32_t' has not been declared
error: unknown type name 'uint32_t'

这种问题可以通过补充标准头文件解决,但不能只满足于“加一行以后能编译”。还需要确认这是源码缺少显式依赖、工具链差异,还是前一个头文件未正确同步造成的连锁错误,并记录修改原因,避免留下无法解释的临时补丁。

3. 内存不足与 OOM

完整构建持续时间长、并行任务多,16 GB 内存环境可能触发 OOM。典型表现是编译进程或整个桌面会话突然退出,但构建日志中没有直观的语法错误。

可以通过以下命令检查:

free -h
dmesg | grep -i -E "oom|killed process"

解决思路包括降低并行度、启用足够的 swap,以及在编译期间避免同时运行高内存应用。

4. 磁盘空间不足

源码、预编译工具、Git 对象和 out 目录会占用大量空间。扩大 swap 时也不能忘记它同样占用磁盘。如果根分区被写满,除了构建失败,图形界面和系统服务也可能无法启动。

df -h
du -sh out
du -sh .repo

这次经历让我意识到,嵌入式系统构建中的“环境问题”并不比代码问题简单。稳定、可复现的主机环境本身就是项目基础设施的一部分。

构建产物在哪里

编译完成后,主要输出位于:

out/musepaper2/

用于烧录的镜像位于:

out/musepaper2/packages/phone/images/

其中可能包含:

boot.img
system.img
vendor.img
userdata.img
updater.img
fastboot.yaml

不同镜像承担的内容不同:

  • boot.img:内核和启动相关内容;
  • system.img:OpenHarmony Framework、系统服务和系统应用;
  • vendor.img:板级服务、外设配置、vendor 库和固件;
  • userdata.img:用户数据分区初始内容。

这也是后续定位“修改应该进入哪个分区”的依据。例如板级蓝牙固件和 Wi-Fi 配置通常进入 vendor,而 Camera 应用会进入 system。

生成完整烧录包

镜像构建完成后,使用板级脚本生成完整烧录包:

./build/gen_zip.sh musepaper2

输出文件为:

out/musepaper2/packages/phone/images/
openharmony-spacemit-musepaper2.zip

在后期完成全部适配后,最终一次全量构建通过了 4289/4289 个 Ninja 步骤,并成功生成上述 ZIP。这说明摄像头、Wi-Fi、USB 和蓝牙相关的 GN 依赖已经能够同时通过全量构建。

不过,“编译成功”只说明构建图可以执行完,并不能单独证明每项功能正确。还要检查关键文件是否进入打包目录,例如:

vendor/etc/wifi/wpa_supplicant.conf
vendor/bin/wifi_fix.sh
vendor/etc/firmware/rtl8852bs_fw
vendor/etc/firmware/rtl8852bs_config
system/app/com.ohos.camera/Camera.hap

对于重要产物,还应该保存哈希:

sha256sum openharmony-spacemit-musepaper2.zip
sha256sum boot.img system.img vendor.img

这样才能确认设备端或团队成员之间使用的是同一个版本。

烧录时的原则

初期我们首先将原始系统版本烧录到设备,用于建立功能基线。烧录应优先使用进迭时空提供的官方工具和完整烧录配置,不应在不了解分区布局时随意写入启动分区。

需要特别区分:

  • 完整烧录:适合验证一套镜像能否在新设备上完整复现;
  • 增量部署:适合缩短开发周期,例如通过 HDC 临时替换某个 HAP 或共享库;
  • 单分区写入:风险高于普通文件替换,必须核对实际启动介质、分区名和镜像尺寸;
  • boot/env/分区表操作:可能直接导致设备无法启动,必须先备份并保存哈希。

开发阶段可以用增量部署验证修改方向,但最终结果必须回到源码和完整构建关系。否则设备上虽然暂时可用,重新烧录后修改就会消失。

原始系统测试结果

原始系统烧录并启动后,我们按照统一清单逐项检查。

系统与 HDC

  • 系统可以进入桌面;
  • HDC 可以连接设备;
  • 静置或电源状态变化后,HDC 存在掉线风险。

后续定位表明,USB PHY 会受到系统深度休眠策略影响,因此 USB/HDC 稳定性被列为独立任务。

Wi-Fi

  • 硬件使用 RTL8852BS;
  • Wi-Fi 数据链路走 SDIO;
  • 原始系统中的驱动、供电和 wpa_supplicant 启动流程仍需完善。

后续工作补齐了 8852bs.ko、Wi-Fi 运行目录、配置文件、启动服务和休眠供电处理。

摄像头

  • 底层能够看到部分视频设备;
  • 前后摄映射、格式能力、预览和拍照链路不完整;
  • Camera App 还不能形成“预览—切换—拍照—相册保存”的稳定闭环。

这成为我后续首先负责的外设适配任务。

蓝牙

  • 设置中存在蓝牙开关,系统也包含蓝牙服务;
  • 但 HCI 初始化和扫描不能稳定完成;
  • 后续需要继续检查 UART、rfkill、Realtek vendor、firmware 和 HCI HDI。

其他基础能力

显示、触控和系统基础界面可以工作,为继续进行外设适配提供了可用环境。

测试不能只看界面

设置页出现开关,最多只能证明上层 UI 和部分系统服务存在。真正验证外设需要跨层证据。

例如 Wi-Fi 可以检查:

lsmod | grep 8852
ip link show wlan0
ps -A | grep wpa_supplicant

蓝牙可以检查:

ls -l /dev/ttyS2
cat /sys/class/rfkill/rfkill0/state
ps -A | grep -E "blue_host|bluetooth_service"

USB/HDC 可以检查:

param get sys.usb.config
ps -A | grep hdcd
hdc list targets

摄像头可以检查:

ls -l /dev/video*
hilog | grep -i -E "camera|v4l2"

我们逐渐把验证标准从“界面看起来能点”改成:

硬件节点存在
  + 驱动/服务稳定
  + 日志链路正确
  + 用户功能可完成
  + 重启后仍然有效

阶段结论

完成这一阶段后,我们得到的不只是一次编译结果,而是一套后续适配可以反复使用的闭环:

  1. 源码能够同步并处理 Git LFS;
  2. MUSEPaper2 产品能够完成全量构建;
  3. 能够生成分区镜像和完整 ZIP;
  4. 原始系统已经烧录并完成外设基线测试;
  5. USB、Wi-Fi、摄像头和蓝牙的问题边界初步明确;
  6. 后续修改需要经过“单项验证—源码集成—全量构建—冷启动回归”。

这一步跑通后,项目才真正从准备阶段进入外设适配阶段。后续文章会分别记录 OpenHarmony 6.1 源码学习、官方构建问题、摄像头和蓝牙的完整适配过程。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐