[鸿蒙PC命令行移植适配]移植rust三方库ox到鸿蒙PC的完整实践
ox是一个由 curlpipe 开发的简洁且灵活的 Rust 文本编辑器,旨在提供一个轻量级、可编程的终端编辑体验。它支持 Lua 脚本扩展、语法高亮、多光标编辑、分屏视图等特性,同时保持极低的资源占用,是vimnano之外的全新选择。
欢迎加入【开源鸿蒙PC社区】,一起共建鸿蒙化C/C++三方库生态。
前言
ox 是一个由 curlpipe 开发的简洁且灵活的 Rust 文本编辑器,旨在提供一个轻量级、可编程的终端编辑体验。它支持 Lua 脚本扩展、语法高亮、多光标编辑、分屏视图等特性,同时保持极低的资源占用,是 vim/nano 之外的全新选择。
前置条件
| 环境/工具 | 描述 |
|---|---|
| 适配库 | ox |
| 开源协议 | "GPL-2.0" |
| 源码版本 | 0.7.7 |
| 目标平台 | 鸿蒙PC |
| 依赖项 | 无 |
| 操作系统平台 | macOS |
| 原仓库地址 | https://github.com/curlpipe/ox |
| 鸿蒙化适配仓库地址 | https://atomgit.com/OpenHarmonyPCDeveloper/ohos-ox |
在Ubuntu中搭建鸿蒙PC 三方库交叉编译构建开发环境 |
https://blog.csdn.net/zl392321162/article/details/159284760 |
在 macOS 中搭建鸿蒙 PC 三方库交叉编译开发环境 |
https://blog.csdn.net/zl392321162/article/details/159284830 |
Windows 10 上安装和使用 WSL 2、安装 Ubuntu 24 详细指南 |
https://blog.csdn.net/yyz_1987/article/details/148545443 |
| 鸿蒙 PC 命令行适配指南(Mac 版) | https://blog.csdn.net/qq_39132095/article/details/154796658 |
| 鸿蒙 PC 生态三方软件移植:开发环境搭建及三方库移植指南 | https://blog.csdn.net/yyz_1987/article/details/154794871 |
OpenHarmony Linux 命令行工具适配实战:基于 Cursor × WSL 的 tree 2.2.1 交叉编译与 HNP 打包全流程指南 |
https://weishuo.blog.csdn.net/article/details/155140843 |
社区维护的鸿蒙 PC 生态命令行工具构建框架 lycium_plusplus |
https://atomgit.com/OpenHarmonyPCDeveloper/lycium_plusplus |
| 支持Rust三方库适配的扩展lycium框架 | https://atomgit.com/CodexBai/lycium_plusplus.git |
| 鸿蒙PC端二进制文件签名命令行使用指南 | https://blog.csdn.net/jianguo888888/article/details/156644386 |
hnp包验证环境 |
https://bxming.blog.csdn.net/article/details/155073889 |
系列索引
| 篇章 | 标题 | 内容 |
|---|---|---|
| 第一篇 | 概述与环境配置 | Lycium 概念、构建机要求、OHOS SDK 配置 |
| 第二篇 | 项目结构与适配目录创建 | 目录结构、community vs thirdparty、创建适配目录 |
| 第三篇 | HPKBUILD 编写详解 | 元数据字段、过程函数、三种构建系统写法 |
| 第四篇 | 构建执行与产物获取 | 构建流程、日志分析、多库递归、HAP 集成 |
| 第五篇 | 流程图与角色职责 | 完整流程图、各角色职责、协作时序 |
| 第六篇 | 关键注意事项与最佳实践 | 依赖管理、架构超集、日志调试、外部适配仓 |
| 第七篇 | 快速参考与模板 | 入门步骤、模板、完整案例、检查清单 |
| 第八篇「番外」 | 扩展lycium框架使其满足rust三方库适配 | 不改变框架原有设计,增加Rust三方库适配能力 |
一、环境配置
1 OpenHarmony SDK 安装
1.1 下载 SDK(环境搭建)
- 在浏览器中打开 DCP 每日构建列表:https://dcp.openharmony.cn/workbench/cicd/dailybuild/dailylist
- 在列表中按本机操作系统选择对应产物(名称随版本变化,以页面为准):
| 开发机系统 | 选择产物(关键词) |
|---|---|
| Windows / Linux | ohos-sdk-full(OHOS 全量 SDK,用于交叉编译) |
| macOS | mac-sdk-full(Mac 版 SDK 包) |
下载到本机后解压(请将下面文件名替换为你实际下载的包名):
cd ~
# Linux / macOS 示例(包名以 DCP 页面为准)
tar -zvxf <你下载的-sdk-xxx>.tar.gz
Windows 请使用资源管理器或 7-Zip 等工具解压对应 .zip / .tar.gz 包。
说明:每日构建会更新版本与文件名,不要固定使用旧文档中的直链;以 DCP 页面上当前可下载的 SDK 包为准。解压后若顶层目录名不是
ohos-sdk,可将该目录移动或软链为~/ohos-sdk(或 Windows 下放到固定路径),与下文OHOS-SDK配置一致。
再进入 ohos-sdk 根目录解压(文件名以 darwin 目录下为准,下例版本号仅作演示):
cd ~/ohos-sdk # Linux / macOS;Windows 请先 cd 到 OHOS_SDK 目录
unzip native-darwin-arm64-6.0.0.46-Beta1.zip
unzip toolchains-darwin-arm64-6.0.0.46-Beta1.zip
Windows 可对两个 zip 右键解压到当前文件夹,或使用 tar/Expand-Archive 等工具解压到 ohos-sdk 根目录。
解压完成后,应得到 native/、toolchains/ 等目录(含 llvm、sysroot、hnpcli 等),再配置 2.1.3 中的环境变量。
1.2 SDK 目录结构
ohos-sdk/
├── native/
│ ├── llvm/bin/ # 编译器工具链
│ ├── sysroot/ # 系统根目录(头文件和库)
│ └── build-tools/ # 构建工具
└── toolchains/
└── hnpcli # HNP打包工具
1.3 环境变量配置
编辑 ~/.zshrc(如果使用 zsh)或 ~/.bash_profile(如果使用 bash):
# OpenHarmony SDK 路径
export OHOS_SDK=~/ohos-sdk
# 添加到 PATH
export PATH="$OHOS_SDK/native/llvm/bin:$PATH"
export PATH="$OHOS_SDK/native/build-tools/cmake/bin:$PATH"
export PATH="$OHOS_SDK/toolchains/bin:$PATH"
# 验证
source ~/.zshrc # 或 source ~/.bash_profile
1.4 验证 SDK 配置
# 检查 SDK 路径
echo $OHOS_SDK
# 检查工具是否在 PATH 中
which clang
which cmake
which hnpcli
# 检查 SDK 工具目录
ls $OHOS_SDK/native/llvm/bin/
ls $OHOS_SDK/native/build-tools/cmake/bin/
ls $OHOS_SDK/toolchains/
# 验证工具版本
clang --version
cmake --version
hnpcli --version
2 Rust 工具链安装
2.1 安装 Rust
# 安装 Rust(如果未安装)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# 验证安装
rustc --version
cargo --version
2.2 配置 Rust 环境变量
编辑 ~/.zshrc(如果使用 zsh)或 ~/.bash_profile(如果使用 bash):
# Rust 环境变量(通常由 rustup 自动添加)
source ~/.cargo/env
# 验证
source ~/.zshrc # 或 source ~/.bash_profile
rustc --version
cargo --version
二、适配步骤
1. 分析ox构建特性
ox 由Rust语言编写,使用Cargo作为构建系统。编译后产出的二进制命令为ox。
核心特性
-
轻量级终端文本编辑器
ox采用极简设计理念,开箱即用,无需复杂配置即可编辑文本文件。相比于vim/nano,它在保持终端原生体验的同时,融合了现代编辑器的交互特性,二进制体积小、启动速度快,适合在资源受限的鸿蒙PC环境中流畅运行。 -
Lua 脚本扩展
支持通过 Lua 脚本对编辑器行为进行高度定制和扩展。用户可编写 Lua 插件实现自定义快捷键、语法高亮规则、自动补全逻辑等,极大地增强了编辑器的可编程性和灵活性。
-
语法高亮与多语言支持
内置丰富的语法高亮规则,覆盖主流编程语言(Rust、Python、JavaScript、C/C++ 等)和标记语言(Markdown、YAML、TOML 等),搭配自动缩进和行号显示,提供舒适的代码编写体验。
-
多光标编辑
支持多光标同时操作,可以在多个位置同时键入、删除或选择文本,大幅提高批量编辑效率。配合列块选择模式,处理表格化文本或对齐代码时尤为高效。
-
分屏视图和多重缓冲区
支持水平/垂直分屏,可同时在多个窗口中编辑不同文件或同一文件的不同位置。缓冲区管理机制让文件切换无需频繁打开和关闭,保持编辑工作流的连续性。
-
终端集成与 Shell 交互
内置终端面板,无需退出编辑器即可执行 Shell 命令;可配置外部命令管道(编译、运行、格式化等),将编辑与开发工作流无缝集成在同一终端界面下。
2. 创建适配项目
参考前置条件列表完成lycium_plusplus交叉框架编译环境搭建,以及lycium_plusplus交叉框架代码克隆,在lycium_plusplus/RustAdapt创建目标库ox适配目录为ohos-ox。
为什么是
ohos-ox?为了和源库名称做区分,表示该库用于ohos设备。
ohos-ox创建可以借助编辑器工具(如VSCode)或者使用文件夹在lycium_plusplus/RustAdapt目录下创建目标库适配目录ohos-ox,也可以执行以下命令进行创建。
# 我将交叉编译框架克隆在根目录,此处可改为正确的目录地址
cd ~/lycium_plusplus/RustAdapt
mkdir ohos-ox
3. 编写HPKBUILD
然后将lycium/template/HPKBUILD.cargo拷贝到RustAdapt/ohos-ox目录下,并重命名为HPKBUILD,HPKBUILD是lycium交叉编译框架完成编译构建的核心配置文件,定义包的元信息、依赖、构建和打包逻辑。需要根据模板在HPKBUILD开头声明ox的基本信息,这些字段被lycium用于下载、组织和记录:
# lycium_plusplus/RustAdapt/ohos-ox/HPKBUILD
pkgname=ox # 库名
pkgver=0.7.7 # 库版本
pkgrel=0 # 发布号
pkgdesc="A simple but flexible text editor." # 库描述
url="https://github.com/curlpipe/ox" # 官网链接
archs=("arm64-v8a") # cpu 架构
license=("GPL-2.0")
depends=() # 依赖库的目录名 必须保证被依赖的库的archs是当前库的archs的超集
makedepends=("cargo" "rustc") # 构建库时的依赖工具->需要用户安装的工具
source="https://github.com/curlpipe/ox/archive/refs/tags/${pkgver}.tar.gz" # 库源码下载链接
downloadpackage=true # 是否自动下载压缩包,如若不写默认 true. (应对一些特殊情况,代码只能 git clone (项目中依赖 submoudle ))
autounpack=true # 是否自动解压,如若不写默认 true, 如果为 false 则需要用户在 prepare 函数中自行解压
buildtools=cargo # 编译方法: cmake(默认) | configure | cargo | 其它则不在此注入 buildargs,由 build() 自行处理
builddir=ox-${pkgver} # 源码压缩包解压后目录名 编译目录名
packagename=$builddir.tar.gz # 压缩包名
| 字段 | 配置值 | 用途 |
|---|---|---|
pkgname |
ox |
pkgname=ox:包名,用于在 LYCIUM_ROOT/usr/ 下创建安装目录、标识依赖关系。 |
pkgver |
0.7.7 |
pkgver=0.7.7:上游版本号,与 https://github.com/curlpipe/ox 仓库最新发行版本保持一致。 |
pkgrel |
0 |
pkgrel=0:包发布号,当同一上游版本需要重新打包时递增,首次适配为 0。 |
pkgdesc |
- | 包的简短描述,取自 ox 官方 Cargo.toml。 |
url |
- | 上游项目主页 URL。 |
archs |
("arm64-v8a") |
archs=("arm64-v8a"):声明支持的架构数组。此处仅列出 arm64-v8a,但代码内部实际也处理了 armeabi-v7a 和 x86_64,此处是声明"主要支持"而非"仅支持"。当前鸿蒙 PC 设备为 arm64 架构,因此必须配置arm64-v8a。 |
license |
("GPL-2.0") |
ox 采用 GPL-2.0 协议。 |
depends |
() |
无运行时依赖。 |
makedepends |
("cargo" "rustc") |
makedepends=("cargo" "rustc"):编译时依赖。Rust 工具链是构建前提。 |
source |
refs/tags/${pkgver}.tar.gz |
源码包下载地址。使用 ${pkgver} 变量拼接,下载 ox 0.7.7 的 release tarball(注意标签不含 v 前缀)。 |
downloadpackage |
true |
downloadpackage=true:告诉 lycium 构建系统自动下载 source 指定的源码包。如果设置为false需要在目标库目录下手动下载源码包。 |
autounpack |
true |
autounpack=true:下载后自动解压,无需手动解压步骤。如果设置为false需要手动解压。 |
buildtools |
cargo |
buildtools=cargo:声明构建工具类型。lycium 据此选择 Cargo 构建流程(而非 make/cmake 等)。 |
builddir |
ox-${pkgver} |
builddir=ox-${pkgver}:解压后的源码目录名。prepare()/build()/package() 均通过 cd $builddir 进入此目录。 |
packagename |
${builddir}.tar.gz |
packagename=${builddir}.tar.gz:源码包文件名,用于校验/定位。 |
还需要修改package函数中编译完成后的二进制文件名称,ox项目编译完成后,会产出一个名为ox的二进制文件,此处需要将cp target/${OHOS_RUST_TARGET}/release/xxx改为cp target/${OHOS_RUST_TARGET}/release/ox并复制到安装目录。
# 打包安装
package() {
# 进入 Rust 项目目录(和编译时同一个目录)
cd $builddir
# 定义安装路径:鸿蒙库的安装目录
DEST="$LYCIUM_ROOT/usr/$pkgname/$ARCH"
# 创建安装目录bin 文件夹
mkdir -p $DEST/bin/
# 【关键】把编译好的 Rust 程序 → 复制到目标目录的 bin 文件夹
cp target/${OHOS_RUST_TARGET}/release/ox "$DEST/bin/"
cd $OLDPWD
}
4 HNP 打包配置
在lycium_plusplus/RustAdapt/ohos-ox目录下创建hnp.json文件,因为在HPKBUILD中存在archive函数,用于将产物打包为 output/<arch>/<pkgname>_<ver>.tar.gz,或执行 HNP 打包,详细介绍可参考系列索引-构建执行与产物获取。
{
"type": "hnp-config",
"name": "ox",
"version": "0.7.7",
"install": {}
}
5 交叉编译并解决可能存在的问题
HPKBUILD中函数不做改变,在lycium_plusplus/lycium目录下打开终端工具,输入./build.sh ohos-ox进行第一次交叉编译。遇到了一个典型的依赖链兼容性问题:间接依赖的 nix crate 版本过低,不支持 OHOS 目标三元组。当使用 cargo build --target aarch64-unknown-linux-ohos 进行交叉编译时,ptyprocess 的编译出现大量错误,核心报错信息如下:
error[E0432]: unresolved import nix::ioctl_write_ptr_bad
error[E0432]: unresolved import nix::ioctl_read_bad
error[E0308]: mismatched types — pipe() 返回 (OwnedFd, OwnedFd) 而非 (RawFd, RawFd)
error[E0308]: close() 接受 OwnedFd 而非 RawFd
error[E0277]: tcgetattr 要求参数实现 AsFd trait 而非 RawFd
error[E0277]: fcntl 接受 RawFd 而非 OwnedFd
问题根源在于 nix crate 的版本差异:
| 对比项 | nix 0.26(ptyprocess 依赖) | nix 0.29+(ox 直接依赖) |
|---|---|---|
| OHOS 目标支持 | ❌ 不支持 aarch64-unknown-linux-ohos |
✅ 已支持 |
pipe() 返回类型 |
(RawFd, RawFd) |
(OwnedFd, OwnedFd) |
close() 参数类型 |
RawFd |
OwnedFd |
tcgetattr/tcsetattr 参数 |
RawFd |
AsFd trait |
fcntl() 参数类型 |
RawFd |
RawFd(不变) |
| ioctl 宏 | ioctl_write_ptr_bad! / ioctl_read_bad! |
已移除 |
errno::from_i32 |
存在 | 已废弃,改用 Errno::from_raw() |
signal::kill 位置 |
nix::signal::kill |
nix::sys::signal::kill |
SysconfVar |
默认可用 | 需要 feature feature |
关键矛盾:ptyprocess 0.4.1 锁定 nix = "0.26",而 nix 0.26 不支持 OHOS 目标平台。nix 0.29 已支持 OHOS,但 API 发生了大量不兼容变更。
保持原始源码不变,通过 .patch 文件在构建时动态应用修改。具体策略:
-
制作一个补丁文件,将 ptyprocess 的
nix依赖从 0.26 升级到 0.29,并适配所有 API 变更 -
制作另一个补丁文件,在 ox 的
Cargo.toml中添加[patch.crates-io]段,将 ptyprocess 指向本地修补版本 -
在
HPKBUILD的prepare()函数中自动完成补丁应用流程
解决步骤
第一步:了解 ptyprocess 0.4.1 原始源码
首先,从 cargo 本地缓存中找到 ptyprocess 的原始源码:
# ptyprocess 源码位于 cargo registry 缓存目录
ls ~/.cargo/registry/src/*/ptyprocess-0.4.1/
关键文件:
Cargo.toml:声明nix = "0.26"依赖src/lib.rs:大量使用 nix 0.26 APIsrc/stream.rs:使用File::from_raw_fd()等
第二步:制作 ptyprocess 兼容性补丁
1 准备工作目录
# 创建工作目录
mkdir -p /tmp/ptyprocess-patch-work
cd /tmp/ptyprocess-patch-work
# 复制原始源码作为基准
cp -r ~/.cargo/registry/src/*/ptyprocess-0.4.1 ./original
cp -r ./original ./modified
# 确保文件可写
chmod -R u+w ./modified
2 修改 Cargo.toml — 升级 nix 依赖
编辑 modified/Cargo.toml,将 nix 依赖从 0.26 升级到 0.29:
[dependencies.nix]
-version = "0.26"
+version = "0.29"
+features = ["fs", "signal", "process", "term", "ioctl", "feature"]
说明:nix 0.29 将许多功能拆分为独立的 feature gate,需要显式启用:
fs:文件系统操作(OFlag、Mode等)signal:信号处理(kill、Signal等)process:进程操作(fork、setsid等)term:终端操作(tcgetattr、tcsetattr等)ioctl:ioctl 操作feature:SysconfVar枚举(sysconf函数需要)
3 修改 lib.rs — 适配 nix 0.29 API
这是工作量最大的部分,需要逐项适配 API 变更:
3.1 新增导入和辅助类型
nix 0.29 中 tcgetattr/tcsetattr 等函数不再接受 RawFd(i32),而是要求实现了 AsFd trait 的类型。为此,我们引入一个辅助包装器:
// 新增导入
use nix::errno::Errno;
use std::os::unix::process::CommandExt; // 从 std::os::unix::prelude 中拆分出来
// 移除 nix 0.26 的 ioctl 宏
// use nix::{ioctl_write_ptr_bad, Result}; ← 删除
use nix::Result; // 仅保留 Result
// 辅助结构体:将 RawFd 包装为实现 AsFd 的类型
struct RawFdAsFd(i32);
impl std::os::unix::io::AsFd for RawFdAsFd {
fn as_fd(&self) -> std::os::unix::io::BorrowedFd<'_> {
unsafe { std::os::unix::io::BorrowedFd::borrow_raw(self.0) }
}
}
3.2 适配 pipe() — 返回 OwnedFd 而非 RawFd
nix 0.26 的 pipe() 返回 (RawFd, RawFd),而 0.29 返回 (OwnedFd, OwnedFd):
// nix 0.26 写法:
// let (exec_err_pipe_r, exec_err_pipe_w) = pipe()?;
// — exec_err_pipe_r 和 exec_err_pipe_w 是 RawFd (i32)
// nix 0.29 写法:
let (exec_err_pipe_r, exec_err_pipe_w) = pipe()?;
// — exec_err_pipe_r 和 exec_err_pipe_w 是 OwnedFd
// 需要时通过 .as_raw_fd() 获取底层 RawFd
3.3 适配 close() — 接受 OwnedFd 而非 RawFd
nix 0.29 的 close() 要求 OwnedFd,不再接受裸 RawFd。对于 RawFd,需改用 libc::close();对于 OwnedFd,直接 drop() 即可:
// nix 0.26 写法:
// close(slave_fd)?; // slave_fd 是 RawFd
// close(exec_err_pipe_r)?; // exec_err_pipe_r 是 RawFd
// nix 0.29 写法:
// 对于 RawFd,使用 libc::close(无错误传播,因为 close 在某些场景下
// 返回的错误可以安全忽略,如 EIO)
unsafe { libc::close(slave_fd); }
unsafe { libc::close(exec_err_pipe_r.as_raw_fd()); }
// 对于 OwnedFd,直接 drop 即可关闭
drop(exec_err_pipe_w);
drop(exec_err_pipe_r);
3.4 适配 fcntl() — 接受 RawFd(不变)
fcntl() 在 nix 0.29 中仍然接受 RawFd。但如果传入的是 OwnedFd,需要先提取 RawFd:
// nix 0.26 写法:
// fcntl(exec_err_pipe_w, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?;
// nix 0.29 写法(exec_err_pipe_w 现在是 OwnedFd):
fcntl(exec_err_pipe_w.as_raw_fd(), FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?;
3.5 适配 tcgetattr / tcsetattr — 要求 AsFd trait
这是最关键的适配点。nix 0.29 将这些函数的参数从 RawFd 改为实现 AsFd trait 的类型:
// nix 0.26 写法:
// let flags = termios::tcgetattr(fd)?; // fd: RawFd
// termios::tcsetattr(fd, termios::SetArg::TCSANOW, &flags)?;
// nix 0.29 写法(使用 RawFdAsFd 包装器):
let flags = termios::tcgetattr(&RawFdAsFd(fd))?;
termios::tcsetattr(&RawFdAsFd(fd), termios::SetArg::TCSANOW, &flags)?;
3.6 适配 ioctl 操作 — 宏被移除
nix 0.26 使用 ioctl_write_ptr_bad! 和 ioctl_read_bad! 宏来定义 ioctl 操作。nix 0.29 已移除这些宏,需要直接使用 libc::ioctl:
// nix 0.26 写法:
// ioctl_write_ptr_bad!(ioctl_set_winsize, TIOCSWINSZ, winsize);
// ioctl_read_bad!(ioctl_get_winsize, TIOCGWINSZ, winsize);
//
// ioctl_set_winsize(fd, &win)?;
// let win = ioctl_get_winsize(fd)?;
// nix 0.29 写法(直接使用 libc::ioctl):
unsafe {
libc::ioctl(fd, TIOCSWINSZ as u64, &win as *const _);
}
let mut win: winsize = std::mem::zeroed();
unsafe {
libc::ioctl(fd, TIOCGWINSZ as u64, &mut win as *mut _);
}
注意:TIOCSWINSZ 和 TIOCGWINSZ 常量在 nix 0.29 中需要从 nix::libc 或系统头文件获取。在 Linux/OHOS 上,它们的值分别为 0x5414 和 0x5413。
3.7 适配 signal::kill — 模块路径变更
// nix 0.26:kill 在 nix::signal 模块
// signal::kill(pid, sig)
// nix 0.29:kill 移至 nix::sys::signal 模块
// 但由于我们 use nix::sys::{signal, ...}
// 仍然是 signal::kill(pid, sig)
// 只需确保 use 路径正确
3.8 适配 open() — 返回 RawFd(在 nix 0.29 中)
nix 0.29 的 open() 函数返回 Result<RawFd>(i32),不是 OwnedFd:
let fd = open("/dev/tty", OFlag::O_RDWR | OFlag::O_NOCTTY, Mode::empty())?;
// fd 的类型是 RawFd (i32)
// 关闭时使用 libc::close
unsafe { libc::close(fd); }
3.9 适配 errno::from_i32 — 已废弃
// nix 0.26 写法:
// return Err(errno::from_i32(code));
// nix 0.29 写法(虽然 from_i32 仍可用但已标记废弃):
return Err(Errno::from_raw(code));
// 或暂时容忍废弃警告:
return Err(errno::from_i32(code)); // 编译时会产出 deprecated 警告
3.10 适配 write / unistd::read — 参数类型变更
// nix 0.26:
// write(exec_err_pipe_w, &code.to_be_bytes())?; // exec_err_pipe_w: RawFd
// unistd::read(exec_err_pipe_r, &mut pipe_buf)?; // exec_err_pipe_r: RawFd
// nix 0.29(pipe 返回 OwnedFd):
write(&exec_err_pipe_w, &code.to_be_bytes())?; // 传引用
unistd::read(exec_err_pipe_r.as_raw_fd(), &mut pipe_buf)?; // 提取 RawFd
4 生成补丁文件
修改完成后,使用 git diff 生成补丁:
cd /tmp/ptyprocess-patch-work
# 在原始和修改后的目录分别初始化 git 仓库
(cd original && git init && git add -A && git commit -m "base" -q)
(cd modified && git init && git add -A && git commit -m "modified" -q)
# 生成补丁
(cd modified && git diff HEAD~1 HEAD) > ptyprocess-0.4.1-nix0.29-compat.patch
第三步:制作 ox Cargo.toml 补丁
需要让 ox 项目使用本地修补过的 ptyprocess 而非 crates.io 上的版本。这通过在 Cargo.toml 中添加 [patch.crates-io] 段实现:
cd /tmp/ptyprocess-patch-work
# 创建 ox Cargo.toml 的补丁
cat > ox-cargo-add-patch-section.patch << 'EOF'
diff --git a/Cargo.toml b/Cargo.toml
index 550454a..701f2cc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -48,3 +48,6 @@ regex = "1.11.1"
ptyprocess = "0.4.1"
mio = { version = "1.0.3", features = ["os-ext"] }
nix = { version = "0.29.0", features = ["fs"] }
+
+[patch.crates-io]
+ptyprocess = { path = "./ptyprocess-local" }
EOF
说明:[patch.crates-io] 是 Cargo 的官方机制,用于将 crates.io 上的依赖替换为本地路径版本。这样 cargo build 时会使用 ./ptyprocess-local/ 目录下的修补代码,而非从 crates.io 下载的原始版本。
第四步:将补丁文件放入项目
将补丁文件放到项目的 patches/ 目录下,与源码分离:
RustAdapt/ohos-ox/
├── HPKBUILD # 构建脚本
├── hnp.json # HNP 打包配置
├── ox-0.7.7/ # 原始源码(不修改!)
│ ├── Cargo.toml
│ ├── Cargo.lock
│ ├── src/
│ └── ...
└── patches/ # 补丁文件目录
├── ptyprocess-0.4.1-nix0.29-compat.patch # ptyprocess 适配补丁
└── ox-cargo-add-patch-section.patch # ox Cargo.toml 补丁
第五步:编写 HPKBUILD 的 prepare() 函数
HPKBUILD 是 lycium 构建系统的配置文件,其 prepare() 函数在编译前自动执行补丁应用流程:
prepare() {
cd $builddir
local PATCH_DIR="${OLDPWD}/patches"
# 步骤 1:从 cargo 缓存复制 ptyprocess 0.4.1 源码到本地
local PTYPROCESS_SRC=""
local CARGO_REGISTRY="${HOME}/.cargo/registry/src"
if [ -d "$CARGO_REGISTRY" ]; then
for reg_dir in "$CARGO_REGISTRY"/*/; do
if [ -d "${reg_dir}ptyprocess-0.4.1" ]; then
PTYPROCESS_SRC="${reg_dir}ptyprocess-0.4.1"
break
fi
done
fi
if [ -z "$PTYPROCESS_SRC" ]; then
echo "ERROR: ptyprocess-0.4.1 not found in cargo registry cache."
echo " Run 'cargo fetch' in the source directory first."
return 1
fi
echo "Found ptyprocess source: $PTYPROCESS_SRC"
cp -r "$PTYPROCESS_SRC" ./ptyprocess-local
chmod -R u+w ./ptyprocess-local
# 步骤 2:应用 ptyprocess 兼容性补丁(nix 0.26→0.29 API 适配)
# 使用 git apply 应用补丁(需要先初始化 git 仓库)
if [ -f "${PATCH_DIR}/ptyprocess-0.4.1-nix0.29-compat.patch" ]; then
echo "Applying ptyprocess compatibility patch..."
(cd ./ptyprocess-local && \
git init && git add -A && git commit -m "base" -q && \
git apply "${PATCH_DIR}/ptyprocess-0.4.1-nix0.29-compat.patch")
if [ $? -ne 0 ]; then
echo "ERROR: Failed to apply ptyprocess compatibility patch"
return 1
fi
echo "ptyprocess patch applied successfully"
else
echo "ERROR: Patch file not found: ${PATCH_DIR}/ptyprocess-0.4.1-nix0.29-compat.patch"
return 1
fi
# 步骤 3:应用 ox Cargo.toml 补丁(添加 [patch.crates-io] 指向本地 ptyprocess)
if [ -f "${PATCH_DIR}/ox-cargo-add-patch-section.patch" ]; then
echo "Applying ox Cargo.toml patch..."
patch -p1 < "${PATCH_DIR}/ox-cargo-add-patch-section.patch"
if [ $? -ne 0 ]; then
echo "ERROR: Failed to apply ox Cargo.toml patch"
return 1
fi
echo "ox Cargo.toml patch applied successfully"
else
echo "ERROR: Patch file not found: ${PATCH_DIR}/ox-cargo-add-patch-section.patch"
return 1
fi
# 步骤 4:删除 Cargo.lock 以允许重新解析依赖
# 因为 ptyprocess 现在依赖 nix 0.29 而非 0.26,依赖图发生了变化
rm -f Cargo.lock
cd ${OLDPWD}
}
完成以上操作后,重新执行交叉编译命令./build.sh ohos-ox。

如果提示ALL JOBS DONE!!!表示当前交叉编译没有问题,编译后的产物,可以在lycium/usr/目录和out/arm64-v8目录下查看。

三、 在鸿蒙PC上验证交叉编译后的ox命令是否可用
将lycium_plusplus/lycium/usr/ox/arm64-v8a/bin/ox二进制文件传到鸿蒙PC上,方式有多种,可以通过聊天软件。macos设备可以在App Store下载【鸿蒙星河互联】,通过分享方式将ox二进制文件发送到鸿蒙PC设备上,这种方式需要鸿蒙PC开启华为分享为所有人可见。在鸿蒙PC右下角会弹出接受弹窗,选择"接受"或者"另存为",接受ox二进制文件。接受后的二进制文件是不可以直接运行的,哪怕使用chmod +x ox这种方式授权也是无法运行的。需要给二进制文件进行签名后才可以,在鸿蒙 PC 侧执行前涉及二进制签名流程,可参考《鸿蒙PC端二进制文件签名命令行使用指南》。打开鸿蒙PC终端,输入以下命令为ox签名授权。
# 进入ox所在目录
cd Desktop
# 执行签名
binary-sign-tool sign -inFile ox -outFile ox -selfSign "1"
# 授予权限
chmod +x ox
# 查看ox版本
./ox --version
./ox

四、 FAQ
执行签名命令出现“zsh: command not found: binary-sign-tool”提示。
需要在应用市场搜索DevBox并安装,DevBox提供了一些开发者常用命令,主要包含文件和目录操作命令、网络命令、构建命令、签名工具等。

更多推荐





所有评论(0)