sd 适配 OpenHarmony构建指南

目录

项目简介

sd (s earch & d isplace) 是一个直观的查找与替换命令行工具,使用 Rust 编写。它提供了比传统 sed 更简洁、更易用的语法,特别适合日常文本处理任务。

主要特性

  • 简洁的正则表达式语法 :使用 JavaScript 和 Python 风格的正则表达式,无需学习 sed 的复杂语法
  • 字符串字面量模式:非正则表达式的查找替换,无需转义特殊字符
  • 易于读写:查找和替换表达式分开,避免未闭合和转义的斜杠问题
  • 智能默认设置:遵循常识,针对典型日常使用场景优化
  • 高性能 :比 sed 快 2-12 倍(根据基准测试)

与 sed 的对比

功能 sd sed
替换所有出现 sd before after sed s/before/after/g
换行符替换 sd '\n' ',' sed ':a;N;$!ba;s/\n/,/g'
原地修改文件 sd before after file.txt sed -i -e 's/before/after/g' file.txt

sd 工具介绍

安装方式

从 Cargo 安装
bash 复制代码
cargo install sd
从包管理器安装

支持多种包管理器,详见 Packaging status

基本使用

命令行选项
bash 复制代码
sd [OPTIONS] <find> <replace_with> [files]...

Arguments:
  <find>        要查找的模式(正则表达式或字符串)
  <replace_with> 替换为的内容
  [files]...    要处理的文件(可选,默认从 stdin 读取)

Options:
  -F, --fixed-strings    将模式视为字面字符串而非正则表达式
  -p, --preview          预览模式,不实际修改文件
  -f, --flags <FLAGS>    正则表达式标志(如 i=忽略大小写)
  -r, --replacements <N> 限制替换次数
  -h, --help             显示帮助信息
使用示例
  1. 字符串字面量模式 (使用 -F 标志):
bash 复制代码
echo 'lots((([]))) of special chars' | sd -F '((([])))' ''
# 输出: lots of special chars
  1. 基本正则表达式
bash 复制代码
# 去除尾随空白
echo 'lorem ipsum 23   ' | sd '\s+$' ''
# 输出: lorem ipsum 23
  1. 捕获组和替换
bash 复制代码
echo 'cargo +nightly toolchain' | sd '(\w+)\s+\+(\w+)\s+(\w+)' 'cmd: $1, channel: $2, args: $3'
# 输出: cmd: cargo, channel: nightly, args: toolchain
  1. 文件原地修改
bash 复制代码
sd 'old_text' 'new_text' file.txt
  1. 预览模式(不实际修改):
bash 复制代码
sd -p 'old_text' 'new_text' file.txt
  1. 多文件处理
bash 复制代码
sd 'old_text' 'new_text' file1.txt file2.txt file3.txt
  1. 管道输入
bash 复制代码
cat file.txt | sd 'old' 'new'

性能优势

根据基准测试,sd 在处理大文件时表现优异:

  • 简单替换 (~1.5GB JSON):比 sed 快约 2.35 倍
  • 正则替换 (~55MB JSON):比 sed 快约 11.93 倍

开始之前先给大家贴一张图片

适配 HarmonyOS 的准备工作

1. 项目结构

复制代码
code/sd/
├── build_ohos.sh      # HarmonyOS 构建脚本
├── hnp.json           # HNP 包配置文件
├── Cargo.toml         # Rust 项目配置
├── src/               # 源代码目录
│   ├── main.rs        # 主程序
│   ├── cli.rs         # 命令行参数解析
│   ├── input.rs       # 输入处理
│   └── replacer.rs    # 替换逻辑
├── gen/               # 生成的文档
│   └── sd.1           # 手册页
└── .cargo/            # Cargo 配置(构建时生成)
    └── config.toml    # 交叉编译配置

2. HNP 配置文件

创建 hnp.json 文件:

json 复制代码
{
    "type":"hnp-config",
    "name":"sd",
    "version":"1.0.1",
    "install":{}
}

3. Rust 项目特点

  • 语言:Rust
  • 构建工具:Cargo
  • 目标平台 :需要交叉编译到 aarch64-linux-ohos
  • 依赖:标准库 + 第三方 crate(regex, rayon, memmap2 等)

构建脚本实现

完整的 build_ohos.sh

bash 复制代码
#!/bin/bash
# ============================================================================
# build_ohos.sh - sd 工具 HarmonyOS 构建脚本
# ============================================================================
# sd 是一个 Rust 项目,使用 cargo 构建
# ============================================================================

export SD_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/sd.org/sd_1.0.1

sys_prefix=${PREFIX}
export PREFIX=${SD_INSTALL_HNP_PATH}
echo "${PREFIX}"

# 创建安装目录(确保目录存在)
mkdir -p ${SD_INSTALL_HNP_PATH}/bin
mkdir -p ${SD_INSTALL_HNP_PATH}/share/man/man1

# 清理之前的构建产物
cargo clean || true

# 使用 stable 工具链
# 注意:源代码中的 try_blocks 特性声明已被移除,因为实际代码中并未使用
export RUSTUP_TOOLCHAIN=stable

# 配置 Rust 交叉编译环境
# HarmonyOS 使用 musl libc,目标平台为 aarch64-linux-ohos
# 由于 Rust 可能没有标准的 ohos target,我们使用通用的 linux-musl target
export TARGET_CC="${CC}"
export TARGET_CXX="${CXX}"
export TARGET_AR="${AR}"
export TARGET_LD="${LD}"
export TARGET_CFLAGS="${CFLAGS}"
export TARGET_LDFLAGS="${LDFLAGS}"

# 创建 .cargo/config.toml 配置交叉编译
mkdir -p .cargo
cat > .cargo/config.toml << CARGO_CONFIG
[target.aarch64-unknown-linux-musl]
linker = "${CC}"
rustflags = [
    "-C", "link-arg=--target=aarch64-linux-ohos",
    "-C", "link-arg=--sysroot=${SYSROOT}",
    "-C", "link-arg=--ld-path=${LD}",
    "-C", "link-arg=-fuse-ld=lld",
]
CARGO_CONFIG

# 尝试使用 aarch64-unknown-linux-musl target(最接近 HarmonyOS)
RUST_TARGET="aarch64-unknown-linux-musl"

# 检查 target 是否已安装
if ! rustup target list --installed | grep -q "^${RUST_TARGET}$"; then
    echo "Installing Rust target: ${RUST_TARGET}"
    rustup target add ${RUST_TARGET} || {
        echo "Warning: Failed to install ${RUST_TARGET}, trying default build"
        RUST_TARGET=""
    }
fi

# 构建项目
if [ -n "${RUST_TARGET}" ]; then
    echo "Building for target: ${RUST_TARGET}"
    cargo build --release --target ${RUST_TARGET} || {
        echo "Error: cargo build failed"
        exit 1
    }
    BINARY_PATH="target/${RUST_TARGET}/release/sd"
else
    echo "Building for default target"
    cargo build --release || {
        echo "Error: cargo build failed"
        exit 1
    }
    BINARY_PATH="target/release/sd"
fi

# 检查二进制文件是否存在
if [ ! -f "${BINARY_PATH}" ]; then
    echo "Error: Binary not found at ${BINARY_PATH}"
    exit 1
fi

# 安装二进制文件
install -m 0755 ${BINARY_PATH} ${SD_INSTALL_HNP_PATH}/bin/sd || {
    echo "Error: Failed to install binary"
    exit 1
}

# 安装手册页(如果存在)
if [ -f "gen/sd.1" ]; then
    gzip -c gen/sd.1 > gen/sd.1.gz 2>/dev/null || true
    install -m 0644 gen/sd.1.gz ${SD_INSTALL_HNP_PATH}/share/man/man1/ 2>/dev/null || true
    rm -f gen/sd.1.gz
fi

# 复制 HNP 配置文件
cp hnp.json ${SD_INSTALL_HNP_PATH}/ || {
    echo "Error: failed to copy hnp.json"
    exit 1
}

# 打包
if [ -d "${SD_INSTALL_HNP_PATH}" ]; then
    pushd ${SD_INSTALL_HNP_PATH}/../ > /dev/null
        ${HNP_TOOL} pack -i ${SD_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/ || {
            echo "Error: HNP pack failed"
            popd > /dev/null
            export PREFIX=${sys_prefix}
            exit 1
        }
        tar -zvcf ${ARCHIVE_PATH}/ohos_sd_1.0.1.tar.gz sd_1.0.1/ || {
            echo "Error: tar failed"
            popd > /dev/null
            export PREFIX=${sys_prefix}
            exit 1
        }
    popd > /dev/null
else
    echo "Error: Installation directory does not exist: ${SD_INSTALL_HNP_PATH}"
    export PREFIX=${sys_prefix}
    exit 1
fi

# 恢复 PREFIX
export PREFIX=${sys_prefix}

echo "Build completed successfully!"
echo "Output files:"
echo "  - ${ARCHIVE_PATH}/sd.hnp"
echo "  - ${ARCHIVE_PATH}/ohos_sd_1.0.1.tar.gz"

构建流程说明

  1. 环境准备:设置安装路径和 PREFIX
  2. 清理构建:清理之前的构建产物
  3. 工具链选择:使用 stable Rust 工具链
  4. 交叉编译配置 :创建 .cargo/config.toml 配置交叉编译
  5. Target 安装 :安装 aarch64-unknown-linux-musl target
  6. 构建项目 :使用 cargo build --release --target
  7. 安装文件:安装二进制文件和手册页
  8. 打包:生成 HNP 包和 tar.gz 压缩包

遇到的问题与解决方案

问题一:Makefile 不存在

错误现象
复制代码
make: *** No rule to make target `clean'.  Stop.
make: *** No targets specified and no makefile found.  Stop.
问题分析

sd 是一个 Rust 项目,使用 cargo 构建,而不是传统的 make。构建脚本错误地使用了 make 命令。

解决方案

将构建脚本改为使用 cargo

bash 复制代码
# 错误的方式
make clean
make VERBOSE=1
make install

# 正确的方式
cargo clean
cargo build --release --target aarch64-unknown-linux-musl

问题二:Nightly 特性依赖

错误现象
复制代码
error[E0554]: `#![feature]` may not be used on the stable release channel
 --> src/main.rs:1:1
  |
1 | #![feature(try_blocks)]
  | ^^^^^^^^^^^^^^^^^^^^^^^
问题分析

源代码中声明了 #![feature(try_blocks)],这是一个 nightly 特性,但实际代码中并未使用该特性。使用 stable 工具链时会出现错误。

解决方案

移除未使用的 nightly 特性声明:

修改前:

rust 复制代码
#![feature(try_blocks)]
mod cli;

修改后:

rust 复制代码
// Removed nightly feature: #![feature(try_blocks)]
// This feature is not actually used in the code
mod cli;

构建脚本配置:

bash 复制代码
# 使用 stable 工具链
export RUSTUP_TOOLCHAIN=stable

问题三:Unsafe 函数警告

错误现象
复制代码
warning[E0133]: call to unsafe function `memmap2::Mmap::map` is unsafe and requires unsafe block
  --> src/input.rs:37:8
   |
37 |     Ok(Mmap::map(&File::open(path)?)?)
  |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
问题分析

Rust 2024 版本要求 unsafe fn 中调用 unsafe 函数时必须显式使用 unsafe 块。

解决方案

unsafe fn 中添加显式的 unsafe 块:

修改前:

rust 复制代码
pub(crate) unsafe fn make_mmap(path: &PathBuf) -> Result<Mmap> {
    Ok(Mmap::map(&File::open(path)?)?)
}

修改后:

rust 复制代码
pub(crate) unsafe fn make_mmap(path: &PathBuf) -> Result<Mmap> {
    unsafe {
        Ok(Mmap::map(&File::open(path)?)?)
    }
}

问题四:链接器配置错误

错误现象
复制代码
error: linking with `cc` failed: exit status: 1
  = note: ld: unknown option: --as-needed
          clang: error: linker command failed with exit code 1
问题分析

Rust 的 aarch64-unknown-linux-musl target 默认使用系统的 cc 链接器,但需要配置为使用 HarmonyOS SDK 的链接器(ld.lld)。

解决方案

创建 .cargo/config.toml 配置文件,指定正确的链接器和链接参数:

bash 复制代码
mkdir -p .cargo
cat > .cargo/config.toml << CARGO_CONFIG
[target.aarch64-unknown-linux-musl]
linker = "${CC}"
rustflags = [
    "-C", "link-arg=--target=aarch64-linux-ohos",
    "-C", "link-arg=--sysroot=${SYSROOT}",
    "-C", "link-arg=--ld-path=${LD}",
    "-C", "link-arg=-fuse-ld=lld",
]
CARGO_CONFIG

关键配置说明:

  • linker = "${CC}":使用 HarmonyOS SDK 的 clang 作为链接器前端
  • --target=aarch64-linux-ohos:指定目标平台
  • --sysroot=${SYSROOT}:指定系统根目录
  • --ld-path=${LD}:指定链接器路径(ld.lld)
  • -fuse-ld=lld:使用 LLVM 的 lld 链接器

问题五:目录不存在错误

错误现象
复制代码
cp: directory /Users/jianguo/HarmonyOSPC/build/data/service/hnp/sd.org/sd_1.0.1 does not exist
pushd: /Users/jianguo/HarmonyOSPC/build/data/service/hnp/sd.org/sd_1.0.1/../: No such file or directory
问题分析

构建脚本在编译失败时,安装目录没有被创建,导致后续步骤失败。

解决方案

在构建前创建所有必要的目录:

bash 复制代码
# 创建安装目录(确保目录存在)
mkdir -p ${SD_INSTALL_HNP_PATH}/bin
mkdir -p ${SD_INSTALL_HNP_PATH}/share/man/man1

并添加错误处理:

bash 复制代码
# 检查二进制文件是否存在
if [ ! -f "${BINARY_PATH}" ]; then
    echo "Error: Binary not found at ${BINARY_PATH}"
    exit 1
fi

# 打包前检查目录是否存在
if [ -d "${SD_INSTALL_HNP_PATH}" ]; then
    # ... 打包操作 ...
else
    echo "Error: Installation directory does not exist"
    exit 1
fi

构建结果验证

构建输出

成功构建后,会在 output/ 目录下生成以下文件:

  • sd.hnp - HarmonyOS Native Package 格式包(约 914KB)
  • ohos_sd_1.0.1.tar.gz - tar.gz 压缩包(约 917KB)

验证命令

bash 复制代码
# 检查文件是否存在
ls -lh output/sd.hnp output/ohos_sd_1.0.1.tar.gz

# 检查 HNP 文件格式
file output/sd.hnp

# 查看 tar.gz 内容
tar -tzf output/ohos_sd_1.0.1.tar.gz

安装目录结构

复制代码
sd_1.0.1/
├── bin/
│   └── sd              # 可执行文件
├── hnp.json            # HNP 配置文件
└── share/
    └── man/
        └── man1/
            └── sd.1.gz # 手册页

使用示例

基本替换

bash 复制代码
# 简单字符串替换
echo "Hello World" | sd "World" "HarmonyOS"
# 输出: Hello HarmonyOS

# 文件原地修改
sd "old_text" "new_text" file.txt

# 多文件处理
sd "old" "new" file1.txt file2.txt file3.txt

正则表达式

bash 复制代码
# 去除尾随空白
echo "lorem ipsum 23   " | sd '\s+$' ''
# 输出: lorem ipsum 23

# 捕获组替换
echo "cargo +nightly toolchain" | sd '(\w+)\s+\+(\w+)\s+(\w+)' 'cmd: $1, channel: $2, args: $3'
# 输出: cmd: cargo, channel: nightly, args: toolchain

# 数字替换
echo "price: 100" | sd '(\d+)' '$$$1'
# 输出: price: $100

字符串字面量模式

bash 复制代码
# 使用 -F 标志,将模式视为字面字符串
echo 'lots((([]))) of special chars' | sd -F '((([])))' ''
# 输出: lots of special chars

# 替换包含特殊字符的字符串
echo "path/to/file" | sd -F "/" "-"
# 输出: path-to-file

预览模式

bash 复制代码
# 预览替换结果,不实际修改文件
sd -p "old" "new" file.txt

# 从管道预览
cat file.txt | sd -p "old" "new"

高级用法

bash 复制代码
# 限制替换次数
echo "foo foo foo" | sd -r 2 "foo" "bar"
# 输出: bar bar foo

# 使用正则表达式标志(忽略大小写)
echo "Hello HELLO hello" | sd -f i "hello" "hi"
# 输出: hi hi hi

# 处理包含换行符的文本
echo -e "line1\nline2\nline3" | sd '\n' ','
# 输出: line1,line2,line3

实际应用场景

  1. 批量文件替换
bash 复制代码
# 替换项目中所有文件中的文本
find . -type f -name "*.rs" -exec sd "old_api" "new_api" {} \;
  1. 配置文件修改
bash 复制代码
# 修改配置文件中的值
sd 'port\s*=\s*\d+' 'port = 8080' config.toml
  1. 代码重构
bash 复制代码
# 重命名函数调用
sd 'old_function\(' 'new_function(' src/**/*.rs
  1. 数据清洗
bash 复制代码
# 清理 CSV 文件中的多余空白
sd '\s+,' ',' data.csv

Rust 交叉编译要点

1. Target 选择

HarmonyOS 使用 musl libc,因此选择 aarch64-unknown-linux-musl target:

bash 复制代码
rustup target add aarch64-unknown-linux-musl

2. 链接器配置

通过 .cargo/config.toml 配置交叉编译:

toml 复制代码
[target.aarch64-unknown-linux-musl]
linker = "clang"
rustflags = [
    "-C", "link-arg=--target=aarch64-linux-ohos",
    "-C", "link-arg=--sysroot=${SYSROOT}",
    "-C", "link-arg=--ld-path=${LD}",
    "-C", "link-arg=-fuse-ld=lld",
]

3. 环境变量

设置交叉编译相关的环境变量:

bash 复制代码
export TARGET_CC="${CC}"
export TARGET_CXX="${CXX}"
export TARGET_AR="${AR}"
export TARGET_LD="${LD}"
export TARGET_CFLAGS="${CFLAGS}"
export TARGET_LDFLAGS="${LDFLAGS}"

4. 构建命令

bash 复制代码
cargo build --release --target aarch64-unknown-linux-musl

总结

适配要点

  1. 识别项目类型 :Rust 项目使用 cargo 而非 make
  2. 移除 nightly 特性:检查并移除未使用的 nightly 特性声明
  3. 修复 unsafe 警告 :在 unsafe fn 中添加显式 unsafe
  4. 配置交叉编译 :创建 .cargo/config.toml 配置链接器
  5. 错误处理完善:添加完善的错误检查和错误处理机制

技术亮点

  • Rust 交叉编译:成功配置 Rust 项目交叉编译到 HarmonyOS
  • 链接器集成:正确集成 HarmonyOS SDK 的链接器
  • 代码兼容性:修复 Rust 2024 版本的兼容性问题
  • 构建自动化:完整的构建脚本,支持自动化构建和打包

适用场景

sd 工具特别适用于:

  • 文本处理:批量查找和替换文本
  • 代码重构:批量修改代码中的函数名、变量名等
  • 配置文件管理:批量修改配置文件
  • 数据处理:清洗和转换数据文件
  • 日志分析:处理和转换日志文件

性能优势

根据基准测试,sd 在处理大文件时比 sed 快 2-12 倍,特别适合:

  • 处理大型 JSON/XML 文件
  • 批量处理多个文件
  • 需要高性能的文本替换场景

参考资源


所以我们今天可以说,Rust开发的命令行工具,也是可以适配鸿蒙的。

相关推荐
一只栖枝10 小时前
HarmonyOS 开发高级认证是什么?含金量高吗?
华为·华为认证·harmonyos·鸿蒙·考证
汉堡黄•᷄ࡇ•᷅15 小时前
鸿蒙开发:应用通知栏基本操作
鸿蒙·鸿蒙系统
夏文强16 小时前
HarmonyOS开发-数据管理-ArkData(3)- 关系型数据库
前端·数据库·harmonyos·鸿蒙
熊猫钓鱼>_>1 天前
从零到一:使用 ArkTS 构建你的第一个鸿蒙应用
华为·移动开发·harmonyos·arkts·鸿蒙·component·网页开发
Kisang.1 天前
【HarmonyOS】ArkWeb——从入门到入土
前端·华为·typescript·harmonyos·鸿蒙
Kisang.2 天前
【HarmonyOS】性能优化——组件的封装与复用
华为·性能优化·typescript·harmonyos·鸿蒙
Kisang.4 天前
【HarmonyOS】ArkTS的多线程并发(下)——线程间通信对象的传递
华为·typescript·harmonyos·鸿蒙
鸿蒙小白龙5 天前
OpenHarmony内核开发实战手册:编译构建、HCK框架与性能优化
harmonyos·鸿蒙·鸿蒙系统·open harmony
lqj_本人7 天前
EntryAbility继承FlutterAbility应用入口深度解析
鸿蒙