欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper/摘要本文复盘 Standard ML 编译器 MLton 20241230 移植到开源鸿蒙PCOpenHarmony arm64的全过程自举链崩溃、musl 浮点差异、HMDFS 文件系统、toybox 工具链、ELF 签名五类平台问题的定位与修复方法19 轮真机 CI、332 项回归测试全部通过配方与补丁已合入 OpenHarmonyPCDeveloper 社区仓库PR !5084。1 背景MLton 是 Standard ML 语言的 whole-program 优化编译器20241230 是当前最新的正式版本。它是这门语言事实上的性能标杆官方基准数据显示 10 项测试中 8 项运行时第一同为 SML 实现的 SML/NJ 平均比它慢 4.16 倍、二进制大 8.45 倍。它也有真实用户——定理证明器 HOL4 的核心用 SML 实现验证开普勒猜想的 Flyspeck 项目用 MLton 构建官方发布版这类形式化验证工具链要在鸿蒙上落地SML 编译器是底座。而 SML 是 Rust、OCaml、F# 类型系统的源头Rust 从 1.78 起把 OpenHarmony 列为 Tier 2 target 之后生态收益明显语言工具链接入这条路是有先例的。MLton 官方支持 12 组 OS 与架构组合这次适配在它的平台列表里新增了 HarmonyOS 分支——不是只把编译器编过而是 332 项回归测试在 OpenHarmony arm64 上原样跑通。对应的 PR !5084 已复审通过并合入 OpenHarmonyPCDeveloper/build_in_harmonyos 主线配方在archives/m/mlton/20241230全程在 HUAWEI MateBook ProHAD-W32HarmonyOSarm64真机上跑了 19 轮 CImake check332/332、六个验证 marker 全部输出、L0/L1/L4/L5 门禁全过完整构建链耗时 68 分 51 秒。图1 PR !5084 复审通过并合入主线开源鸿蒙PC社区 build_in_harmonyos 仓库这次适配用到的环境项值设备HUAWEI MateBook ProHAD-W32系统HarmonyOSOpenHarmonyAPI 23架构arm64aarch64上游MLton 20241230构建Conan 2.x ohpcd 社区制品仓引导编译器Poly/ML 5.9.2.1含 ARM64 修复依赖gmp 6.3.02 上游假设与鸿蒙PC 环境的差异MLton 的构建有两点不同于常规 C/C 库。一是自举官方构建要先编译 bootstrap-polyml 作为引导编译器。二是它的回归测试会系统地触碰 libc 数学函数、文件系统、进程和信号对目标平台的环境完整性要求很高。源码树放进真机跑第一轮构建后实际遇到的问题集中在五处差异点上游假设鸿蒙PC 实际情况libcglibc 舍入行为musl libc部分 libm 结果差 1 ULP文件系统常规 POSIXHMDFS 对link()返回 EPERM/tmp只读打包工具GNU gzip 长选项toybox gzip 只支持短选项签名无签名步骤binary-sign-tool 输出 mode 640丢可执行位引导编译器Poly/ML 可用ARM64 后端在 OHOS 上崩溃这些差异单个都不难处理麻烦在于它们同时出现在一次构建里并且会被 332 项回归测试逐个暴露出来。3 适配流程适配流程改动自东北大学开源鸿蒙技术俱乐部的研究。王莹教授课题组在面向OpenHarmony平台的C/C软件库自动移植技术课题中提出了知识驱动的自动移植方案 CROSS2OH通过实证研究把跨平台不兼容问题归纳为八类、对应八种通用适配策略并构建了覆盖 305 个 API 替代方案与 1599 个头文件路径映射的适配知识库成果发表在 ASE 2025[1]东北大学团队的课题成果展播报道见[2]。本次适配使用的开发 skill 以这项工作为基础实现我在其上做了个性化定制先侦察确认源码地址和校验值再写 Conan 配方和平台补丁然后真机跑 CI失败后诊断、修复、复核。平台补丁0001主要实现让 MLton 认识 OHOS。Basis Library 的平台类型新增 OHOS 构造bin/platform把 HarmonyOS 内核映射为 ohos运行时复用经过实际编译验证的 Linux-musl 路径。关键改动节选--- a/basis-library/mlton/platform.sml b/basis-library/mlton/platform.sml -127,6 127,7 | HPUX | Linux | OHOS | MinGW | NetBSD -160,6 162,7 | hpux HPUX | hurd Hurd | linux Linux | ohos OHOS | mingw MinGW --- a/bin/platform b/bin/platform -52,6 52,9 Linux) HOST_OSlinux ;; HarmonyOS) HOST_OSohos ;; MINGW*) HOST_OSmingw这次的主要开发工作是在 AtomCode 上完成的。前期侦察和配方初稿在 OpenCode 里起步之后的主体阶段——五处平台差异的定位、三份补丁的编写、引导编译器 polyml/5.9.2.1 的发布、19 轮 CI 的迭代修复——都由 AtomCode 接续执行到最终合入。用下来的体会是这类移植任务里 AI 工具真正实现高效高质的地方不是写代码快而是能把取证—修复—验证跑成固定动作每轮 CI 失败后先产出诊断报告和证据日志钉死根因才动补丁然后定向复现旧 FAIL、新 PASS。人工负责的是每轮失败后的决策——修哪里、修到什么程度、什么不能动。这条流程里我认为最关键且提高效率的点是先取证再动手。每个问题必须看到旧版本 FAIL、新版本 PASS 的对照才算闭环并且要求AI通过联网取证对改动有充足的理由和证据禁止吞错误禁止放宽容差禁止跳过用例。CI 共跑了 19 轮前 13 轮解决平台识别、补丁格式、/tmp只读、HMDFS 硬链接这些问题第 14 到 16 轮逐个清掉浮点、gzip、签名三个点第 17 轮首次全绿第 19 轮复核通过。4 自举链Poly/ML 的 ARM64 崩溃4.1 崩溃定位第 6 轮 CI引导编译器 Poly/ML 在编译 MLton 的过程中抛出getAllocatedGenReg内部错误构建中断。定位后确认是 Poly/ML 的 ARM64 GC save-set 寄存器分配器的问题跨 GC 存活的寄存器需要物化但相应的寄存器槽从未被分配运行时读到了空值。4.2 官方无修复的验证动手修之前先确认了一件事上游是否已有修复。把官方针对 issue #277 的修复提交5437d321干净应用到 v5.9.2固定输入下崩溃指纹与打补丁前完全一致再检出官方 master 最新端点d615dad7同样输入依然复现。也就是说上游历史无修复。这一步不能省——省了本地补丁的正当性就说不清楚。4.3 补丁与发布补丁的内容很克制已分配的 GenReg 复用未分配的走原有冲突感知的findRegister分配spill 失败路径保持原样报错。不默认寄存器不删活跃值不关优化。同时自建了arm64_save_set_regression.ML回归用例防止回退。按仓库规则已发布的版本不能原地改配方所以修复以polyml/5.9.2.1为独立版本号发布到社区 ohpcd 制品仓MLton 配方里只声明依赖不携带 Poly/ML 的文件defbuild_requirements(self):# Poly/ML is an explicit, audited source-built bootstrap compiler.self.tool_requires(polyml/5.9.2.1)同输入旧 FAIL、新 PASS产物哈希可复核。这种独立补丁 回归用例 独立版本号的做法后续其他库遇到上游无修复的引导依赖问题时可以照搬。5 浮点差异atan2f 差 1 ULP5.1 差异现象第 13 轮 CI 后只剩一个失败用例real 回归中的 atan2期望 atan2 (0.34028235E39, ~0.123E4) 1.570796251 实际 atan2 (0.34028235E39, ~0.123E4) 1.570796371差异从第 8 位有效数字开始是典型的 1 ULP 问题。这时候最忌讳直接改期望值——差异可能出在 MLton 代码生成、SML Basis 库、系统 libm 任何一层没定位清楚就改期望等于把可能的编译器 bug 藏起来。5.2 三路交叉归因验证方法是三路交叉同一输入分别用 C 直接调用atan2f、用 SML Basis 的Real32.Math.atan2、用 SML 经 FFI 调用atan2f把结果按原始比特输出对比。三路逐位一致都是0x3fc90fdb。编译器无罪这是 musl 与 glibc 在该输入下的舍入差异而且 musl 返回的才是正确舍入值——上游 x86-linux 和 darwin 的 oracle 记录的正是这个值只有默认的 amd64-linux oracle 记录了偏差值。5.3 平台 oracle 变体解法顺势而为MLton 回归框架本来就支持按平台选择期望文件测试名.平台.ok新增一个real.arm64-ohos.ok变体会被自动拾取。公共 golden 不动容差不放宽用例不跳过。这条经验后来沉淀为社区知识库的 E332 条目平台差异用平台 oracle 表达不修改公共基线。6 其余三处差异这三处相对常规。HMDFS 不支持硬链接且/tmp只读测试临时文件整体迁到 TMPDIR硬链接用例改在支持硬链接的/dev/shm上用唯一文件前缀执行实测/dev/shm不能建子目录mkdtemp 用不了toybox gzip 不认 GNU 长选项一个 11 行的补丁把--force --best改成-f -9签名工具输出的文件 mode 是 640替换后可执行位丢失、打包出的编译器无法运行在_sign_tree里替换前记录原 mode、替换后恢复。签名那处修复的关键片段conanfile.py的_sign_treeorig_modestat.S_IMODE(os.stat(path).st_mode)subprocess.run([objcopy,--remove-section,.codesign,path,clean],checkTrue)subprocess.run([signer,sign,-inFile,clean,-outFile,signed,-selfSign,1],checkTrue)os.chmod(signed,orig_mode)# 签名输出默认 mode640恢复原可执行位os.replace(signed,path)gzip 那处的补丁最短全文只有 11 行直接贴出来感受一下这类修复的量级--- a/Makefile b/Makefile -425,7 425,7 $(MKDIR) $(TMAN) cd $(SRC)/man $(CP) $(MAN_PAGES) $(TMAN)/ ifeq (true, $(GZIP_MAN)) - cd $(TMAN) $(GZIP) --force --best $(MAN_PAGES); cd $(TMAN) $(GZIP) -f -9 $(MAN_PAGES); endif STRIP_PROGS : $(TLIB)/$(MLTON_OUTPUT)$(EXE)其余 diff 都在仓库补丁文件里这里不再展开。7 真机运行与复现PR 合入后我在同一台 MateBook Pro 上做了一次端到端复现从 ohpcd 制品仓下载 CI 构建的官方产物与第 19 轮 CI 的 package 引用一致编译并运行 test_package 的消费者测试。(* MLton on HarmonyOS PC: consumer test from PR !5084 test_package *) val answer List.foldl op 0 [1, 2, 3, 4]; val _ if answer 10 then print MLTON_CONSUMER_OK\n else raise Fail bad sum;$ mlton-codegenc-outputhello hello.sml# 整程序编译约 3 秒$ ./hello MLTON_CONSUMER_OK故意写错的语法样例同样被正确拒绝Syntax error found at SEMICOLON。负向测试在 test_package 里的写法很直白——编译必须失败成功反而报错resultsubprocess.run([mlton,-codegen,c,-output,output-bad,bad],stdoutsubprocess.PIPE,stderrsubprocess.STDOUT,textTrue)ifresult.returncode0:raiseConanException(negative syntax test unexpectedly succeeded)self.output.info(NEGATIVE_TEST_MARKER: invalid SML rejected PASS)图2 HUAWEI MateBook Pro鸿蒙PC真机运行 MLton 20241230编译并执行 hello.sml如果你手上有配置了社区适配环境的鸿蒙PC 设备可以直接验证conan remoteaddohpcd https://conan.cnb.cool/OpenHarmonyPCDeveloper/Conan/-/packages/ conan listmlton/*-rohpcd# 查看可用版本与官方构建产物图3 ohpcd 制品仓查询 mlton/20241230鸿蒙PC 真机实测输出配方、三个补丁和 test_package 的完整源码都在上面 AtomGit 仓库里文中每个问题都能对到具体的 diff。适配中遇到同类报错的话这些补丁可以直接拿来参考。8 小结回头看这次适配可复用的东西主要是几条方法平台能力缺口先做能力探测再定修复方式浮点差异先归因到层再决定是平台 oracle 还是代码问题上游无修复时用独立补丁加回归用例形成可审计的闭环所有修复保持最小改动失败路径不吞错误。这些经验已经作为 E332–E335 条目进入社区知识库。这套把踩坑经验结构化成可复用资产的做法和东北大学团队 CROSS2OH 构建适配知识库[1] 的思路是相通的。图4 第 19 轮 CI 复核摘要设备端 round-19-ci-summary.log 关键行编译器是语言生态的地基。MLton 在鸿蒙PC 上跑通 332 项回归意味着 Standard ML 的工具链在 OpenHarmony arm64 上完整可用了。9 常见问题FAQQ1鸿蒙PC 上/tmp不可写测试写临时文件失败怎么办把临时文件根迁到TMPDIR环境变量指定的目录见第 6 节。Q2HMDFS 上创建硬链接报 EPERMHMDFS 不支持link()。硬链接用例改到支持硬链接的/dev/shm上用唯一文件前缀避免冲突/dev/shm不能建子目录mkdtemp 用不了见第 6 节。Q3musl 和 glibc 的浮点结果差 1 ULP是编译器 bug 吗不一定是。先做多路交叉归因C / SML Basis / FFI 逐位对比确认是 libm 舍入差异后用平台 oracle 变体表达期望值不要直接改公共基线见第 5 节。Q4鸿蒙的 gzip 不认--force --best长选项OHOS 的/usr/bin/gzip是 toybox 版本只支持短选项改用-f -9见第 6 节。Q5二进制签名后无法执行Unable to runbinary-sign-tool 签名输出文件 mode 为 640替换后丢执行位签名前记录原 mode、替换后os.chmod恢复见第 6 节。Q6哪里能拿到 OpenHarmonyarm64的 MLton 官方构建产物ohpcd 社区制品仓第 7 节有查询与下载命令。参考文献[1] Qian Zhang, Tsz On Li, Ying Wang, Li Li, Shing-Chi Cheung. CROSS2OH: Enabling Seamless Porting of C/C Software Libraries to OpenHarmony[C]// Proceedings of the 40th IEEE/ACM International Conference on Automated Software Engineering (ASE 2025). Seoul, Republic of Korea: IEEE, 2025: 1744-1755. DOI: 10.1109/ASE63991.2025.00146[2] 知识驱动、自动修复东北大学团队为开源鸿蒙 C/C 软件库移植打造自动化工具链——开源鸿蒙技术课题成果展播第 5 期[EB/OL]. 微信公众平台, 2026-08. https://mp.weixin.qq.com/s/0pddnK1bxTAUNf9PnTuebQ欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper/