
欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper/摘要本文复盘 LAPACKE 0.3.30 移植到开源鸿蒙 PCHarmonyOSaarch64的全过程。LAPACKE 没有独立上游发布版本跟随 OpenBLAS 0.3.30内嵌 LAPACK 3.12.0交付它等于把 OpenBLAS 的 Fortran 构建体系整体搬上真机。途中遇到三类问题精简 flang 工具链链接 Fortran 可执行文件缺目标级链接件、OpenBLAS 构建系统在鸿蒙上误记 CROSS1 导致全部上游测试被静默跳过、affinity 接口适配被代码审查打回后重写为 POSIX 能力级。最终上游测试四件套utest/blat/ctest/lapack-test真实执行合计 5,197,358 项判定通过率 99.989%576 项 DGEEV 特征值族阈值未达有上游三处引证归因。配方与补丁已交付社区仓库 OpenHarmonyPCDeveloper/build_in_harmonyosAtomGit的archives/l/liblapacke/0.3.30。1 背景LAPACKE 是 netlib 给 LAPACK 做的标准 C 接口官方页面高层函数自动管理工作区同时支持行主序和列主序——C 代码中调用LAPACKE_dgesv求解线性方程组使用的就是这一层接口。numpy/scipy 一类科学计算栈的底层依赖里都有它的位置科学计算软件要在鸿蒙 PC 上落地这个库是必要的基础组件。从C 接口库的定位出发这项任务最初被评估为一次常规适配。核对源码分布后评估需要修正LAPACKE 没有独立上游发布源码位于 OpenBLAS 源码树的lapack-netlib/子目录版本号与 OpenBLAS 保持一致——0.3.30 对应 OpenBLAS 0.3.302025-06-19 发布内嵌 LAPACK 3.12.0。交付 liblapacke 0.3.30实际是把 OpenBLAS 完整构建出来lapacke.h 和 LAPACKE_* 符号是其中一层。最终结果真机交付lapacke.h等全套头文件加内嵌 LAPACKE 符号的 libopenblas消费者直接-lopenblas上游测试四件套全部真实执行合计 5,197,358 项判定、通过率 99.989%CI 共 5 轮前两轮分别败于补丁偏移和测试脚本自身缺陷第 3 轮起全绿。全程使用的环境项值设备HUAWEI MateBook Pro开源鸿蒙 PCHarmonyOSaarch64上游OpenBLAS 0.3.30含 LAPACKE LAPACK 3.12.0BSD-3-ClauseFortran 工具链flang-ohos 20.1.0LLVM Flang 系C 工具链OHOS SDK clang 15.0.4构建Conan 2.x设备原生构建源码校验tar.gz SHA25627342cff…63c95dGitHub release 校验值2 上游假设与鸿蒙 PC 环境的差异OpenBLAS 的构建系统是 GotoBLAS 传下来的 perl 脚本加 Makefile 体系隐含假设比一般 CMake 项目多。在真机上启动构建后实际遇到的差异集中在四处差异点上游假设鸿蒙 PC 实际情况Fortran 工具链系统有可用的 Fortran 编译器无 gfortran仅有精简打包的 flang-ohos测试可执行链接驱动自带 crt 等目标级链接件flang 包资源目录缺件链接期报错平台判定uname -s与编译器探针结论一致HarmonyOS vs OS_LINUX被误判为交叉编译affinity 接口glibc 风格pthread_*_np可用设备动态库无法解析_np本就是非移植扩展其中两处的影响超出构建失败本身它们会让结果呈现正常、实际不正常。这也是本次移植耗时最多的两处见第 5、6 节。3 路线纯 C 编译为什么不是答案OpenBLAS 有NOFORTRAN1开关字面含义是不使用 Fortran 编译表面上适用于无 Fortran 工具链的平台。翻构建系统确认它的实际行为NOFORTRAN1置C_LAPACK1Makefile.system :382LAPACK 的编译整体切换到源码树自带的 f2c 转换 C 源、用 CC 进行SRC/Makefile 的 C_LAPACK 分支测试矩阵生成器 MATGEN 也有对应的 C 转换——库本体的编译存在纯 C 路径。另一条联动NO_LAPACK1强制NO_LAPACKE1:1458服务于只要 BLAS的场景由ONLY_CBLAS等开关触发与 NOFORTRAN 无关。两条联动不是一条链混读会得出纯 C 路线产不出 LAPACKE的错误结论。纯 C 路线真正过不去的是验证层上游 LAPACK 测试的主体 EIG 与 LIN 两个目录共 1,132 个源文件358 774全部是 Fortran 实现没有任何 C 转换路径。没有 Fortran 编译器lapack-test 无从构建——库编得出来上游口径的验证无从谈起。本任务的验收口径是上游测试全量真实执行纯 C 路线在这个口径下不成立Fortran 工具链问题必须正面解决。设备上可用的 Fortran 编译器只有仓库自带的 flang-ohos 20.1.0选择它有依据仓库内 blas、lapack、cblas 等十几个配方已用它完成静态库构建路线有先例。不过静态库可以编译与测试可执行可以链接、可以运行之间还差两个环节这是后两节的内容。另外两条评估后未采用的路线记录如下。路线 B 是把 LAPACKE 的 C 源码单独抽出编译成独立库、依赖现成的 openblas 包LAPACKE 0.3.30 与仓库内其他版本的 OpenBLAS 引擎混搭版本口径不一致且消费者闭包中会出现两个 BLAS 引擎。路线 C 是走仓内 lapack/3.12.1 配方的 CMake 路线该先例自身就因 FortranCInterface 链接验证失败产不出 LAPACKE 共享库。综合版本口径、依赖闭包与验证可行性全量构建是唯一同时满足的路线。4 flang 链接缺件构建目录内的 overlay 资源目录构建打通后最先暴露问题的是测试可执行的链接步骤。OpenBLAS 的上游测试blat、lapack-test全部是 Fortran 可执行程序ld.lld连续报ld.lld: error: cannot open Scrt1.o: No such file or directory ld.lld: error: cannot open crti.o: No such file or directory ld.lld: error: cannot open crtbeginS.o: No such file or directory ld.lld: error: unable to find library -lm ld.lld: error: cannot open …/lib/clang/20/lib/aarch64-linux-ohos/libclang_rt.builtins.a: … ld.lld: error: unable to find library -l:libunwind.a用flang -v查看驱动实际执行的链接行失败机理明确flang 把 crt、内置库、unwind 这些目标级链接件全部从自己的资源目录包/lib/clang/20取用而该目录在精简包中不存在——包内只有 FortranRuntime 和 FortranDecimal 两个运行库。另外OHOS flang 编译的 program 对象自带 main 与 _QQmain 双符号llvm-nm 可验证入口不依赖 FortranMain。鸿蒙 SDK 中有全部实体但那是 clang 15.0.4 的目录布局文件名和位置都与 flang 20 期望的不一致。再试--sysroot该驱动不接受此选项-isysroot也无法注入链接搜索路径。一种直观的修复方向是修改 flang 包或 SDK 实体通过改名、复制补齐缺失文件。这条路线不能采用工具链实体是设备上的共享环境任何改动都会影响后续所有构建。实际采用的方案是在构建目录内构造 overlay 资源目录10 个软链接把 SDK 中同物异名的实体按 flang 期望的名字集中crtbeginS.o指向 SDK 的clang_rt.crtbegin.o以此类推每一项都做存在性检查缺件直接报错而不是静默跳过然后链接期注入LDFLAGS-resource-dir overlay。上游源码一行未动flang 包和 SDK 一个文件未改。为了确认该方案针对的是真实缺口、而非既有做法的重复包装做了一个负对照实验用仓库现有配方blas、lapack 系的-resource-dir SDK直连写法链接同一可执行文件结果失败报错与上面一致。这说明配方树内同族的 16 个以上 Fortran 先例全部止步于静态库构建静态库不涉及 crt可执行链接此前没有先例。验证用的五步探针在新 shell 中可以完整复现flang-20-chello.f90# 编译成功——问题只在链接flang-20-ohello_neg hello.o# 负对照无 overlay预期失败# …构造 overlay10 项 symlink…flang-20-ohello_pos hello.o -resource-dir rd ./hello_pos# 输出 AUDITOR_HELLO_OK 1.4142135这一步的负对照不能省略——缺少它无法区分修复了真实缺口与重复包装既有做法两种情况。5 测试静默跳过CROSS1 造成的假 PASS链接打通后执行make lapack-test数秒内正常退出。没有报错没有告警日志中没有任何测试输出。重复执行现象相同。检查构建树生成的Makefile.conf其中记录为CROSS1——构建系统判定这是一次交叉编译而构建机即目标机本次是设备原生构建判定有误。定位到c_check脚本判定逻辑如下它用uname -s取主机系统名鸿蒙设备上返回HarmonyOS再用编译器预定义宏探测目标系统clang 报告OS_LINUX。两个结论不一致脚本判定为交叉编译写入CROSS1。而上游 Makefile 中所有就地测试执行都挂在ifneq ($(CROSS), 1)门下——CROSS1时测试段整体不展开make 照常退出零告警。验证这个判断只需要两行输出 0 和 1make-nlapack-testCROSS1|grep-clapack_testing.py# 0执行段被跳过make-nlapack-testCROSS0|grep-clapack_testing.py# 1执行段恢复展开解法是在测试步骤命令行显式加CROSS0覆盖。只覆盖测试执行判定这一个变量上游的探测逻辑和生成的配置文件都不动。真交叉构建的场景下这个覆盖是错误的交叉产物本就不应就地执行因此该动作的适用边界明确构建机等于目标机时才成立。这个问题的风险在于它不产生任何错误信号构建失败会迫使排查静默跳过则呈现为正常结束测试结论在未被察觉的情况下失真。“先检查grep ^CROSS Makefile.conf、再采信测试结果”应当作为 GotoBLAS 系构建的固定检查步骤。6 affinity 返工从平台宏到 POSIXmusl 环境下还有一个问题上游代码使用的pthread_setaffinity_np系列在设备动态库中无法解析。_np后缀本身就是 glibc 的非移植扩展man page 明确标注 STANDARDS: GNU更换 libc 实现后遇到此问题在预期之内。第一版补丁用#if defined(OS_LINUX) !defined(__OHOS__)将这段代码在鸿蒙上条件编译排除。功能上可以运行但被代码审查打回项目规则禁止在补丁中引入平台条件编译宏要求按 POSIX 能力级适配。这个判定成立——平台宏方案存在一层隐患它依赖编译器恰好定义了该宏工具链变更后守卫会静默失效原始缺陷无告警复现。重写后的补丁改用sched_setaffinity/sched_getaffinityPOSIX 标准接口musl 和 glibc 都提供。跨线程寻址的问题用syscall(SYS_gettid)解决工作线程启动时记录自己的内核 TID按 TID 调用openblas_setaffinity/openblas_getaffinity两个对外 API 原样保留。返修后全量重跑 CI第 5 轮并在产物级做了核对.so和.a中pthread_*_np引用归零sched_*正常导入对外符号集不变。这次返工的对比值得记录平台宏的适配只对当前编译环境成立能力探测的适配对接口语义成立前者的维护成本会在工具链变更时再次出现。7 全量测试5,197,358 项判定和 576 项未达阈值测试四件套的规模比预想大套件规模结果OpenBLAS utest utest_ext127 1522 项断言全过已折入 CI 默认链BLAS blats/d/c/z × blat1/2/3 × 2 线程模式24 次程序执行92 个 PASS 块0 failCBLAS ctest12 个程序含 error-exits全过LAPACK 官方 lapack-testEIG LIN5,195,617 项判定576 项阈值未达其他错误 0lapack-test 的官方汇总lapack_testing.pyREAL 1,568,556 / DOUBLE 1,569,378 / COMPLEX 1,028,308 / COMPLEX16 1,029,375。合计 5,197,358 项判定含 utest 和 blat通过 5,196,782 项通过率 99.989%。这 576 项需要交代清楚——含糊处理会直接影响测试结论的可信度。逐项分析其分布全部落在非对称特征值驱动族sed/ded/ced/zed 四个输入文件的 DGEEV 相关子节四个精度各 144 项失败结构完全一致残差比值全部顶在 1/ulp 的钳制值上命中的只有极端量级的病态矩阵类型。同一个输入文件中 DGEES、DGEEVX、DGEESX 子节和 nep.in 全部通过。这个形态与上游的已知现象一致Reference-LAPACK issue #732 中维护者原话是激进编译优化和/或高度优化的 BLAS是 LAPACK 严格测试失败的已知来源netlib LAPACK FAQ 将轻微超阈归因于数学库实现差异、判定为可忽略OpenBLAS issue #4187 在 ARM 平台报告过同族失败53/1092。判定口径因此写作通过附记录例外——0.011% 的阈值未达有出处、有归因不是回避。耗时数据均为真机实测CI 默认路径全量构建 utest 消费者测试约 25 分钟在官方默认 3600 秒构建超时内自足全量上游测试约 2.6 小时23:02 首个输出01:38 收官其中最重的 LIN 族 c/z 各 677,060 项判定——构建负载并行时单族约 2.1 小时空载时同规模约 9 分钟。因此全量套件做成配方里的RUN_UPSTREAM_TESTS1可选目标、留档真实执行日志CI 常规门禁只跑轻量回归以单轮约 25 分钟换取每轮都可回归。CI 共 5 轮逐轮记录第 1 轮补丁按 0.3.34 源码编写hunk 在 0.3.30 对应位置偏移应用失败——更换目标版本不是修改版本号补丁必须对着目标树重新生成第 2 轮 test_package 的行主序断言传错了 ldb——n×1 的右端项 b 在行主序下 ldb 应为 nrhs 而非 ndge_trans按in[j*ldini]寻址ldb 传 n 会越界读——测试脚本自身也可能有缺陷负向验证因此不能省略第 3 轮起进入正轨第 4 轮为补齐 Fortran 测试环境后的终树第 5 轮为 affinity 返工后的全量重跑即交付树。8 真机运行与复现交付后做了端到端复现做成一个分六段的演示脚本环境、链接探针、CROSS 静默门、产物自省、消费者基准、回归测试每段结束暂停确认全程真机执行、逐段截图。第一段确认设备与工具链HarmonyOS 内核、aarch64、20 逻辑核flang 20.1.0 就位。图1 演示第 1 段真机环境与工具链HarmonyOS aarch64、20 核、flang 20.1.0第二段是第 4 节链接缺件的最小复现。先做无 overlay 负对照链接ld.lld 依次报缺 Scrt1.o、crti.o、crtbeginS.o、libclang_rt.builtins.a、libunwind.a随后建 symlink overlay 资源目录、链接行注入-resource-dir同一个 hello.f90 链接成功并运行llvm-nm 现场验证 flang 对象自带 main 与 _QQmain 双符号——这是第 4 节不需要 FortranMain的实证。图2 演示第 2 段Fortran 可执行链接最小复现负对照失败 → overlay 修复 → 运行输出第三段到真实构建树解剖第 5 节的静默门grep ^CROSS Makefile.conf现场输出 CROSS1make -n对照显示 CROSS1 时 lapack_testing.py 的执行行为 0、CROSS0 时为 1——0 与 1 之差就是假 PASS 与真实执行的分界。图3 演示第 3 段CROSS1 静默跳过现场Makefile.conf 的 CROSS1 make -n 对照 0/1第四段自省交付物8 个 lapacke 头文件、libopenblas 的 SONAME、2605 个 LAPACKE_* 导出符号再 grep 证实 affinity 返工后的工件状态——sched_* 能力接口在位、glibc 风格的非移植扩展 pthread_*_np 引用为 0。图4 演示第 4 段交付物自省8 个头文件、SONAME、2605 个 LAPACKE_* 导出符号第五段是消费者视角的性能与正确性实测写一个 C 程序#include lapacke.h链接 libopenblas跑 dgemm/dpotrf/dgesv 三类基准并求解一个 3×3 线性方程组逐项核对数值——图5 演示第 5 段消费者基准与正确性实测dgemm/dpotrf/dgesv GFLOPS 残差 3×3 核对clang-O2-oconsumer consumer.c -I包/include -L包/lib-lopenblasLD_LIBRARY_PATH包/lib ./consumer openblas:OpenBLAS0.3.30 NO_AFFINITY ARMV8MAX_THREADS20core:ARMV8 threads:20cblas_dgemmN15000.068s98.56GFLOPS cblas_dgemmN25000.245s127.43GFLOPS LAPACKE_dpotrfN25000.222s23.50GFLOPSinfo0LAPACKE_dgesvN20000.240s22.21GFLOPSinfo0rel.residual1.46e-15 correctness: LAPACKE_DGESV_CONSUMER_OK x[615-23]20 线程下 dgemm 两档测得 98.56 与 127.43 GFLOPS同机另一次运行为 104.19/121.62波动来自后台负载dgesv 解 2000×2000 方程组的相对残差 1.46e-15量级上就是机器精度——这是可信赖的双精度解。第六段现场执行轻量回归全套——utest 127 项、utest_ext 1522 项断言全部通过随后展示全量 lapack-test 的官方汇总表合计 5,195,617 项判定、576 项阈值未达、其他错误 0与第 7 节的记录一致。图6 演示第 6 段utest/utest_ext 现场执行127/127、1522/1522 lapack-test 官方汇总表全量 lapack-test 约 2.6 小时演示中不重放官方汇总表与逐精度明细见留档日志。配方、两个补丁、test_package 的完整源码都在社区仓库的archives/l/liblapacke/0.3.30文中每个问题都能对应到具体 diff。9 小结回顾整个过程可复用的方法有三条构建系统的限制先读机理再定方案NOFORTRAN 的联动关系查清之前不动手测试结论先确认测试真实执行再评估通过make -n对照可以直接暴露静默跳过平台差异用能力探测表达不依赖平台宏——affinity 的返工是一次现成的对照。链接探针与 CROSS 对照两条命令自包含同场景的移植可以直接复用。最后把这次用到的入口留在这里想动手的读者可以直接取开源鸿蒙PC社区——适配方向与积分赛动态社区项目平台——新库在这里申请liblapacke 0.3.30 配方与补丁fork 分支 feat/liblapacke-0.3.30评审中——本篇交付的配方、补丁与 test_package。10 常见问题FAQQ1鸿蒙 PC 上能运行 Fortran 程序吗能。flang-ohosLLVM Flang 系全量编译没有问题链接可执行文件需要 overlay 补齐目标级链接件第 4 节运行时依赖 FortranRuntime/FortranDecimal。Q2LAPACKE 0.3.30 是官方版本号吗LAPACKE 没有独立上游发布版本跟随 OpenBLAS 0.3.302025-06-19内嵌 LAPACK 3.12.0见第 1 节。Q3576 项测试未达阈值这个库还能用吗能。576/5,195,617 0.011%全部集中在 DGEEV 驱动族的极端病态矩阵上游三处引证一致归因为优化 BLAS 的已知阈值敏感非法输入和其他错误为 0逐项归因见第 7 节。Q4为什么全量测试不放进 CI全量约 2.6 小时纳入后会阻塞常规门禁。CI 默认链保留 utest 和消费者测试约 25 分钟一轮全量做成RUN_UPSTREAM_TESTS1可选目标交付时全量执行留档见第 7 节。Q5make lapack-test几秒就结束且没有任何测试输出是怎么回事GotoBLAS 系构建在鸿蒙上被 c_check 误记 CROSS1测试段整体静默跳过。先执行grep ^CROSS Makefile.conf结果为 1 就在测试步骤加CROSS0覆盖见第 5 节。Q6LAPACKE_dgesv行主序调用崩溃或解出错误值怎么排查先查 ldb。行主序下 n×nrhs 的右端项 bldb 是行长度 nrhs不是 n——传成 n 时dge_trans按in[j*ldini]寻址会越界读小尺寸表现为解出错误值大尺寸越界直接段错误本例实测 N≥350 起。A 的 lda 传 n 是对的b 的 ldb 要传 nrhs。这个坑在本次 CI 第 2 轮和演示脚本编写时各踩过一次轮次记录见第 7 节。参考文献[1] netlib LAPACKE 官方页面. https://www.netlib.org/lapack/lapacke.html[2] OpenBLAS v0.3.30 Release. https://github.com/OpenMathLib/OpenBLAS/releases/tag/v0.3.30[3] LAPACK 3.12.0 Release. https://github.com/Reference-LAPACK/lapack/releases/tag/v3.12.0[4] LLVM Flang 项目主页. https://flang.llvm.org/[5] Reference-LAPACK issue #732优化 BLAS 与严格 LAPACK 测试失败. https://github.com/Reference-LAPACK/lapack/issues/732[6] netlib LAPACK FAQHow do I interpret LAPACK testing failures? https://www.netlib.org/lapack/faq.html[7] OpenBLAS issue #4187ARM 平台同族阈值未达. https://github.com/OpenMathLib/OpenBLAS/issues/4187[8] pthread_setaffinity_np(3) Linux man pageSTANDARDS: GNU. https://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html欢迎加入开源鸿蒙PC社区 https://harmonypc.csdn.net/欢迎在PC社区平台申请新建项目https://atomgit.com/OpenHarmonyPCDeveloper/