欢迎加入【开源鸿蒙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 × WSLtree 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(环境搭建)
  1. 在浏览器中打开 DCP 每日构建列表https://dcp.openharmony.cn/workbench/cicd/dailybuild/dailylist
  2. 在列表中按本机操作系统选择对应产物(名称随版本变化,以页面为准):
开发机系统 选择产物(关键词)
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/ 等目录(含 llvmsysroothnpcli 等),再配置 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构建特性

oxRust语言编写,使用Cargo作为构建系统。编译后产出的二进制命令为ox

核心特性

  1. 轻量级终端文本编辑器

    ox 采用极简设计理念,开箱即用,无需复杂配置即可编辑文本文件。相比于 vim/nano,它在保持终端原生体验的同时,融合了现代编辑器的交互特性,二进制体积小、启动速度快,适合在资源受限的鸿蒙PC环境中流畅运行。

  2. Lua 脚本扩展

    ​ 支持通过 Lua 脚本对编辑器行为进行高度定制和扩展。用户可编写 Lua 插件实现自定义快捷键、语法高亮规则、自动补全逻辑等,极大地增强了编辑器的可编程性和灵活性。

  3. 语法高亮与多语言支持

    ​ 内置丰富的语法高亮规则,覆盖主流编程语言(Rust、Python、JavaScript、C/C++ 等)和标记语言(Markdown、YAML、TOML 等),搭配自动缩进和行号显示,提供舒适的代码编写体验。

  4. 多光标编辑

    ​ 支持多光标同时操作,可以在多个位置同时键入、删除或选择文本,大幅提高批量编辑效率。配合列块选择模式,处理表格化文本或对齐代码时尤为高效。

  5. 分屏视图和多重缓冲区

    ​ 支持水平/垂直分屏,可同时在多个窗口中编辑不同文件或同一文件的不同位置。缓冲区管理机制让文件切换无需频繁打开和关闭,保持编辑工作流的连续性。

  6. 终端集成与 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目录下,并重命名为HPKBUILDHPKBUILDlycium交叉编译框架完成编译构建的核心配置文件,定义包的元信息、依赖、构建和打包逻辑。需要根据模板在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-v7ax86_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.7release 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 指向本地修补版本

  • HPKBUILDprepare() 函数中自动完成补丁应用流程

解决步骤
第一步:了解 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 API
  • src/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:文件系统操作(OFlagMode 等)
  • signal:信号处理(killSignal 等)
  • process:进程操作(forksetsid 等)
  • term:终端操作(tcgetattrtcsetattr 等)
  • ioctl:ioctl 操作
  • featureSysconfVar 枚举(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 _);
}

注意TIOCSWINSZTIOCGWINSZ 常量在 nix 0.29 中需要从 nix::libc 或系统头文件获取。在 Linux/OHOS 上,它们的值分别为 0x54140x5413

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

image-20260519211517154

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

image-20260519211548913

三、 在鸿蒙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

image-20260520092208594

四、 FAQ

执行签名命令出现“zsh: command not found: binary-sign-tool”提示。

需要在应用市场搜索DevBox并安装,DevBox提供了一些开发者常用命令,主要包含文件和目录操作命令、网络命令、构建命令、签名工具等。

image-20260515233557854

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐