# oh_nodejs **Repository Path**: spacemit-openharmony/oh_nodejs ## Basic Information - **Project Name**: oh_nodejs - **Description**: oh_nodejs是基于原生nodejs进行鸿蒙的编译适配后可独立运行在openharmony系统的原生版本,支持通过npm安装对应包并运行。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-16 - **Last Updated**: 2026-07-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Node.js riscv64 交叉编译与鸿蒙设备部署指南 使用 OpenHarmony 源码树自带的 Spacemit RISC-V GCC 工具链,静态链接交叉编译 Node.js v22.16.0,一键部署到鸿蒙设备。 **核心思路:Node.js 源码独立下载,只需指定鸿蒙的交叉编译工具链路径即可编译,无需将源码放入鸿蒙源码树。** ## 前置条件 | 项目 | 要求 | |------|------| | 编译服务器 | x86_64 Linux,可访问鸿蒙 prebuilts 工具链 | | 鸿蒙源码 | 仅需 `prebuilts/gcc/` 下的交叉编译工具链 | | 鸿蒙设备 | riscv64 架构,SSH 可达 | | Node.js 源码 | v22.16.0(从 Gitee 仓库克隆) | ## 关键路径 只需知道鸿蒙源码树中交叉编译工具链的路径(相对于鸿蒙源码根目录): ``` prebuilts/gcc/linux-x86/riscv64/spacemit-riscv-gcc/bin/ ├── riscv64-unknown-linux-gnu-gcc ← 交叉编译器 (GCC 13.2.1) ├── riscv64-unknown-linux-gnu-g++ ├── riscv64-unknown-linux-gnu-ar ├── riscv64-unknown-linux-gnu-strip └── ... ``` Node.js 源码可以放在任意位置,无需放入鸿蒙源码树。 ## 一键编译部署脚本 ```bash #!/bin/bash # ================================================================ # Node.js riscv64 交叉编译与鸿蒙设备一键部署脚本 # 核心原理: 独立下载Node.js源码 + 指定鸿蒙prebuilts工具链 # 链接方式: 完全静态链接 (无运行时动态库依赖) # ================================================================ set -uo pipefail # ============== 配置区 (按需修改) ============== # 鸿蒙源码根目录 (仅用于定位prebuilts工具链) OH_ROOT="/home/heshihuan/WorkSpace2/k3" # 交叉编译工具链 (相对于OH_ROOT) TC_DIR="prebuilts/gcc/linux-x86/riscv64/spacemit-riscv-gcc" TC_PREFIX="riscv64-unknown-linux-gnu" # Node.js版本 NODE_VERSION="22.16.0" # 目标设备 DEVICE_IP="root@10.0.90.166" DEVICE_NODE_DIR="/data/node" # 编译工作目录 (独立于OH源码树) WORK_DIR="/tmp/nodejs-build" # 编译并行度 JOBS=64 # ============== 开始 ============== echo "============================================" echo " Node.js v${NODE_VERSION} riscv64 交叉编译" echo " 工具链: ${OH_ROOT}/${TC_DIR}" echo "============================================" # 检查工具链 TC_BIN="${OH_ROOT}/${TC_DIR}/bin" if [ ! -f "${TC_BIN}/${TC_PREFIX}-gcc" ]; then echo "错误: 找不到工具链 ${TC_BIN}/${TC_PREFIX}-gcc" exit 1 fi # ============== [1/5] 下载Node.js源码 ============== echo "[1/5] 下载 Node.js v${NODE_VERSION} 源码..." mkdir -p "${WORK_DIR}" cd "${WORK_DIR}" NODE_SRC="node-v${NODE_VERSION}" NODE_REPO="git@gitee.com:spacemit-openharmony/oh_nodejs.git" if [ ! -d "${NODE_SRC}" ]; then git clone --depth 1 --branch "v${NODE_VERSION}" "${NODE_REPO}" "${NODE_SRC}" fi echo " 源码路径: ${WORK_DIR}/${NODE_SRC}" # ============== [2/5] 设置交叉编译环境 ============== echo "[2/5] 设置交叉编译环境..." # 注意: /usr/bin 必须在 PATH 前面,否则工具链目录下的 python3 会覆盖系统 python3 export PATH="/usr/bin:${TC_BIN}:${PATH}" export CC="${TC_PREFIX}-gcc" export CXX="${TC_PREFIX}-g++" export AR="${TC_PREFIX}-ar" export RANLIB="${TC_PREFIX}-ranlib" export NM="${TC_PREFIX}-nm" export STRIP="${TC_PREFIX}-strip" # Host编译器 (编译构建期间需要在x86_64上运行的工具) export CC_host=gcc export CXX_host=g++ # 静态链接标志 (关键: 使node不依赖目标系统glibc/musl) export LDFLAGS="-static -static-libgcc" export CXXFLAGS="-static-libstdc++" # ============== [3/5] Configure + Make ============== echo "[3/5] Configure + Make..." cd "${WORK_DIR}/${NODE_SRC}" rm -rf out/ python3 configure \ --dest-cpu=riscv64 \ --dest-os=linux \ --cross-compiling \ --prefix=/opt/node \ --without-intl \ --openssl-no-asm \ --without-snapshot if [ $? -ne 0 ]; then echo "错误: configure 失败" exit 1 fi make -j"${JOBS}" if [ $? -ne 0 ]; then echo "错误: make 失败" exit 1 fi # Strip "${TC_BIN}/${TC_PREFIX}-strip" out/Release/node -o out/Release/node.stripped echo " 编译产物: $(ls -lh out/Release/node.stripped | awk '{print $5}')" file out/Release/node.stripped # ============== [4/5] 打包 ============== echo "[4/5] 打包部署文件..." DEPLOY_DIR="${WORK_DIR}/deploy" rm -rf "${DEPLOY_DIR}" mkdir -p "${DEPLOY_DIR}/bin" "${DEPLOY_DIR}/lib/node_modules" cp out/Release/node.stripped "${DEPLOY_DIR}/bin/node" cp -r deps/npm "${DEPLOY_DIR}/lib/node_modules/npm" cp -r deps/corepack "${DEPLOY_DIR}/lib/node_modules/corepack" 2>/dev/null || true # npm/npx包装脚本 cat > "${DEPLOY_DIR}/bin/npm" << 'NPMEOF' #!/bin/sh exec /data/node/bin/node /data/node/lib/node_modules/npm/bin/npm-cli.js "$@" NPMEOF cat > "${DEPLOY_DIR}/bin/npx" << 'NPXEOF' #!/bin/sh exec /data/node/bin/node /data/node/lib/node_modules/npm/bin/npx-cli.js "$@" NPXEOF chmod +x "${DEPLOY_DIR}/bin/node" "${DEPLOY_DIR}/bin/npm" "${DEPLOY_DIR}/bin/npx" DEPLOY_TAR="${WORK_DIR}/node-ohos-static-riscv64.tar.gz" cd "${DEPLOY_DIR}" && tar czf "${DEPLOY_TAR}" . echo " 部署包: ${DEPLOY_TAR} ($(ls -lh ${DEPLOY_TAR} | awk '{print $5}'))" # ============== [5/5] 部署到设备 ============== echo "[5/5] 部署到 ${DEVICE_IP}..." ssh "${DEVICE_IP}" "rm -rf ${DEVICE_NODE_DIR} && mkdir -p ${DEVICE_NODE_DIR}" scp "${DEPLOY_TAR}" "${DEVICE_IP}:${DEVICE_NODE_DIR}/" ssh "${DEVICE_IP}" "cd ${DEVICE_NODE_DIR} && tar xzf node-ohos-static-riscv64.tar.gz && rm node-ohos-static-riscv64.tar.gz && chmod +x bin/node bin/npm bin/npx" # 验证 echo "" echo "============================================" echo " 部署完成! 验证运行..." echo "============================================" ssh "${DEVICE_IP}" " ${DEVICE_NODE_DIR}/bin/node --version ${DEVICE_NODE_DIR}/bin/node -e 'console.log(\"架构:\", process.arch, \"平台:\", process.platform)' ${DEVICE_NODE_DIR}/bin/npm --version " echo "" echo "完成! 在设备上使用:" echo " ${DEVICE_NODE_DIR}/bin/node --version" echo " ${DEVICE_NODE_DIR}/bin/npm install " ``` ## 手动步骤详解 如需分步操作,按以下流程: ### 步骤一:下载 Node.js 源码 ```bash # 从 Gitee 仓库克隆,放到任意目录 mkdir -p /tmp/nodejs-build && cd /tmp/nodejs-build git clone --depth 1 --branch v22.16.0 git@gitee.com:spacemit-openharmony/oh_nodejs.git node-v22.16.0 cd node-v22.16.0 ``` ### 步骤二:设置交叉编译环境 ```bash # 指定鸿蒙prebuilts工具链路径 (将OH_ROOT替换为你的鸿蒙源码根目录) OH_ROOT=/path/to/openharmony TC_BIN=$OH_ROOT/prebuilts/gcc/linux-x86/riscv64/spacemit-riscv-gcc/bin # 注意: /usr/bin 必须在前,避免工具链自带的python3覆盖系统python3 export PATH=/usr/bin:$TC_BIN:$PATH # 交叉编译器 export CC=riscv64-unknown-linux-gnu-gcc export CXX=riscv64-unknown-linux-gnu-g++ export AR=riscv64-unknown-linux-gnu-ar export RANLIB=riscv64-unknown-linux-gnu-ranlib export NM=riscv64-unknown-linux-gnu-nm export STRIP=riscv64-unknown-linux-gnu-strip # Host编译器 (编译构建期间需要在x86_64上运行的工具) export CC_host=gcc export CXX_host=g++ # 静态链接标志 (关键: 使node不依赖目标系统的glibc/musl) export LDFLAGS="-static -static-libgcc" export CXXFLAGS="-static-libstdc++" ``` ### 步骤三:Configure + Make ```bash rm -rf out python3 configure \ --dest-cpu=riscv64 \ --dest-os=linux \ --cross-compiling \ --prefix=/opt/node \ --without-intl \ --openssl-no-asm \ --without-snapshot make -j64 ``` **configure 参数说明:** | 参数 | 说明 | |------|------| | `--dest-cpu=riscv64` | 目标CPU架构 | | `--dest-os=linux` | 目标操作系统 | | `--cross-compiling` | 交叉编译模式 | | `--without-intl` | 禁用ICU (减小体积,express v5等依赖ICU的包不可用) | | `--openssl-no-asm` | 禁用OpenSSL汇编 (交叉编译器不支持目标架构汇编) | | `--without-snapshot` | 禁用V8快照 (减小体积) | ### 步骤四:Strip + 打包 ```bash # 去除调试信息 riscv64-unknown-linux-gnu-strip out/Release/node -o out/Release/node.stripped # 打包 mkdir -p /tmp/deploy/bin /tmp/deploy/lib/node_modules cp out/Release/node.stripped /tmp/deploy/bin/node cp -r deps/npm /tmp/deploy/lib/node_modules/npm cp -r deps/corepack /tmp/deploy/lib/node_modules/corepack # npm/npx shell脚本 cat > /tmp/deploy/bin/npm << 'EOF' #!/bin/sh exec /data/node/bin/node /data/node/lib/node_modules/npm/bin/npm-cli.js "$@" EOF cat > /tmp/deploy/bin/npx << 'EOF' #!/bin/sh exec /data/node/bin/node /data/node/lib/node_modules/npm/bin/npx-cli.js "$@" EOF chmod +x /tmp/deploy/bin/* cd /tmp/deploy && tar czf /tmp/node-ohos-static-riscv64.tar.gz . ``` ### 步骤五:上传到鸿蒙设备 ```bash # 部署 (将 DEVICE_IP 替换为实际设备地址) DEVICE_IP=root@10.0.90.166 NODE_DIR=/data/node ssh $DEVICE_IP "rm -rf $NODE_DIR && mkdir -p $NODE_DIR" scp /tmp/node-ohos-static-riscv64.tar.gz $DEVICE_IP:$NODE_DIR/ ssh $DEVICE_IP "cd $NODE_DIR && tar xzf node-ohos-static-riscv64.tar.gz && rm node-ohos-static-riscv64.tar.gz && chmod +x bin/node bin/npm bin/npx" # 验证 ssh $DEVICE_IP "$NODE_DIR/bin/node --version" # 输出: v22.16.0 ``` ## 在设备上使用 ```bash # SSH连接设备 ssh root@10.0.90.166 # 直接运行 (静态链接,无需设置LD_LIBRARY_PATH) /data/node/bin/node --version # 输出: v22.16.0 /data/node/bin/node -e "console.log(process.arch, process.platform)" # 输出: riscv64 linux # 使用npm安装包 export HOME=/data /data/node/bin/npm config set registry https://registry.npmmirror.com/ /data/node/bin/npm install lodash express@4 ``` ## 常见问题 ### Q1: configure 报错 `python3: error while loading shared libraries` **原因:** 工具链 `bin/` 目录下有一个 `python3`(GCC 的 Python 绑定),覆盖了系统 python3。 **解决:** PATH 中将 `/usr/bin` 放在工具链目录前面:`export PATH=/usr/bin:$TC_BIN:$PATH` ### Q2: make 报错 `No rule to make target ... .deps/...` **原因:** 源码所在路径过深,make 生成的 `.deps` 文件会拼接完整路径,超出文件系统路径长度限制。 **解决:** 将源码放在浅路径(如 `/tmp/nodejs-build/`)。官网下载的 tar 包解压到 `/tmp` 下路径足够短。 ### Q3: OpenSSL 编译报错 `-m64` **原因:** OpenSSL 默认在 x86_64 上使用 `-m64`,交叉编译器不支持此选项。 **解决:** configure 添加 `--openssl-no-asm`。 ### Q4: `bytecode_builtins_list_generator` 无法执行 **原因:** 未设置 `CC_host`/`CXX_host`,导致 host 工具也被交叉编译为 riscv64,无法在 x86_64 上运行。 **解决:** 设置 `export CC_host=gcc CXX_host=g++`。 ### Q5: 运行时报 `ld-linux-riscv64-lp64d.so.1 not found` **原因:** 使用了动态链接,但鸿蒙设备使用 musl libc(动态链接器为 `ld-musl-riscv64.so.1`),glibc 动态链接器不存在。 **解决:** 编译时添加静态链接标志 `LDFLAGS="-static -static-libgcc" CXXFLAGS="-static-libstdc++"`。 ### Q6: express v5 报错 `Invalid regular expression` **原因:** express v5 使用 `\p{ID_Start}` Unicode 属性转义,需要 ICU 支持。Node.js 编译时使用了 `--without-intl`。 **解决:** 使用 express v4(`npm install express@4`)。 ### Q7: chalk v5 无法 require **原因:** chalk v5 是纯 ESM 模块,CommonJS 环境无法 `require()`。 **解决:** 使用 chalk v4(`npm install chalk@4`)。 ### Q8: sql.js (WASM SQLite) 报 OOM **原因:** V8 的 WASM 内存分配在 riscv64 平台存在限制。 **解决:** 使用纯 JS 替代方案(lokijs、nedb)。 ## 编译产物信息 | 项目 | 值 | |------|------| | 二进制格式 | ELF 64-bit LSB executable, UCB RISC-V, RVC, double-float ABI | | 链接方式 | statically linked | | strip 后大小 | 50MB | | 压缩包大小 | 24MB | | 运行时依赖 | 无 | | Node.js 版本 | v22.16.0 | | npm 版本 | 10.9.2 | | 交叉编译器 | GCC 13.2.1 (OH prebuilts) | ## 测试验证结果 在 OpenHarmony (riscv64, Spacemit X100) 上验证 48 项测试全部通过: | 类别 | 结果 | |------|------| | 核心功能 (crypto/HTTP/fs/性能) | 9/9 | | npm 包功能 (27个包) | 27/27 | | 网络请求/HTTP服务/文件I/O/异步 | 12/12 | ### 已验证的 npm 包 (27个) | 类别 | 包 | |------|------| | 工具库 | lodash, dayjs, uuid, semver, mathjs | | Web框架 | express@4, axios, ws | | 数据处理 | csv-parse, ini, yamljs, iconv-lite, zod, mime-types | | 模板引擎 | ejs, pug, handlebars, markdown-it | | CLI/调试 | commander, chalk@4, debug, winston, nodemailer | | 异步/文件 | async, glob, rimraf, js-beautify |