欢迎加入【开源鸿蒙PC社区】,一起共建鸿蒙化C/C++三方库生态。
欢迎在【PC社区】平台贡献你的项目。
仓库: libuv/libuv v1.52.1 — Cross-platform asynchronous I/O library
适配平台: 鸿蒙PC


资源地址
libuv 上游仓库https://github.com/libuv/libuv
libuv 文档https://docs.libuv.org/
lycium_plusplus 框架https://atomgit.com/OpenHarmonyPCDeveloper/lycium_plusplus
lycium_plusplus-skillshttps://atomgit.com/unisources/lycium_plusplus-skills
libuv 适配仓库https://atomgit.com/unisources/libuv

在这里插入图片描述

目录

  1. 前言
  2. 什么是鸿蒙化适配?
  3. Step 1:HPKBUILD 骨架生成
  4. Step 2:构建环境检查
  5. Step 3:问题发现与修复
  6. Step 4:构建验证
  7. 经验总结与最佳实践

一、前言

不知道你有没有这种经历:交叉编译一个C/C++库,配置了半小时工具链,结果第一个 cmake 就报 ${CMAKE} not found……好不容易跑起来了,又冒出几百行 cpu_set_t 未定义的编译错误。每修一个 Bug,要等 5-15 分钟编译,然后发现下一个错误。

libuv 是跨平台异步 I/O 库的核心实现,Node.js、Luvit 等运行时都依赖它。将它移植到鸿蒙 PC 平台,可以让更多 Node.js 生态的应用运行在 OpenHarmony 上。

本文完整记录 libuv v1.52.1 在鸿蒙 PC 上的适配过程,从 HPKBUILD 生成到最终构建验证,全程使用 AtomCode Skills 自动化工作流。


二、什么是鸿蒙化适配?

OpenHarmony(开源鸿蒙)使用 musl libc 而非 Linux 常用的 glibc,并使用自有的 OHOS SDK 交叉编译工具链。将 Linux 生态下的 C/C++ 三方库移植到 OpenHarmony,通常需要:

  • 编写 HPKBUILD 构建脚本(基于 lycium_plusplus 框架的包构建描述文件)
  • 配置交叉编译工具链(使用 OHOS SDK 中的 aarch64-linux-ohos-clang
  • 处理 musl libc 与 glibc 的 API 差异(如 cpu_set_t_GNU_SOURCE
  • 解决构建系统的平台检测问题(CMake 的 CMAKE_SYSTEM_NAME
  • 验证产物在 OHOS 设备上的正确运行

AtomCode Skills 工作流总览

本次适配全程使用以下 Skills:

Skill作用
/new-package生成 HPKBUILD 骨架
/build-check验证交叉编译环境
/porting-reviewer审查 HPKBUILD 和潜在问题
/dependency-reviewer检查依赖声明完整性

/new-package

HPKBUILD 骨架

/build-check

环境就绪

/porting-reviewer

问题发现与修复

构建验证

适配完成


三、Step 1:HPKBUILD 骨架生成

3.1 使用 /new-package Skill

libuv 是一个 CMake 项目,使用 /new-package libuv 1.52.1 "Cross-platform asynchronous I/O library" 自动生成 HPKBUILD 骨架。

3.2 关键修改

CMake 项目与 Makefile 项目的 HPKBUILD 差异:

差异项CMake 项目(libuv)Makefile 项目
buildtoolscmakemake
makedepends通常为空(使用 OHOS SDK 内置 cmake)可能需要 make
cmake 路径${OHOS_SDK}/native/build-tools/cmake/bin/cmake不适用
工具链文件${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake直接设置 cc 变量

3.3 完整 HPKBUILD

# HPKBUILD - libuv
# Maintainer: allincoding <3384684593@qq.com>

pkgname=libuv
pkgver=1.52.1
pkgrel=0
pkgdesc="Cross-platform asynchronous I/O library (libuv)"
url="https://github.com/libuv/libuv"
archs=("arm64-v8a")
license=("MIT")
depends=()
makedepends=()

source="https://github.com/libuv/libuv/archive/refs/tags/v$pkgver.tar.gz"

autounpack=true
downloadpackage=true
buildtools="cmake"
builddir=libuv-$pkgver
packagename=v$pkgver.tar.gz
patchflag=false

3.4 关键变量说明

变量说明
pkgnamelibuv必须与 thirdparty/ 目录名一致,lycium 通过目录名索引包
pkgver1.52.1与上游 Release Tag 一致,用于拼接下载 URL
archs("arm64-v8a")目标架构,鸿蒙 PC 当前仅 arm64
license("MIT")与上游许可证一致
buildtoolscmake指定构建工具类型
patchflagfalse本库无需 patch

3.5 build() 函数解析

build() {
    cd $builddir

    # Step 1: CMake 配置 —— 使用 OHOS SDK 内置 cmake 和交叉编译工具链
    ${OHOS_SDK}/native/build-tools/cmake/bin/cmake \
        -DCMAKE_TOOLCHAIN_FILE=${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake \
        -DOHOS_ARCH=$ARCH \
        -DCMAKE_C_COMPILER=${cc} \
        -DCMAKE_CXX_COMPILER=${cxx} \
        -DCMAKE_C_FLAGS="${cflags} -D_GNU_SOURCE -Wno-unused-command-line-argument" \
        -DCMAKE_CXX_FLAGS="${cxxflags} -D_GNU_SOURCE -Wno-unused-command-line-argument" \
        -DCMAKE_INSTALL_PREFIX=$LYCIUM_ROOT/usr/$pkgname/$ARCH \
        -DLIBUV_BUILD_SHARED=OFF \
        -DLIBUV_BUILD_TESTS=OFF \
        -DCMAKE_BUILD_TYPE=Release \
        -B$ARCH-build -S./ \
        -Wno-dev \
        2>&1 | tee -a "${buildlog}"

    # Step 2: 编译
    $MAKE -C $ARCH-build -j$(nproc) \
        2>&1 | tee -a "${buildlog}"

    # Step 3: 安装到 LYCIUM_ROOT
    $MAKE -C $ARCH-build install \
        2>&1 | tee -a "${buildlog}"
}
行/选项作用为什么需要
OHOS_SDK/cmake使用 OHOS SDK 内置的 cmake系统 cmake 版本可能不兼容,SDK 内置版本与工具链匹配
CMAKE_TOOLCHAIN_FILE指定交叉编译工具链告诉 CMake 使用 OHOS 的 aarch64 工具链
CMAKE_INSTALL_PREFIX安装到统一输出目录$LYCIUM_ROOT/usr/$pkgname/$ARCH 是 lycium 的标准产物路径
LIBUV_BUILD_SHARED=OFF关闭动态库,只生成静态库OHOS 应用更倾向于静态链接以减少运行时依赖,也避免链接 linux 特定源文件
-D_GNU_SOURCE启用 GNU 扩展musl libc 的 cpu_set_t 等类型需要此宏定义
-Wno-dev抑制 CMake 开发者警告避免大量无意义警告干扰真正的错误

四、Step 2:构建环境检查

4.1 使用 /build-check Skill

执行 /build-check 自动检测交叉编译环境:

$ /build-check
[OHOS SDK]    OHOS_SDK=/home/ohpkg/linux           ✅
[Toolchain]   aarch64-linux-ohos-clang              ✅
[CMake]       cmake 3.22+                           ✅
[Output]      /home/lycium_plusplus/lycium/usr      ✅

4.2 常见缺失项及修复

缺失项错误现象修复方式
OHOS SDK 未安装command not found: ohos下载 OHOS SDK 并配置 OHOS_SDK 环境变量
工具链架构不匹配unknown architecture检查 prepare() 中工具链前缀是否为 aarch64-linux-ohos-
cmake 路径错误-B: command not found使用 ${OHOS_SDK}/native/build-tools/cmake/bin/cmake 全路径

五、Step 3:问题发现与修复

5.1 审查维度总览

审查维度检查项状态风险等级
构建系统CMakeLists.txt 兼容性⚠️
依赖管理depends / makedepends 完整性
工具链CC/CXX/CFLAGS 交叉编译适配
musl 兼容cpu_set_t等 glibc 特定 API
许可证MIT 合规

5.2 问题发现清单

#问题分类具体问题根因修复方案
1构建工具${CMAKE} 未定义lycium HPKBUILD 中 ${CMAKE} 变量不生效使用 $OHOS_SDK 全路径调用 cmake
2musl 兼容cpu_set_t / CPU_SETSIZE 未定义OHOS musl 不默认导出 CPU 亲和性 APICFLAGS 添加 -D_GNU_SOURCE
3构建系统uv__iou_fs_* 等链接错误共享库尝试链接 linux io_uring 特定源文件-DLIBUV_BUILD_SHARED=OFF 仅构建静态库
4安装路径cmake 安装到 / 根目录$dep_install_dir 变量为空改用 $LYCIUM_ROOT/usr/$pkgname/$ARCH
问题 1 根因分析:${CMAKE} 未定义

现象

/home/lycium_plusplus/thirdparty/libuv/HPKBUILD: line 55: -B: command not found

根因:lycium 框架早期版本提供 ${CMAKE} 变量,但当前版本不再自动注入。需要使用 ${OHOS_SDK}/native/build-tools/cmake/bin/cmake 全路径。同时,${CMAKE_CROSSFILE} 也应替换为 ${OHOS_SDK}/native/build/cmake/ohos.toolchain.cmake 全路径。

问题 2 根因分析:musl libc 缺少 cpu_set_t

现象src/unix/core.c: error: use of undeclared identifier 'cpu_set_t'

文件错误类型数量
src/unix/core.cCPU_SETSIZE, cpu_set_t, CPU_COUNT7 个
src/unix/thread.ccpu_set_t, 线程亲和性 API10 个

根因:libuv 的 core.cthread.c 使用 sched_getaffinityCPU_SET 宏获取/设置 CPU 亲和性。在 glibc 下,这些定义通过 <sched.h> 自动导出。而 musl libc 要求显式定义 _GNU_SOURCE 才能导出。OHOS SDK 默认不定义此宏。

修复:在 CMake 的 CFLAGS / CXXFLAGS 中添加 -D_GNU_SOURCE

- -DCMAKE_C_FLAGS="${cflags} -Wno-unused-command-line-argument"
+ -DCMAKE_C_FLAGS="${cflags} -D_GNU_SOURCE -Wno-unused-command-line-argument"
问题 3 根因分析:共享库链接 linux 特定符号

现象:链接阶段报 19 个 undefined symbol: uv__iou_fs_openuv__io_poll 等错误。

根因:libuv 默认同时构建共享库 (uv) 和静态库 (uv_a)。共享库需要链接所有源文件,但 src/unix/ 下的 iou.clinux-core.csysinfo-loadavg.c 等文件包含 linux 特有的系统调用(io_uring、getrandomstatx 等),OHOS musl libc 不提供这些 API。

修复:关闭共享库构建,只生成静态库:

+ -DLIBUV_BUILD_SHARED=OFF

静态库 uv_a 采用按需链接,编译阶段只生成 .o 文件不检查外部符号,因此未用到的 linux 特定符号不会产生链接错误。

问题 4 根因分析:安装路径为空

现象:cmake install 将文件安装到 /include//lib/libuv.a 等根目录路径。

根因${dep_install_dir} 在 lycium 的构建环境中未被定义,CMake 的 CMAKE_INSTALL_PREFIX 接收到空值,回退为默认值 /

修复:使用 lycium 标准产物路径:

- -DCMAKE_INSTALL_PREFIX=${dep_install_dir}
+ -DCMAKE_INSTALL_PREFIX=$LYCIUM_ROOT/usr/$pkgname/$ARCH

5.3 修复方案可行性评估

方案工作量风险是否最终采用
方案A(采用):CFLAGS + _GNU_SOURCE1 行修改
方案B(备选):修改 libuv 源码添加 #define _GNU_SOURCE2 行修改❌ 维护成本高
方案C(采用):LIBUV_BUILD_SHARED=OFF1 行修改

关键点:libuv 适配不需要任何源码级别的修改——所有问题都通过 HPKBUILD 配置层面解决。这得益于 libuv 自身对 CMake 和 Clang 的良好兼容性。


六、Step 4:构建验证

6.1 构建日志

$ cd /home/lycium_plusplus/lycium && ./build.sh libuv
...
-- summary of build options:
    Install prefix:  /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a
    Target system:   OHOS
    Compiler:
      C compiler:    /home/ohpkg/linux/native/llvm/bin/clang (Clang)
      CFLAGS:        -D_GNU_SOURCE -Wno-unused-command-line-argument -D__MUSL__
...
[100%] Linking C static library libuv.a
[100%] Built target uv_a
Install the project...
-- Installing: /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a/lib/libuv.a
-- Installing: /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a/include/uv.h
...
libuv validation: verify that libuv.a is non-empty
✅ libuv.a found
-rw-r--r-- 1 root root 373K libuv.a
  Symbol count: 420
Build libuv 1.52.1 end!
ALL JOBS DONE!!!

6.2 构建产物清单

$ find /home/lycium_plusplus/lycium/usr/libuv -type f | sort
lycium/usr/libuv/arm64-v8a/include/uv.h                   # 主头文件
lycium/usr/libuv/arm64-v8a/include/uv/errno.h              # 错误码定义
lycium/usr/libuv/arm64-v8a/include/uv/threadpool.h         # 线程池接口
lycium/usr/libuv/arm64-v8a/include/uv/version.h            # 版本信息
lycium/usr/libuv/arm64-v8a/include/uv/linux.h              # linux 平台定义
lycium/usr/libuv/arm64-v8a/include/uv/unix.h               # unix 通用定义
lycium/usr/libuv/arm64-v8a/lib/libuv.a                     # 静态库(373KB)
lycium/usr/libuv/arm64-v8a/lib/pkgconfig/libuv-static.pc   # pkg-config 配置
lycium/usr/libuv/arm64-v8a/lib/cmake/libuv/                # CMake 配置
lycium/usr/libuv/arm64-v8a/share/doc/libuv/LICENSE         # 许可证

6.3 产物正确性验证

文件类型验证(file 命令)
$ file /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a/lib/libuv.a
libuv.a: current ar archive    # ✅ arm64 架构静态库
符号表验证(nm 命令)
$ nm /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a/lib/libuv.a | grep " T uv_" | head -5
0000000000000000 T uv__fs_poll_close
0000000000000000 T uv_fs_poll_getpath
0000000000000000 T uv_fs_poll_init
0000000000000000 T uv_fs_poll_start
0000000000000000 T uv_fs_poll_stop
...
Total: 420 T symbols
字符串检查(strings 命令)
$ strings /home/lycium_plusplus/lycium/usr/libuv/arm64-v8a/lib/libuv.a | grep -i "libuv"
libuv
libuv version

6.4 验证结果总表

检查项命令预期结果实际结果状态
文件架构fileARM aarch64current ar archive
关键符号nm至少包含 uv_run420 个 T 符号
版本信息strings包含版本号
文件大小ls -lh非空373 KB

七、经验总结与最佳实践

7.1 本次适配遇到的典型问题分类

问题类别出现次数占比典型代表
musl libc 兼容性125%cpu_set_t_GNU_SOURCE
构建系统配置250%${CMAKE} 路径、LIBUV_BUILD_SHARED
安装路径125%dep_install_dir 为空

7.2 鸿蒙化适配最佳实践

  1. CMake 项目优先使用 OHOS SDK 内置的 cmake:lycium 框架中 ${CMAKE} 变量可能不可用,应使用 ${OHOS_SDK}/native/build-tools/cmake/bin/cmake 全路径。系统 cmake 版本可能与 SDK 工具链不兼容。

  2. musl 兼容性问题先尝试 -D_GNU_SOURCE:许多 glibc 特有的类型、宏、函数在 musl libc 下需要显式定义 _GNU_SOURCE 才能导出。这是修复 musl 兼容性问题最高性价比的手段——加一行 CFLAGS 而非修改源码。

  3. 静态库优先于动态库:OHOS 应用场景下,静态链接减少了运行时依赖和版本兼容问题。对于 libuv 这类大型库,关闭共享库构建 (LIBUV_BUILD_SHARED=OFF) 还能避免 linux 特有的系统调用导致的链接错误。

7.3 同类库适配对比

对比维度KCP(单文件 C 库)libuv(当前库)
构建系统无(直接 clang 编译)CMake
文件规模1 个 .c + 1 个 .h50+ 源文件
musl 兼容无需修改CFLAGS 加 -D_GNU_SOURCE
修复数量4 个4 个
适配耗时3 小时2 小时

7.4 总结

libuv 的鸿蒙 PC 适配是一个典型的 CMake 项目移植案例。与 KCP(单文件 C 库)不同,libuv 涉及 50+ 源文件、多平台条件编译,适配的核心在于配置层面而非源码层面的调整:

  • 替换 ${CMAKE} 为 SDK 全路径
  • 添加 -D_GNU_SOURCE 解决 musl 兼容性
  • 关闭共享库构建避免 linux 特定符号
  • 修正安装路径为 lycium 标准产物目录

最终产物 libuv.a(373KB、420 个导出符号)可直接用于鸿蒙应用的 NAPI 集成。

下期预告:下一期我们将基于 libuv 的交叉编译产物,通过 NAPI 桥接集成到 HarmonyOS 应用中,实现事件循环、网络请求、文件 I/O 等能力的 ArkTS 调用。

附录:最终文件结构

thirdparty/libuv/
├── HPKBUILD            # 构建脚本
├── SHA512SUM           # 源码校验和
├── v1.52.1.tar.gz      # 源码包
└── libuv-1.52.1/       # 解压目录
    ├── CMakeLists.txt
    ├── src/             # 源码
    ├── include/         # 头文件
    └── arm64-v8a-build/ # 构建输出
Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐