把 glibc 移植到鸿蒙 PC 上:它能用来做什么
1 前言
鸿蒙 PC 的鸿蒙内核(HongMeng kernel)不是 Linux,但 ABI 与 Linux 深度兼容。用户态的 libc 是定制版的 musl libc。
这意味着,鸿蒙 PC 在“蹭生态”这件事上有得天独厚的优势。它不仅可以运行 ohos-sdk 编译的 aarch64-linux-ohos 制品,Linux 世界的一部分 aarch64-linux-musl 制品也能直接拿来跑。
但 Linux 世界还有大量的官方预编译二进制只发 glibc 版本(Node.js、Neovim、CMake 等),它们并不能被鸿蒙 PC“蹭”到。
最近我把上游 Homebrew 的 glibc 2.39 移植进了 Harmonybrew,brew install glibc 即可安装。鸿蒙 PC 从此连 glibc 生态也能“蹭”了。
2 移植简介
上游 glibc 不能直接在鸿蒙内核(HongMeng kernel)上运行,主要是内核行为差异:
- 鸿蒙内核对可执行段的 mmap 权限检查更严格
- 一批系统调用被安全策略直接 SIGSYS 杀死
- EPOLLONESHOT 注册不 disarm 导致 EPOLLOUT 幽灵投递
移植共打了 9 个补丁逐一规避。这里不展开,感兴趣的读者可以直接看代码:
- formula:https://atomgit.com/Harmonybrew/homebrew-core/blob/main/Formula/g/glibc.rb
- 补丁目录:https://atomgit.com/Harmonybrew/homebrew-core/tree/main/Patches/glibc
3 先跑起来
先把 glibc 和两个工具装上:
brew install -y glibc patchelf ohos-selfsign
在鸿蒙 PC 上跑 glibc 程序,本质是让程序用 brewed glibc 的 loader,而不是系统里不存在的 /lib/ld-linux-aarch64.so.1。
有两种使用方式:
方式一:通过 ld.so 启动程序
# 鸿蒙 PC 上的二进制需要签名后才能运行
selfsign ./<your-program>
# 通过 ld.so 启动程序
$(brew --prefix)/opt/glibc/bin/ld.so ./<your-program> <args>
方式二:patchelf 改解释器
# 把二进制的 PT_INTERP 永久改成 brewed loader
patchelf --set-interpreter $(brew --prefix)/opt/glibc/lib/ld-linux-aarch64.so.1 ./<your-program>
# 鸿蒙 PC 上的二进制需要签名后才能运行
# 注意:先改解释器再签名,顺序不能颠倒
selfsign ./<your-program>
# 正常执行即可
./<your-program> <args>
需要留意两点:
- 鸿蒙 PC 强制校验可执行文件和 .so 的代码签名,所以自己下载的 Linux 二进制要用
selfsign进行签名后才能运行。selfsign是一个第三方的二进制签名工具,与官方的binary-sign-tool一样,都可以对鸿蒙 PC 上的二进制进行自签名。不过它比官方签名工具更健壮,更不容易把文件签坏。因此本文选用这个签名工具。 - 鸿蒙 PC 不允许修改已通过验签的二进制。如果一个二进制已经拥有了正确的代码签名且已经被正常运行过一次(意味着它已经通过了验签),你将无法再对它做任何写操作。如果你需要修改这类文件(例如再次修改它的解释器),你需要先将它删掉再重新拷贝一份到原位置中,再进行修改。
4 实测它能用来做什么
4.1 Bun:单文件,开箱即用
Bun 官方 linux-aarch64 版是单个二进制,只依赖 glibc 基础库,是最简单的一个:
curl -LO https://github.com/oven-sh/bun/releases/latest/download/bun-linux-aarch64.zip
unzip bun-linux-aarch64.zip
patchelf --set-interpreter $(brew --prefix)/opt/glibc/lib/ld-linux-aarch64.so.1 bun-linux-aarch64/bun
selfsign bun-linux-aarch64/bun
./bun-linux-aarch64/bun --version
实测 1.4.3 正常运行。
4.2 OpenJDK:从编译到子进程全通
Temurin 21(Adoptium 官方 linux-aarch64 构建),自带的库很全,也不需要任何外部运行库:
curl -LO "https://api.adoptium.net/v3/binary/latest/21/ga/linux/aarch64/jdk/hotspot/normal/eclipse" -o jdk.tar.gz
mkdir jdk && tar -xzf jdk.tar.gz -C jdk --strip-components=1
# 改两个可执行入口的解释器:启动器 bin/java 和起子进程用的 lib/jspawnhelper
patchelf --set-interpreter $(brew --prefix)/opt/glibc/lib/ld-linux-aarch64.so.1 jdk/bin/java
patchelf --set-interpreter $(brew --prefix)/opt/glibc/lib/ld-linux-aarch64.so.1 jdk/lib/jspawnhelper
# 改过的可执行文件和所有 .so 都要签名
selfsign jdk/bin/java
selfsign jdk/lib/jspawnhelper
find jdk/lib -name "*.so" -type f | while read f; do selfsign "$f"; done
之后 ./jdk/bin/java -version、./jdk/bin/javac 直接可用。实测 javac 编译、线程池、JIT、网络栈(HttpClient)、子进程全部工作,鸿蒙 PC 上现在可以用 GNU/Linux 的 JDK 做 Java 开发了。
4.3 Node.js:需要先补三个 C++ 运行库
Node.js 比上面两个麻烦一点:它是 C++ 程序,除了 glibc 还需要 libstdc++.so.6、libgcc_s.so.1、libatomic.so.1。Harmonybrew 里的 gcc 是 ohos-sdk(musl)构建的,它的同名库不能给 glibc 程序用,所以我们从 Debian 官方源提取:
# 需要 bsdtar 解 deb 包
brew install -y libarchive
# 下载三个 deb(版本号会随 Debian 更新变化,404 就到目录里找最新的:
# https://deb.debian.org/debian/pool/main/g/gcc-14/ )
mkdir -p ~/glibc-runtime-libs/debs && cd ~/glibc-runtime-libs/debs
curl -LO https://deb.debian.org/debian/pool/main/g/gcc-14/libstdc++6_14.2.0-19_arm64.deb
curl -LO https://deb.debian.org/debian/pool/main/g/gcc-14/libgcc-s1_14.2.0-19_arm64.deb
curl -LO https://deb.debian.org/debian/pool/main/g/gcc-14/libatomic1_14.2.0-19_arm64.deb
# 解包:deb 外层是 ar 归档、内层是 data.tar.zst,bsdtar 两层都能解
cd ~/glibc-runtime-libs
for d in debs/*.deb; do
mkdir -p tmp && (cd tmp && bsdtar -xf "../$d" && bsdtar -xf data.tar.zst)
done
# 取出库文件并签名
cp -L tmp/usr/lib/aarch64-linux-gnu/libstdc++.so.6.0.* ./libstdc++.so.6
cp -L tmp/usr/lib/aarch64-linux-gnu/libgcc_s.so.1 ./libgcc_s.so.1
cp -L tmp/usr/lib/aarch64-linux-gnu/libatomic.so.1.2.0 ./libatomic.so.1
rm -rf tmp debs
for f in *.so*; do selfsign "$f"; done
补充说明为什么选 Debian:Debian 13 的系统 glibc 虽然更新,但这三个库实际引用的符号最高只到 GLIBC_2.38,与 brewed glibc 2.39 兼容,本文已实测;不推荐 Arch 这类滚动发行版,它们的运行库有可能会引用 2.39 里还不存在的符号版本。
把这个目录注册进 glibc 的库缓存,之后所有 glibc 程序都能自动找到这三个库,一劳永逸:
mkdir -p $(brew --prefix)/etc/ld.so.conf.d
echo "$HOME/glibc-runtime-libs" > $(brew --prefix)/etc/ld.so.conf.d/60-glibc-runtime-libs.conf
$(brew --prefix)/opt/glibc/sbin/ldconfig
然后下载 Node.js,改解释器、签名、直接跑:
curl -LO https://nodejs.org/dist/v26.11.1/node-v26.11.1-linux-arm64.tar.gz
tar -xzf node-v26.11.1-linux-arm64.tar.gz
patchelf --set-interpreter $(brew --prefix)/opt/glibc/lib/ld-linux-aarch64.so.1 node-v26.11.1-linux-arm64/bin/node
selfsign node-v26.11.1-linux-arm64/bin/node
./node-v26.11.1-linux-arm64/bin/node -e "console.log('hello')"
事件循环、HTTP 服务器、Worker 线程、JIT 全部正常,可以直接拿它在鸿蒙 PC 上跑现成的 Node.js 服务端程序。
4.4 Claude Code:真的能干活
前面三个都是语言运行时,最后跑一个真实的大型应用:glibc 版 Claude Code 在鸿蒙 PC 上完整可用,读写文件、调编译器、起子进程、访问模型 API 全部正常。
完整的教程见我之前写的专题文章:在鸿蒙 PC 上使用 Claude Code(最新的 Bun 版本)。所需工具与本文相同(glibc、patchelf、ohos-selfsign),照着做即可。
5 目前的限制
这套方案是“用 glibc 做 Linux 兼容层”,有些限制是机制本身决定的:
- 涉及系统安全限制的能力绕不过去。比如需要挂载文件系统、创建设备节点、访问内核特权接口的程序,glibc 无能为力,这不是兼容层能解决的。
- 鸿蒙内核有一批系统调用被安全策略拦截。brewed glibc 的处理是让它们返回 ENOSYS,程序走回退路径。个别程序如果强依赖这些能力且没有回退逻辑,就无法运行。
- uname 标识是内核真实返回值:glibc 不做修改、如实上报(sysname 是
HarmonyOS而不是Linux,release 是HongMeng Kernel 1.13.0而不是 Linux 风格的版本号)。个别会主动检查系统标识或内核版本的程序可能因此无法正常工作。遇到这类问题时可以通过 uname-is-linux 等方案按需做平台标识伪装。注意:Harmonybrew 里面的 uname-is-linux 制品不能直接用于 glibc 程序,因为它是基于 musl 构建的。如需使用请自行基于 glibc 构建。 - localedef 生成个别大型 locale(如 en_US.UTF-8)在鸿蒙内核上还有未查明的问题,C.UTF-8 正常。
- 鸿蒙内核对个别能力(如 SVE 向量长度上报)行为特殊,OpenJDK 会打印一条无害警告并自动降级。
6 结语
glibc 的移植让鸿蒙 PC 第一次具备了直接运行 GNU/Linux 预编译生态的能力:Bun、OpenJDK、Node、Claude Code 这些现成的官方二进制现在都能在鸿蒙内核上正常工作。它不是要取代 musl 生态(Harmonybrew 仍然是主力),而是为 GNU/Linux 程序打开一扇门。
更多推荐





所有评论(0)