news 2026/7/17 4:05:05

HarmonyOS鸿蒙PC平台nodejs三方库移植实战(bcrypt和 sqlite3移植笔记)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS鸿蒙PC平台nodejs三方库移植实战(bcrypt和 sqlite3移植笔记)

本文记录下移植nodejs三方库bcrypt和 sqlite3到鸿蒙PC上的踩坑过程和经验分享。鸿蒙PC平台nodejs三方库移植也很简单。鸿蒙 PC 安装 bcrypt 和sqlite3三方库实录:预编译与源码编译双路实战,关于 HarmonyOS + Node.js 原生模块的兼容性测试验证总结笔记。


更多交流学习,欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/

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

猫哥的博客:https://blog.csdn.net/qq8864

背景

在鸿蒙 PC 上,(安装好node环境的前提下)执行了这样一个简单的命令:

npminstallbcrypt

然后——没有任何报错node-gyp没有崩毁,编译器没有报缺头文件,3 个包安静地装好,测试用例全部通过。

这在 Node.js 原生模块的安装史上,算得上一个"小反常"。

不过后面我们进一步验证了:不仅预编译能装,强制走源码编译也完全 OK。鸿蒙 PC 上的 C++ 工具链(来自 Harmonybrew 的 clang、make、python3)完整可用。

注:踩坑记,从应用市场上下载安装的node-H软件包,版本23.x有问题啊,直接崩掉,建议卸载掉它。推荐使用 Harmonybrew 的软件包工具安装node环境。


安装成功真机截图:

bcrypt 是什么?

bcrypt是一个密码哈希库,以 C++ 编写,通过 Node-API 暴露给 JavaScript。它的安装有两种路径:

路径 A(预编译): bcrypt 官方发布的 .node 二进制 → node-gyp-build(安装时脚本) 复制到 node_modules 中 路径 B(源码编译): bcrypt 源码 (.cc/.h) → node-gyp 调用 C++ 编译器 生成 .node 二进制

路径 A 静默无感,路径 B 则依赖完整的 C/C++ 编译工具链。绝大多数安装报错都发生在路径 B。

常规安装常见的坑

如果走源码编译路径,鸿蒙系统并不默认提供 GNU/Unix 开发工具链,典型的报错有:

错误信息根因
gyp ERR! stack Error: not found: make缺 GNU Make
fatal error: 'node.h' file not foundNode 头文件未安装
fatal error: 'openssl/opensslv.h' file not foundOpenSSL 开发头文件缺失
gyp ERR! stack Error: Could not find any Python installationPython 未安装(node-gyp 依赖)
clang: error: no such file or directory编译器路径未配置

环境准备:在鸿蒙 PC 上搭建 C++ 编译工具链

在尝试安装原生模块之前,需要先确保鸿蒙 PC 具备基本的 C/C++ 编译环境。这块依赖 Harmonybrew(专为 OpenHarmony 移植的 Homebrew 发行版)来完成。

⛔️ HMDFS 文件系统缺陷
HiShell 环境中TMPDIR默认指向/storage/Users/currentUser,该目录承载在HMDFS上。HMDFS 存在已知文件系统缺陷,可能导致node-gyp编译过程中临时文件写入失败。

建议在安装工具链后,先设置环境变量将临时目录和工作目录指向非 HMDFS 路径:

exportTMPDIR=/data/storage/el2/base/files/tmpmkdir-p$TMPDIR

详见 featured-packages.md 场景一 中的完整说明。

安装 Harmonybrew

步骤操作
① 卸载冲突软件如果安装了 GitNext 和 DevBox,先卸载
② 打开安全开关设置 → 系统 → 开发者选项 → 打开"开发者选项";设置 → 隐私和安全 → 高级 → 打开"运行来自非应用市场的扩展程序"
③ 开启隐藏开发者菜单设置 → 关于本机 → 连续点击"软件版本"7 次 → 确认重启
④ 安装 Harmonybrewzsh -c "$(curl -fsSL https://harmonybrew.atomgit.com/install.sh)"
⑤ 配置环境变量echo 'eval "$(/storage/Users/currentUser/.harmonybrew/bin/brew shellenv)"' >> ~/.zshrc然后执行eval使生效

本文收录于 Harmonybrew 特色软件包清单

安装编译所需工具

推荐使用 Harmonybrew 的一站式开发工具包:

# 安装开发工具包(含 ohos-sdk clang、llvm-gcc-compat、make、coreutils 等)brewinstalldevel-base# 同时安装 Python(node-gyp 依赖)brewinstallpython

💡为什么推荐devel-base它相当于 Debian 中的build-essential,级联依赖了ohos-sdkllvm-gcc-compatmakecoreutils等包。其中ohos-sdk提供的 clang 链接器经过了封装,编译产物会自动带有代码签名,确保.node文件能被 Node.js 运行时正常加载。

如果只需要验证编译链路通不通,安装普通 LLVM 也可以:

brewinstallllvmmakecmake python

但正式项目建议使用devel-base,避免因代码签名问题导致运行时加载失败。

安装后检查关键工具是否就绪:

clang++--version# C++ 编译器make--version# GNU Makepython3--version# node-gyp 脚本依赖

💡 提示brew list可查看已安装的全部包;brew search [keyword]搜索可用包;brew update更新包索引。

这套环境就绪后,鸿蒙 PC 就具备了编译绝大多数node-gyp原生模块的能力。下面安装 bcrypt 就不再依赖预编译路径——即使用走源码编译,工具链也完整可用。


为什么这次这么顺利?

1. bcrypt@6.0.0 用了预编译策略,且覆盖了鸿蒙的架构

这是最核心的原因

bcrypt 从 6.x 开始,安装脚本从node-gyp rebuild(每次都编译)切换为node-gyp-build(优先下载预编译二进制)。而 bcrypt@6.0.0 的官方预编译包覆盖了以下平台:

prebuilds/ ├── darwin-arm64 ├── darwin-x64 ├── linux-arm │ ├── bcrypt.glibc.node │ └── bcrypt.musl.node ├── linux-arm64 │ ├── bcrypt.glibc.node → glibc 变体 │ └── bcrypt.musl.node → musl 变体,鸿蒙命中 ├── linux-x64 │ ├── bcrypt.glibc.node │ └── bcrypt.musl.node ├── win32-arm64 ├── win32-x64

安装时node-gyp-build检测到linux-arm64+ musl libc,精准匹配了bcrypt.musl.node,直接复制使用,完全绕过了 C++ 编译环节

2.--tag-libc构建参数正确生成了 musl 变体

bcrypt@6.0.0 的 npm 构建脚本是:

prebuildify--napi--tag-libc--strip

--tag-libc参数让构建 CI 分别为 glibc 和 musl 各生成一个.node变体:

linux-arm64/ ├── bcrypt.glibc.node → 链接 glibc,适用 Ubuntu/Debian 等 └── bcrypt.musl.node → 链接 musl,适用 Alpine/HarmonyOS

鸿蒙 PC 的系统 libc 是 musl,node-gyp-build自动选择了bcrypt.musl.node。不依赖任何二进制兼容层,完美匹配。

3. 即使强制走源码编译,Harmonybrew 工具链也完全胜任

我们还做了另一个实验——删除build/目录后强制走源码编译:

rm-rfnode_modules/bcrypt/buildnpmrebuild bcrypt --foreground-scripts

输出清晰显示:clang++被调用编译了src/blowfish.ccsrc/bcrypt.ccsrc/bcrypt_node.cc,链接生成了bcrypt_lib.node。测试全部通过。

这意味着 Harmonybrew 安装的 clang 编译器、GNU Make、Python 3、全链路可用

依赖状态
clang++(C++ 编译器)✅ 来自 Harmonybrew
make(构建工具)✅ 来自 Harmonybrew
python3(node-gyp 脚本依赖)✅ 来自 Harmonybrew
node.h(Node API 头文件)✅ 随 Node 安装自带

4. 完整的测试用例验证了功能正确性

为了确认编译产物正确可用,我们编写了一组覆盖 bcrypt 核心 API 的测试用例,涵盖:

  • 异步 hash + compare:多个密码串(含中文、空密码)
  • 不同 saltRounds:验证$2b$格式和轮数编码
  • 同步 APIhashSync/compareSync
  • 边界情况:空密码输入
  • getRounds:校验 hash 中编码的 saltRounds 值
constbcrypt=require('bcrypt');constpasswords=['test123','Hello@2024','aB3#xyZ!','密码123',''];constsaltRounds=[4,10,12];asyncfunctionrunTests(){letpassed=0;letfailed=0;console.log('🧪 bcrypt 测试用例\n'+'='.repeat(40));// 测试 1: 基础 hash + compareconsole.log('\n📌 测试 1: hash + compare 基本流程');for(constpwofpasswords){try{consthash=awaitbcrypt.hash(pw,10);constmatch=awaitbcrypt.compare(pw,hash);constwrong=awaitbcrypt.compare('wrong-'+pw,hash);constok=match===true&&wrong===false;console.log(`${ok?'✅':'❌'}hash("${pw||'(空)'}") → compare →${ok?'正确':'失败'}`);ok?passed++:failed++;}catch(e){console.log(`❌ hash("${pw||'(空)'}") 抛出异常:${e.message}`);failed++;}}// 测试 2: 不同 saltRoundsconsole.log('\n📌 测试 2: 不同 saltRounds');for(constrofsaltRounds){try{consthash=awaitbcrypt.hash('test123',r);constparts=hash.split('$');constrounds=parts[2];constsalt=(parts[3]||'').slice(0,6);constok=rounds===String(r)&&parts[1]==='2b';console.log(`${ok?'✅':'❌'}saltRounds=${r}→ $${parts[1]}$${rounds}$${salt}...`);ok?passed++:failed++;}catch(e){console.log(`❌ saltRounds=${r}异常:${e.message}`);failed++;}}// 测试 3: 同步 APIconsole.log('\n📌 测试 3: 同步 API (hashSync / compareSync)');try{consthash=bcrypt.hashSync('sync-test',8);constok=bcrypt.compareSync('sync-test',hash)&&!bcrypt.compareSync('wrong',hash);console.log(`${ok?'✅':'❌'}hashSync + compareSync${ok?'正常':'异常'}`);ok?passed++:failed++;}catch(e){console.log(`❌ sync API 异常:${e.message}`);failed++;}// 测试 4: 空值保护console.log('\n📌 测试 4: 边界情况');try{consth1=bcrypt.hashSync('',4);constok=bcrypt.compareSync('',h1);console.log(`${ok?'✅':'❌'}空密码 hash+compare${ok?'正常':'异常'}`);ok?passed++:failed++;}catch(e){console.log(`❌ 空密码处理:${e.message}`);failed++;}// 测试 5: getRoundsconsole.log('\n📌 测试 5: getRounds 解析 hash 轮数');try{consthash=bcrypt.hashSync('rounds-test',11);constrounds=bcrypt.getRounds(hash);constok=rounds===11;console.log(`${ok?'✅':'❌'}getRounds() →${rounds}${ok?'(正确)':'(应为11)'}`);ok?passed++:failed++;}catch(e){console.log(`❌ getRounds 异常:${e.message}`);failed++;}// 汇总console.log('\n'+'='.repeat(40));consttotal=passed+failed;console.log(`📊 总计:${total}用例 | ✅ 通过:${passed}| ❌ 失败:${failed}`);console.log(total===passed?'\n🎉 全部通过!':`\n⚠️ 有${failed}个失败`);}runTests().catch(e=>console.error('测试框架异常:',e));

输出结果(从源码编译的bcrypt_lib.node上运行):

🧪 bcrypt 测试用例 ======================================== 📌 测试 1: hash + compare 基本流程 ✅ hash("test123") → compare → 正确 ✅ hash("Hello@2024") → compare → 正确 ✅ hash("aB3#xyZ!") → compare → 正确 ✅ hash("密码123") → compare → 正确 ✅ hash("(空)") → compare → 正确 📌 测试 2: 不同 saltRounds ✅ saltRounds=4 → $2b$4$zQX5l... ✅ saltRounds=10 → $2b$10$WrMpR... ✅ saltRounds=12 → $2b$12$VgCfD... 📌 测试 3: 同步 API (hashSync / compareSync) ✅ hashSync + compareSync 正常 📌 测试 4: 边界情况 ✅ 空密码 hash+compare 正常 📌 测试 5: getRounds 解析 hash 轮数 ✅ getRounds() → 11 (正确) ======================================== 📊 总计: 10 用例 | ✅ 通过: 10 | ❌ 失败: 0 🎉 全部通过!

5 组测试覆盖了 10 个子用例,全部通过。无论是预编译.node还是源码编译的bcrypt_lib.node,功能表现完全一致。

一个有意思的细节

新版 npm(10.x+)中,--build-from-source已被废弃:

npm warn Unknown command: "--build-from-source"

正确的做法是:

# 方式一:删预编译二进制触发回退rm-rfnode_modules/bcrypt/prebuildsnpmrebuild bcrypt# 方式二:直接调用 node-gypnpmrebuild bcrypt --foreground-scripts# 方式三:最底层cdnode_modules/bcrypt&&npx node-gyp rebuild--verbose

--foreground-scripts可以把编译过程的每一条clang++命令都输出到终端,方便调试。


延伸实战:sqlite3 的移植教训

除了 bcrypt,我们还在同一台机器上移植了另一个 native 模块——sqlite3@6.0.1。这次遇到的情况完全不同,正好验证了工具链的健壮性。

首次安装:编译失败

npminstallsqlite3

报错关键信息:

514 error make: ar: No such file or directory 514 error make: *** [../node-addon-api/nothing.target.mk:130: Release/obj.target/../node-addon-api/nothing.a] Error 127

根因分析

ar(GNU Archiver)是 binutils 的一部分,负责将.o目标文件打包为.a静态库。node-gyp在编译 native 模块时,通过Makefile调用ar来创建中间静态库,但 Harmonybrew 默认的devel-base没有包含ar

为什么 bcrypt 没遇到这个问题?

模块安装路径结果
bcryptprebuild预编译 → 直接下载.node二进制✅ 成功,零编译
sqlite3prebuild-install超时 → 回退node-gyp rebuild源码编译❌ 缺少ar失败

bcrypt 的预编译路径完全绕过了 C++ 编译环节;而 sqlite3 在预编译下载超时后回退到源码编译,才暴露出ar缺失的问题。

修复

安装提供ar的工具包:

brewinstallbinutils

或更全面的:

brewinstallllvm-gcc-compat binutils

验证:

whichar# → /harmonybrew/bin/arar--version# → GNU ar (GNU Binutils) ...

重新安装

npmrebuild sqlite3 --foreground-scripts

这次编译链路完整走通:clang++编译.ccar打包.aclang++链接生成.node,最终输出added 57 packages,无任何gyp ERR!

测试验证

参照 bcrypt 的测试风格,为 sqlite3 编写了 10 组测试用例:

#测试项覆盖内容
1打开/关闭数据库文件创建、连接生命周期
2CREATE TABLE + INSERTDDL、参数化插入、lastID
3SELECT 查询db.all()、排序、行数验证
4参数化查询防 SQL 注入、db.get()
5UPDATE修改数据、this.changes
6DELETE删除前后行数对比
7事务BEGIN/COMMIT/ROLLBACK可见性
8错误处理NOT NULL 约束违反捕获
9serialize 串行化执行顺序保证
10内存数据库:memory:模式读写

全部 10 组通过:

🧪 sqlite3 测试用例 ======================================== 📌 测试 1: 打开和关闭数据库 ✅ 📌 测试 2: 建表 + 插入数据 ✅ 📌 测试 3: SELECT 查询 ✅ 📌 测试 4: 参数化查询 ✅ 📌 测试 5: UPDATE ✅ 📌 测试 6: DELETE ✅ 📌 测试 7: 事务 ✅ 📌 测试 8: 错误处理 ✅ 📌 测试 9: serialize 串行化 ✅ 📌 测试 10: 内存数据库 ✅ ======================================== 📊 总计: 10 用例 | ✅ 通过: 10 | ❌ 失败: 0 🎉 全部通过!

sqlite3 移植的核心经验

  1. 预编译不是万能的——bcrypt 走预编译一路顺风,但 sqlite3 的预编译下载超时后就暴露了工具链缺口
  2. ar是编译链路的关键一环——devel-base包含了clang++makepython3,但缺少binutilsarld等)。安装binutils即可补齐
  3. 源码编译路径验证了工具链的完整性——修复后 sqlite3 完整走通了 C++ 编译→静态库打包→链接的全流程,证明 Harmonybrew 工具链完全胜任 node-gyp native 模块的编译需求
  4. --foreground-scripts是调试利器——能看到完整的 clang++ 编译命令和ar打包过程,快速定位缺失的工具

最终结论

因素角色
bcrypt@6.x 预编译策略关键因素——走预编译路径时零依赖安装
--tag-libc构建参数生成了-glibc/-musl双变体,鸿蒙精确命中后者
鸿蒙系统是 ARM64 + musl与预编译包完美匹配,无需兼容层
devel-base(Harmonybrew 工具链)预编译路径未使用,但源码编译路径完整可用

所以这背后是两个好消息:

预编译路径:bcrypt@6.0.0 的构建者用--tag-libc为不同 libc 分别构建了变体,鸿蒙 PC 是linux-arm64+ musl,node-gyp-build精准命中了bcrypt.musl.node——零编译,装完即用。

源码编译备胎:即使预编译二进制不存在(或被人删了),devel-base工具链已就绪,直接npm rebuild能顺利从.cc源码编译出.node二进制。两条路都通。

对鸿蒙上 Node.js 开发者的参考

  • 优先选择支持 prebuild 的包,安装过程最省心
  • 即使包没有预编译,有devel-base工具链(clang + make + python3),大部分node-gyp模块也能从源码编译
  • bcrypt--tag-libc是一个好实践——如果开发 native 模块,建议也加上这个参数,对齐不同 libc 环境下安装者的体验
  • 如果遇到--build-from-source报 unknown command,换成--foreground-scripts,这是新 npm 的正确方式
  • 迁移 sqlite3 等模块的额外教训:安装binutils补全ar等归档工具,确保源码编译链路完整

📸参考资料

  • 完整工具链安装指南:Harmonybrew 特色软件包清单
  • 本文涉及的测试代码:test-bcrypt.js、test-sqlite3.js
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 4:04:22

【Python基础】Python开发环境搭建实战操作详解

目录 一、前言 二、Python 基本介绍 2.1 Python 核心特点 2.2 Python 应用领域 2.3 Python 优缺点 2.4 现代 Python 生态趋势 2.5 Python 使用建议 三、Python 环境搭建 3.1 获取安装包 3.2 安装过程 3.3 效果验证 四、Python 编程初体验 4.1 Hello World 输出 4.…

作者头像 李华
网站建设 2026/7/17 4:03:47

VScode:使用TeamoRouter的API服务

TeamoRouter的优势 TeamoRouter是一个包含多种大语言模型的中转平台,可以间接调用 Claude、GPT、Gemini 、Deepseek等各种 AI 模型,同时提供API服务。 1.价格便宜 如图所示,无需多言。 2.操作省心 无需翻墙,担心网络环境是否…

作者头像 李华
网站建设 2026/7/17 4:03:32

C语言实现健壮字符串替换函数:从内存管理到工程实践

1. 项目概述与核心价值最近在整理一个老项目的代码,里面充斥着各种手写的、风格各异的字符串替换逻辑,看得人头大。有的用strtok加循环硬拼,有的自己写指针挪来挪去,稍不注意就缓冲区溢出或者内存泄漏。这让我下定决心&#xff0c…

作者头像 李华
网站建设 2026/7/17 4:03:23

Windows 11 23H2新特性与ARM64架构解析

1. Windows 11 23H2版本概述Windows 11 23H2是微软在2023年下半年推出的重大功能更新版本,作为Windows 11系统的第二个年度更新,它带来了多项性能改进和新功能增强。这个版本特别值得关注的是它对ARM64架构设备的原生支持,使得采用高通骁龙等…

作者头像 李华
网站建设 2026/7/17 4:02:53

Ubuntu高效工作环境搭建:精选必备软件与配置指南

1. Ubuntu常用软件概览作为一名Linux系统管理员,我使用Ubuntu已有8年时间。在这期间,我尝试过数百款Ubuntu软件,最终筛选出一批真正实用、高效的必备工具。这些软件不仅能满足日常办公需求,更能提升开发效率,让Ubuntu系…

作者头像 李华
网站建设 2026/7/17 4:02:49

Python学生成绩管理系统开发指南:从基础语法到项目实战

那天下午,一个刚学 Python 不久的朋友给我发来消息:“老师布置了一个学生成绩管理系统的作业,要求用 Python 实现,但我连从哪里开始都不知道。” 我问他具体需求,他说要能录入成绩、查询成绩、统计平均分,还…

作者头像 李华