MongoDB 鸿蒙 PC 适配全记录:从 Bazel 交叉编译到 HNP 原生数据库服务

欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

适配开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mongo

一、为什么要适配 MongoDB

MongoDB 是文档型数据库生态中具有代表性的开源项目。它用 BSON 文档组织数据,弱化了关系型数据库中固定表结构的约束,并围绕导入导出、备份恢复、状态观测和分片路由形成了一套成熟的工具链。对 HarmonyOS PC 而言,MongoDB 的价值不只是"多一款可以打开的应用",更重要的是补充本地原生数据库服务能力:开发者可以直接在设备上保存结构化数据、验证数据模型、制作离线演示,也能为后续移植到鸿蒙 PC 的开发工具和服务端软件提供数据底座。

选择 MongoDB 作为适配对象,也是在检验一条比普通桌面应用更完整的原生软件交付链路。MongoDB 上游是体量很大的 C++20/Bazel 工程,默认依赖 glibc 语义和较新的编译器能力;真正运行时还涉及 WiredTiger 持久化、网络监听、后台进程、命令行工具以及数据目录权限。只有同时解决编译、打包、安装和真机运行四个层面的问题,适配才有实际意义。

本次适配基于 MongoDB master 分支的 9.0.0-alpha0 开发版本,HNP 包版本为 9.0.0,目标架构为 arm64-v8a,应用 BundleName 为 com.example.mongodb。最终产物采用"介绍页 HAP + MongoDB HNP"的组合:HAP 负责签名安装、版本与命令说明,HNP 则提供 mongodmongos 和 8 个官方 Database Tools。

二、先确定交付方式:数据库服务不应依附 ArkUI 页面

MongoDB 的核心是常驻数据库进程,而不是一个需要一直留在前台的图形窗口。如果把服务生命周期绑定到 ArkUI 页面,窗口关闭、应用切后台等行为都会干扰数据库运行,也会让原有命令行参数和运维工具失去意义。因此,本次适配没有重写 MongoDB 的服务模型,而是使用 HarmonyOS Native Package(HNP)交付原生 ELF,再由一个轻量 HAP 完成安装和使用引导。

这条路线把职责分成了四层:

层次 主要问题 鸿蒙侧处理方式
构建层 上游 Bazel 配置只覆盖官方支持平台 增加 ohos_arm64 平台与专用 C/C++ 交叉工具链
兼容层 glibc、Landlock、resolver 等接口与 OHOS musl 不一致 通过 __MUSL__is_ohos 条件分支做小范围兼容
交付层 服务器、路由程序和工具需要统一注册 用 HNP 打包 10 个官方命令,并在 HAP 签名前注入
运行层 /tmp、数据目录和安全策略不同于普通 Linux 使用全小写可写目录、TCP 回环连接并禁用 Unix socket

HAP 页面关闭后,已经启动的 mongod 仍按数据库进程自身的生命周期运行;终端中的导入、导出和观测命令也直接连接 127.0.0.1:27017。这种方式保留了 MongoDB 在服务器平台上的使用习惯,同时符合 HarmonyOS PC 的安装与签名要求。

三、鸿蒙版本的工程结构

适配代码尽量与上游源码树分离,平台判断只在确有差异的位置启用:

text 复制代码
ohos_mongo/
├── build_mongo_hnp.sh                    # 交叉编译、架构审计、strip 与 HNP 打包
├── OHOS_MIGRATION_PLAN.md                # 平台差异和阶段性适配方案
├── bazel/
│   ├── platforms/                        # ohos_arm64 平台约束
│   └── toolchains/cc/mongo_ohos_cross/   # OHOS C/C++ 交叉工具链与包装器
├── ohos_port/
│   ├── libcxx-ohos/                      # 面向 OHOS musl 的 libc++ 22 静态运行库
│   ├── database-tools/                   # 8 个 arm64 官方 Database Tools
│   ├── hnp.json                          # HNP 元数据和公共命令链接
│   └── mongod.conf                       # YAML 配置示例
└── ohos/
    ├── AppScope/                         # 应用版本、图标和 BundleName
    ├── hnp/arm64-v8a/                    # mongodb.hnp 投放目录
    ├── hnp-inject-plugin.ts              # PackageHap 与 SignHap 之间注入 HNP
    └── entry/src/main/
        ├── module.json5                  # 2in1、INTERNET 权限和 hnpPackages 声明
        └── ets/pages/Index.ets           # 安装说明页

ohos_port/hnp.json 注册的命令包括 mongodmongosmongodumpmongorestoremongoexportmongoimportmongostatmongotopmongofilesbsondump。这些命令均来自 MongoDB 上游服务器产物或官方 Database Tools,没有用自定义包装器替换原始命令语义。

完整的数据流为:

text 复制代码
MongoDB C++ 源码
    └── Bazel + OHOS 混合工具链
          ├── mongod / mongos(aarch64 OHOS ELF)
          └── 官方 Database Tools(Go arm64 静态产物)
                 └── mongodb.hnp
                       └── 注入、签名为 HarmonyOS HAP
                              └── 真机 HiShell 直接执行官方命令

四、从安装到数据导出的真机验证

以下 5 张图片均来自已连接的 HUAWEI MateBook Pro 鸿蒙 PC 真机,设备型号标识为 HAD-W32,系统版本为 6.1.0.117,截图分辨率为 3120×2080。验证过程使用设备系统自带终端的 HiShell 环境,所有命令均由已安装 HNP 中的真实二进制执行。

1. HAP 页面确认原生服务和工具已经随包交付

安装后打开 MongoDB 应用,可以看到服务端、分片路由和 Database Tools 清单,也能直接查到真机运行时需要使用的数据目录、日志目录、监听地址和 --nounixsocket 参数。这个页面只负责说明,不承载数据库服务本身。

把命令清单放在安装入口中有两个好处:一是用户不必进入 HNP 安装目录寻找二进制,二是可以明确区分 mongod 服务端与数据工具的职责。页面关闭后,终端仍可独立使用这些命令。

2. 确认运行的是 arm64 MongoDB 原生产物

在真机 HiShell 中执行 mongod --version,输出显示数据库版本为 v9.0.0-alpha0,分配器为 systemjavascriptEnginenone,同时给出 distarch: arm64target_arch: arm64

这一结果来自设备实际加载并执行的 mongod ELF,比应用页中的静态版本文案更能说明交叉编译结果有效。system 分配器和关闭服务端 JavaScript 也与本轮针对 OHOS musl 的构建取舍一致。

3. WiredTiger 完成初始化,数据库进程进入可连接状态

真机上先创建全小写的数据与日志目录,再以 TCP 回环地址启动服务:

bash 复制代码
mkdir -p /data/storage/el2/base/mongo-data/db \
  /data/storage/el2/base/mongo-data/log

mongod \
  --dbpath /data/storage/el2/base/mongo-data/db \
  --logpath /data/storage/el2/base/mongo-data/log/mongod.log \
  --bind_ip 127.0.0.1 \
  --port 27017 \
  --nounixsocket \
  --fork

终端返回 child process started successfully, parent exiting,说明 WiredTiger 初始化、日志文件创建、端口监听和后台派生均已完成。

这里使用 --nounixsocket 不是为了简化演示,而是适应鸿蒙 PC 的文件系统边界:MongoDB 默认会尝试在 /tmp 创建 Unix socket,而该路径在应用终端环境中不可写。显式使用 TCP 回环连接后,数据库功能不受这一差异影响。

4. 使用官方 mongoimport 建立数据写入闭环

验证数据链路时创建了一份带有 namecategorypricestock 字段的 CSV,并通过官方 mongoimport 写入 harmony_demo.products 集合。工具连接到真机本地 27017 端口,主动清理同名集合后导入两条文档,结果显示 2 document(s) imported successfully,失败数为 0。

这一过程覆盖了 TCP 连接、数据库与集合创建、CSV 类型推断、BSON 文档生成以及 WiredTiger 持久化。相比只观察进程是否存在,真实导入结果更能说明数据库已经具备可用的数据写入能力。

5. 使用官方 mongoexport 读回 BSON 文档

随后使用 mongoexport --pretty 从同一集合读取数据。终端中返回两条带有真实 ObjectId 的 JSON 文档,字段值与导入源一致,最后明确显示 exported 2 records

导入和导出构成了最小但完整的数据闭环:数据不是写入临时缓存后丢失,也不是应用页面中的固定样例,而是经过 mongoimport → mongod → WiredTiger → mongoexport 整条链路写入并重新读取。

五、适配过程中最棘手的问题

难点一:MongoDB 的 Bazel 构建没有现成的 OHOS 目标

MongoDB 上游大量使用 Bazel 平台约束、工具链选择和 select() 分支。只给编译命令增加 --target=aarch64-unknown-linux-ohos 并不能形成完整目标平台,依赖分析阶段仍可能选择宿主机配置或找不到匹配工具链。

适配中新增了 ohos_arm64 平台和独占的 is_ohos 约束,同时把目标声明为 Linux/aarch64,以复用仓库中已经成熟的 Linux ARM64 依赖分支。专用 cc_toolchain 再把编译、归档、链接、strip 等动作统一接到 OHOS 工具链上。这样平台差异集中在少量新增配置里,不需要逐个改写上游 BUILD 文件。

难点二:SDK clang 版本与 MongoDB master 的要求不匹配

当前工程需要较新的 C++20 前端能力,而 OpenHarmony SDK 内置 clang 15 无法覆盖 MongoDB master 的编译要求;完全使用桌面端 clang,又会丢失 OHOS 的 musl sysroot、目标 ABI、链接器和运行时约束。

最终采用混合工具链:Homebrew clang 22 负责 C/C++ 前端,OHOS SDK 提供 sysroot、ld.lld 和 compiler-rt,项目内则提供面向 OHOS musl 构建的 libc++ 22 静态库。工具链包装器固定目标三元组和搜索路径,避免链接阶段意外混入 macOS 库。

难点三:glibc 假设必须逐项映射到 musl

上游代码在进程信息、DNS 查询、动态库诊断、启动检查和栈回溯等位置包含 glibc 特有接口。适配没有用一组空宏粗暴掩盖问题,而是根据每项能力的实际用途选择等价实现或关闭仅用于诊断的平台特性。

源码兼容修改通过 #if defined(__MUSL__) && !defined(__GLIBC__) 保护,Bazel 侧差异使用 is_ohos 约束。Linux/glibc 和 macOS 构建继续走上游路径,OHOS 分支只在目标平台生效。

难点四:Landlock 探测在真机上不是返回失败,而是触发 SIGSYS

MongoDB 启动时会探测 Linux Landlock ABI。普通 Linux 内核不支持时通常返回 ENOSYS,程序可以继续;鸿蒙 PC 的应用安全策略对相关 syscall 的处理更严格,会直接以 SIGSYS 终止进程,因此最初表现为 mongod 启动后无输出消失。

通过系统日志定位到受限 syscall 后,OHOS musl 分支不再执行 Landlock 探测,并把该能力报告为不可用。Landlock 属于额外的 Linux 文件系统沙箱机制,关闭探测不会改变 MongoDB 的查询和存储语义,却能避免触碰目标系统明确禁止的系统调用。

难点五:HNP 需要在签名前进入 HAP

module.json5 中声明 hnpPackages 只是描述包依赖,当前构建链还需要把真实的 mongodb.hnp 放进 HAP。项目使用 hnp-inject-plugin.tsPackageHap 完成后重打未签名 HAP,再交给原有 SignHap 任务签名。这样 HNP 内容受到同一份 HAP 签名保护,设备安装时也能正确注册 10 个公共命令。

六、构建、安装与运行

本项目是原生 C++/Bazel 工程,不属于 Electron 或 Qt 应用。开发机需要安装 DevEco Studio/OpenHarmony SDK、较新的 Homebrew LLVM、MongoDB 使用的 Bazel wrapper,以及项目所需的 Python 构建环境。

交叉编译服务器、执行架构审计并打包 HNP:

bash 复制代码
cd ohos_mongo
./build_mongo_hnp.sh

如果 mongodmongos 已经编译完成,可以跳过 Bazel 阶段,只重新审计并打包:

bash 复制代码
SKIP_BAZEL=1 ./build_mongo_hnp.sh

脚本会确认两个服务器产物都是 ARM aarch64 ELF,对二进制执行 strip,并把 8 个 Database Tools 一起打入:

text 复制代码
ohos/hnp/arm64-v8a/mongodb.hnp

随后进入鸿蒙工程完成 HAP 构建与签名:

bash 复制代码
cd ohos
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
export JAVA_HOME=/Applications/DevEco-Studio.app/Contents/jbr/Contents/Home
hvigorw assembleHap

连接鸿蒙 PC 后安装并启动介绍页:

bash 复制代码
hdc list targets
hdc install -r entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a EntryAbility -b com.example.mongodb -m entry

实际数据库功能应在设备系统终端的 HiShell 标签中验证。首次启动建议使用全小写路径,并显式关闭 Unix socket:

bash 复制代码
mkdir -p /data/storage/el2/base/mongo-data/db \
  /data/storage/el2/base/mongo-data/log

mongod \
  --dbpath /data/storage/el2/base/mongo-data/db \
  --logpath /data/storage/el2/base/mongo-data/log/mongod.log \
  --bind_ip 127.0.0.1 --port 27017 \
  --nounixsocket --fork

hdc shell 适合安装、拉取截图和查看系统信息,但它与用户在真机终端打开的 HiShell 不是同一运行上下文。数据库的文件写入、标准输入输出和交互行为,应以真机 HiShell 结果为准。

七、当前功能边界

当前版本已经在鸿蒙 PC 真机上验证:

  • HAP 安装、HNP 解包以及 10 个公共命令注册;
  • mongod --version 正常执行并报告 arm64 目标架构;
  • 全小写数据目录中的 WiredTiger 初始化和持久化;
  • mongod 监听 127.0.0.1:27017 并以 --fork 进入后台;
  • mongoimport 创建数据库、集合并导入 CSV 文档;
  • mongoexport 读回 BSON 文档并输出标准 JSON;
  • mongodumpmongorestoremongostatmongotopmongofilesbsondump 随同一 HNP 交付;
  • mongos 分片路由程序随包交付。

本轮构建也保留了清晰边界。服务端 JavaScript、TLS、SASL/LDAP、tcmalloc、Landlock 和精细 libunwind 栈回溯没有启用;mongosh 是独立的 Node.js 项目,也不在当前 HNP 中。Unix domain socket 因 /tmp 权限限制不作为运行入口,设备本地通过 TCP 回环连接。

这些限制不影响本地单实例的存储、导入导出和基础运维,但当前产物更适合开发、教学、兼容性验证与离线数据处理,不应直接等同于已经完成长期压力测试和安全加固的生产级集群版本。TLS、认证体系、复制集和分片集群的端到端验证仍应作为后续阶段单独推进。

八、总结

MongoDB 的鸿蒙 PC 适配难点并不集中在某一处编译错误,而是由 Bazel 平台模型、现代 C++ 工具链、musl 接口差异、系统调用安全策略、HNP 打包和真机文件系统共同构成。任何一层只做到"看起来可以"都会在下一层暴露问题:二进制能链接不代表能启动,进程能启动也不代表数据可以落盘,工具随包存在更不代表导入导出链路已经跑通。

当前版本已经把这条链路连了起来:MongoDB 服务器由 Bazel 交叉编译为 aarch64 OHOS 原生产物,官方 Database Tools 与服务端统一进入 HNP,再由 HAP 完成签名和安装;真机上能够启动 WiredTiger、导入 CSV,并重新导出带 ObjectId 的 JSON 文档。更重要的是,平台兼容修改都通过条件分支收敛在 OHOS/musl 路径中,没有破坏上游平台原有的构建逻辑,为后续补齐 TLS、认证和集群能力留下了清晰基础。

相关推荐
YangYang9YangYan1 小时前
2026 校招管理会计 JD 拆解,数据分析能力要求与工具清单
java·数据库·数据分析
安好说AI1 小时前
Flutter for OpenHarmony 实战:媒体选择库 adaptive_image_picker 的鸿蒙化适配全解读
flutter·harmonyos·媒体
贾伟康1 小时前
【HarmonyOS 7新能力|011】分布式数字身份入门实战:从能力边界到最小可运行链路
harmonyos·arkts·隐私保护·数字身份·harmonyos 7
颜颜yan_2 小时前
Geany 鸿蒙 PC 适配全记录:以 Qt 重建轻量 IDE,打通编辑、项目检索与命令执行
ide·qt·harmonyos
敲代码的嘎仔2 小时前
互动问答系统实战:两级评论模型、ES 搜索集成、Caffeine 多级缓存全记录
java·开发语言·数据库·elasticsearch·缓存·mybatis·高并发
●VON2 小时前
Flutter 鸿蒙插件适配实战:用 app_version_details 1.0.3 读取版本号与包名
flutter·华为·harmonyos
倔强的石头_2 小时前
SQL Server数据库迁移,为什么 KES V9R4C019 能把改代码变成改连接
数据库
承渊政道2 小时前
PR-Agent鸿蒙PC适配全记录:从Python服务端代理到ArkTS原生评审客户端
python·华为·代理模式·agent·harmonyos·pc端
黑色的白兔No12 小时前
deepin 25安装mysql
数据库·mysql·debian