摘要
本文介绍了如何使用 lycium 交叉编译框架将 Ruby 3.3.7 移植到 HarmonyOS 平台的完整解决方案。在不修改 Ruby 源代码的前提下,通过合理配置构建脚本和环境变量,成功实现了 Ruby 在 HarmonyOS 三种主要架构(armeabi-v7a、arm64-v8a、x86_64)上的交叉编译。本文详细记录了适配过程中遇到的技术难点及其解决方案,为后续类似项目的移植提供参考。
1. 背景介绍
1.1 Ruby 语言简介
Ruby 是一种动态、开源的编程语言,以简洁性和高效性著称。它广泛应用于 Web 开发(Ruby on Rails)、脚本编写、自动化测试等领域。将 Ruby 移植到 HarmonyOS 平台,可以为开发者提供更多的编程选择,丰富 HarmonyOS 的生态系统。
1.2 lycium 框架简介
lycium 是一个专为 OpenHarmony/HarmonyOS 设计的交叉编译框架,类似于 Alpine Linux 的 APKBUILD 系统。它通过 HPKBUILD 配置文件定义构建规则,支持自动下载源码、处理依赖关系、执行交叉编译等功能。
1.3 适配目标
| 项目 | 规格 |
|---|---|
| 源软件 | Ruby 3.3.7 |
| 目标平台 | HarmonyOS |
| 支持架构 | armeabi-v7a (32位ARM)、arm64-v8a (64位ARM)、x86_64 |
| 构建主机 | macOS (Apple Silicon) |
| 核心原则 | 不修改 Ruby 源代码 |
2. 技术方案
2.1 总体架构
┌─────────────────────────────────────────────────────────┐
│ 构建主机 (macOS) │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ baseruby │ │ lycium │ │ OHOS SDK │ │
│ │ (Ruby 3.x) │ │ 框架 │ │ (clang 工具链) │ │
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
│ │ │ │ │
│ └────────────────┼───────────────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ HPKBUILD │ │
│ │ (构建配置文件) │ │
│ └───────────┬───────────┘ │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │armeabi-v7a │ │ arm64-v8a │ │ x86_64 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ HarmonyOS 设备 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Ruby 解释器 + 标准库 + 扩展模块 │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
2.2 依赖关系
Ruby 的交叉编译依赖以下组件:
构建时依赖:
- baseruby:宿主机上的 Ruby 解释器(用于生成配置文件)
- OHOS SDK:包含交叉编译工具链(clang/llvm)
- bison、autoconf:构建工具
运行时依赖:
- openssl:提供加密和 SSL/TLS 功能
- zlib-ng:提供压缩功能
2.3 HPKBUILD 配置
核心配置文件 HPKBUILD 定义了构建规则:
bash
pkgname=ruby
pkgver=3.3.7
pkgrel=0
pkgdesc="Ruby programming language"
url="https://www.ruby-lang.org/"
archs=("armeabi-v7a" "arm64-v8a" "x86_64")
license=("Ruby License" "BSD-2-Clause")
depends=("openssl" "zlib-ng")
makedepends=("ruby" "bison" "autoconf")
source="https://cache.ruby-lang.org/pub/ruby/3.3/$pkgname-$pkgver.tar.gz"
3. 关键技术问题及解决方案
3.1 问题一:config.sub 不识别 HarmonyOS
问题描述:
Ruby 使用 autoconf 生成的 config.sub 脚本来识别目标平台。由于 HarmonyOS (ohos) 是较新的操作系统,Ruby 的 config.sub 无法识别 *-linux-ohos 格式的 target triplet。
错误: Invalid configuration 'x86_64-linux-ohos': OS 'ohos' not recognized
解决方案:
由于不能修改 Ruby 源码,采用"伪装"策略,使用标准 Linux GNU triplet 替代 OHOS triplet:
bash
# 架构到 host triplet 的映射
armeabi-v7a → arm-linux-gnueabi
arm64-v8a → aarch64-linux-gnu
x86_64 → x86_64-linux-gnu
这种方案可行是因为 HarmonyOS 在 ABI 层面与 Linux 高度兼容,使用 musl libc 作为 C 库实现。
3.2 问题二:MAKE 环境变量冲突
问题描述:
lycium 框架设置 MAKE="make -j8" 以支持并行编译。但 Ruby 的 Makefile 在某些场景下使用 $(MAKE) 来调用子 make 进程,导致 shell 错误:
错误: /bin/sh: -j8: command not found
原因分析:
当 Ruby 的 Makefile 执行类似以下命令时:
makefile
$(MAKE) -f Makefile.rbconfig
由于 MAKE="make -j8",实际执行变成:
bash
make -j8 -f Makefile.rbconfig
在某些 shell 解析场景下,-j8 被错误地当作独立命令。
解决方案:
在构建开始前取消 MAKE 环境变量,改为直接在 make 命令中指定并行度:
bash
build() {
unset MAKE
./configure ...
make -j8 V=1 # 直接指定并行编译
}
3.3 问题三:UTF-8 编码兼容性
问题描述:
在构建扩展模块时,Ruby 的 extmk.rb 脚本抛出编码错误:
错误: ./ext/extmk.rb:246:in `join': incompatible character encodings:
ASCII-8BIT and UTF-8 (Encoding::CompatibilityError)
原因分析:
- 构建路径可能包含非 ASCII 字符(如中文目录名)
- macOS 系统自带的 Ruby 2.6.x 对 UTF-8 路径处理存在缺陷
- 不同来源的字符串(文件系统 vs 代码内部)编码不一致
解决方案:
采用双重策略:
策略一:使用现代版本的 baseruby
bash
# 优先使用 Homebrew 安装的 Ruby 3.x
if [ -x "/opt/homebrew/opt/ruby/bin/ruby" ]; then
baseruby="/opt/homebrew/opt/ruby/bin/ruby"
fi
策略二:设置 UTF-8 环境变量
bash
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
export RUBYOPT="-E UTF-8:UTF-8"
3.4 问题四:ARM 架构构建时的深层编码问题
问题描述:
即使解决了上述编码问题,在构建 ARM 架构时,mkconfig.rb 脚本仍然失败:
错误: ./tool/mkconfig.rb:34:in 'block in <main>':
invalid byte sequence in UTF-8 (ArgumentError)
原因分析:
mkconfig.rb 读取 config.status 文件(由 configure 生成),该文件包含绝对路径。当路径中包含非 ASCII 字符时:
- config.status 以二进制模式写入
- mkconfig.rb 以 UTF-8 模式读取
- 编码不匹配导致解析失败
解决方案:
将整个构建环境复制到纯 ASCII 路径下执行:
bash
# 创建纯 ASCII 构建环境
mkdir -p /tmp/ruby_build
cp -R lycium thirdparty /tmp/ruby_build/
# 在纯 ASCII 路径下构建
cd /tmp/ruby_build/lycium
./build.sh ruby
# 构建完成后复制回原位置
cp -R /tmp/ruby_build/lycium/usr/ruby /original/path/lycium/usr/
最佳实践: 建议项目根目录路径仅包含 ASCII 字符,以避免此类问题。
4. 构建流程
4.1 环境准备
bash
# 1. 安装 Homebrew Ruby (macOS)
brew install ruby
# 2. 确认 OHOS SDK 已配置
echo $OHOS_SDK # 应输出 SDK 路径
# 3. 确保依赖库已构建
ls lycium/usr/openssl/ # 应包含三种架构
ls lycium/usr/zlib-ng/ # 应包含三种架构
4.2 执行构建
bash
# 进入 lycium 目录
cd lycium
# 设置环境变量
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
# 执行构建(自动构建所有架构)
./build.sh ruby
4.3 验证结果
bash
# 检查构建产物
for arch in armeabi-v7a arm64-v8a x86_64; do
echo "=== $arch ==="
file lycium/usr/ruby/$arch/bin/ruby
done
预期输出:
=== armeabi-v7a ===
ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV),
dynamically linked, interpreter /lib/ld-musl-arm.so.1
=== arm64-v8a ===
ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV),
dynamically linked, interpreter /lib/ld-musl-aarch64.so.1
=== x86_64 ===
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib/ld-musl-x86_64.so.1
5. 构建产物说明
5.1 目录结构
lycium/usr/ruby/<ARCH>/
├── bin/
│ ├── ruby # Ruby 解释器主程序
│ ├── irb # 交互式 Ruby Shell
│ ├── gem # RubyGems 包管理器
│ ├── bundle # Bundler 依赖管理
│ ├── rake # Rake 构建工具
│ ├── rdoc # 文档生成器
│ └── ...
├── include/
│ └── ruby-3.3.0/ # C 扩展开发头文件
├── lib/
│ ├── libruby.so # 符号链接
│ ├── libruby.so.3.3 # 符号链接
│ ├── libruby.so.3.3.7 # Ruby 核心共享库
│ └── ruby/3.3.0/
│ ├── <target>/ # 平台相关扩展 (.so)
│ └── *.rb # 标准库 Ruby 文件
└── share/
└── ri/ # Ruby 文档数据
5.2 扩展模块
成功编译的扩展模块包括:
| 模块 | 功能 |
|---|---|
| openssl.so | SSL/TLS 加密支持 |
| zlib.so | 数据压缩 |
| socket.so | 网络编程 |
| json.so | JSON 解析 |
| bigdecimal.so | 高精度数值计算 |
| date_core.so | 日期时间处理 |
| digest.so | 摘要算法 |
| psych.so | YAML 解析 |
| ... | (共 19 个扩展模块) |
6. 部署与测试
6.1 部署到 HarmonyOS 设备
bash
# 将 Ruby 目录推送到设备
hdc file send lycium/usr/ruby/<ARCH> /data/local/tmp/ruby
# 设置环境变量
export PATH=/data/local/tmp/ruby/bin:$PATH
export LD_LIBRARY_PATH=/data/local/tmp/ruby/lib:$LD_LIBRARY_PATH
6.2 基本功能测试
bash
# 版本检查
ruby --version
# 简单脚本测试
ruby -e 'puts "Hello, HarmonyOS!"'
# 标准库测试
ruby -e 'require "json"; puts JSON.generate({status: "ok"})'
# OpenSSL 测试
ruby -e 'require "openssl"; puts OpenSSL::VERSION'
7. 总结
7.1 技术亮点
- 零源码修改:完全通过配置和环境变量解决兼容性问题
- 多架构支持:一套配置同时支持三种 CPU 架构
- 完整功能:包含所有核心扩展模块
- 可复现构建:通过 HPKBUILD 实现标准化构建流程
7.2 经验总结
| 类别 | 经验 |
|---|---|
| 平台兼容 | HarmonyOS 与 Linux ABI 高度兼容,可使用 GNU triplet |
| 编码处理 | 使用现代版本 Ruby 作为 baseruby,避免路径包含非 ASCII 字符 |
| 环境隔离 | 必要时取消或重设框架预设的环境变量 |
| 调试技巧 | 启用 V=1 查看详细编译命令,便于定位问题 |
7.3 后续工作
- 在实际 HarmonyOS 设备上进行完整功能测试
- 评估性能表现并进行必要优化
- 探索与 HarmonyOS 特性的深度集成可能性
参考资料
- Ruby 官方文档: https://www.ruby-lang.org/
- OpenHarmony 三方库适配指南
- lycium 框架文档
- OHOS SDK 交叉编译指南