Some checks failed
EcoArk Wheel Pipeline CI / build (push) Failing after 1m41s
- Add pipeline/manifest.py for packages.txt parsing - Implement real numpy cross-compilation (rebuild.py) with OHOS NDK + vendored meson - Extend CLI with --manifest, --build-from-source, --stage-integration modes - Add recipes/, experiments/, and scripts/ for integration staging and artifact upload - Update CI workflow with manifest validation, artifact upload, and release publishing - Update Makefile and README with new targets and documentation
256 lines
9.9 KiB
Markdown
256 lines
9.9 KiB
Markdown
# EcoArk HarmonyOS Wheel Pipeline
|
||
|
||
为 **EcoArk / HarmonyOS Python 环境** 准备的 wheel 重打包与重编译流水线。
|
||
|
||
## 用途
|
||
|
||
- **单 wheel 模式**:接收一个 `.whl` 文件,自动检测类型并处理
|
||
- 纯 Python wheel → 直接重打包为 `harmonyos_arm64` 兼容标签,安装即用
|
||
- Native wheel → 交叉编译为 HarmonyOS/arm64 原生 .so 并组装 wheel
|
||
- **清单批量模式**:通过 `packages.txt` 清单文件,逐个拉取源码仓库,执行重编,最终打成 zip 包
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
ecoarkpywhl/
|
||
├── wheel_pipeline.py # CLI 入口(最简调用)
|
||
├── packages.txt # 待处理项目清单(格式说明见下文)
|
||
├── pipeline/
|
||
│ ├── cli.py # 参数解析 & 主流程(含 --build-from-source 模式)
|
||
│ ├── manifest.py # packages.txt 解析器
|
||
│ ├── detect.py # 检测 wheel 类型(纯 Python / native)
|
||
│ ├── repack.py # 纯 Python wheel 重打包
|
||
│ └── rebuild.py # Native wheel 交叉编译 + wheel 组装
|
||
├── recipes/
|
||
│ └── numpy_integration_manifest.json # numpy 集成暂存配方
|
||
├── scripts/
|
||
│ ├── stage_integration.py # 集成暂存脚本
|
||
│ └── upload_release_assets.py # Gitea Release 上传脚本
|
||
├── experiments/ # 交叉编译实验记录
|
||
├── Makefile # 常用命令
|
||
├── output/ # 输出目录(wheels/、sources/)
|
||
└── README.md
|
||
```
|
||
|
||
## packages.txt — 项目清单
|
||
|
||
`packages.txt` 定义需要批量重编的包列表,格式:
|
||
|
||
```
|
||
package_name:git_repository_url
|
||
```
|
||
|
||
- 每行一个包,`:` 前为包名,后为 git clone URL
|
||
- 空行和以 `#` 开头的行被忽略
|
||
- 所有行被注释的 `packages.txt` 是安全的空清单
|
||
|
||
### 示例
|
||
|
||
```
|
||
# numpy:https://github.com/numpy/numpy.git
|
||
# scipy:https://github.com/scipy/scipy.git
|
||
```
|
||
|
||
去掉 `#` 即激活对应包。
|
||
|
||
## 集成暂存模式(Integration Staging)
|
||
|
||
将已编译的 native .so 文件从 wheel 中提取并组织到 `output/integration/<pkg>/` 目录,
|
||
附带 README 和 manifest,说明各模块在 EcoArk pythonrunner main-so 链接中的目标路径。
|
||
|
||
```bash
|
||
# 通过 CLI 入口
|
||
python3 wheel_pipeline.py --stage-integration
|
||
|
||
# 或通过 Makefile
|
||
make stage-integration
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 单 wheel 模式(向后兼容)
|
||
|
||
```bash
|
||
# 纯 Python wheel → 重打包
|
||
python3 wheel_pipeline.py some_pure_package.whl
|
||
|
||
# 指定输出目录
|
||
python3 wheel_pipeline.py some_pure_package.whl --output-dir /tmp/wheels
|
||
|
||
# Native wheel → 触发重编译入口
|
||
python3 wheel_pipeline.py some_native_package.whl
|
||
```
|
||
|
||
### 从源码交叉编译
|
||
|
||
```bash
|
||
# 交叉编译 numpy 1.26.4 并产出 HarmonyOS arm64 wheel
|
||
python3 wheel_pipeline.py --build-from-source numpy --package-version 1.26.4
|
||
|
||
# 强制重新编译(跳过缓存)
|
||
python3 wheel_pipeline.py --build-from-source numpy --package-version 1.26.4 --rebuild
|
||
```
|
||
|
||
### 清单批量模式
|
||
|
||
```bash
|
||
# 读取 packages.txt,逐个拉取源码并生成 wheel
|
||
python3 wheel_pipeline.py --manifest packages.txt --output-dir output
|
||
|
||
# 使用自定义清单
|
||
python3 wheel_pipeline.py --manifest my_list.txt
|
||
```
|
||
|
||
或通过 Makefile:
|
||
|
||
```bash
|
||
make repack INPUT=some_package.whl
|
||
make rebuild INPUT=some_native_package.whl
|
||
make manifest MANIFEST=packages.txt
|
||
make build-numpy VERSION=1.26.4
|
||
```
|
||
|
||
## 清单模式工作流行为
|
||
|
||
1. 读取 `packages.txt`(或 `--manifest` 指定的文件)
|
||
2. 对每个未注释的条目:
|
||
- `git clone --depth 1 <repo_url>` 到 `output/sources/<pkg_name>/`
|
||
- 调用 `pipeline/rebuild.rebuild_from_source()` 生成 wheel
|
||
3. 收集 `output/wheels/` 下所有 `.whl` 文件
|
||
4. 打包为 `output/ecoark-rebuild-output.zip`
|
||
|
||
### CI 中的产物路径
|
||
|
||
| 产物 | 路径 | 获取方式 |
|
||
|------|------|----------|
|
||
| 单个 wheel | `output/wheels/<pkg>-<ver>-cp312-cp312-harmonyos_arm64.whl` | **artifact**: `ecoark-wheels-individual` |
|
||
| 汇总 zip 包 | `output/ecoark-rebuild-output.zip` | **artifact**: `ecoark-harmonyos-wheels` |
|
||
| Release 附件 | 同上 | **Gitea Release**(需配置 token + tag push) |
|
||
|
||
> **artifact** = 在 Gitea Actions 运行结果页面直接下载(无需配置,即时可用)
|
||
> **Release** = 在 Gitea 仓库 Releases 页面长期保留(需配置 token,推 tag 时触发)
|
||
|
||
## Gitea Actions 流水线
|
||
|
||
当前工作流(`.gitea/workflows/wheel-pipeline.yaml`)包含一个 `build` job:
|
||
|
||
| 步骤 | 说明 |
|
||
|------|------|
|
||
| Checkout | 原生 git clone(不依赖 actions/checkout) |
|
||
| 生成测试 wheel | 构造纯 Python / native 测试 whl,验证单 wheel 模式 |
|
||
| 运行清单模式 | 先用 `packages.txt`(空清单 → no-op),再用临时清单验证 |
|
||
| 上传总 zip artifact | `scripts/upload_artifacts.py` → `ecoark-harmonyos-wheels`(Gitea Runtime API) |
|
||
| 上传单个 .whl artifacts | `scripts/upload_artifacts.py` → `ecoark-wheels-individual`(Gitea Runtime API) |
|
||
| 上传到 Gitea Release | `scripts/upload_release_assets.py`(需要 `GITEA_TOKEN` + `ENABLE_RELEASE_UPLOAD` 两个 secrets,见下方说明) |
|
||
|
||
## 从 CI 获取产物
|
||
|
||
### 方式一:直接下载 artifact(零配置,即时可用)
|
||
|
||
每次 CI 构建完成后,在 Gitea Actions 运行结果页面可以下载两类 artifact。
|
||
artifact 上传使用 `scripts/upload_artifacts.py` 通过 Gitea Actions Runtime API 完成,
|
||
**不依赖任何 GitHub-specific action**(如 `actions/upload-artifact`)。
|
||
|
||
| Artifact 名称 | 内容 | 适用场景 |
|
||
|---------------|------|----------|
|
||
| `ecoark-harmonyos-wheels` | 所有 wheel 打包成的 **一个 zip** | 一次下载全部 |
|
||
| `ecoark-wheels-individual` | 每个 `.whl` 文件**独立存放** | 只需特定一个 wheel |
|
||
|
||
操作步骤:
|
||
1. 打开 Gitea 仓库 → **Actions** → 最近成功运行
|
||
2. 在 workflow 页面底部找到 **Artifacts** 区域
|
||
3. 点击 `ecoark-wheels-individual` 进入,选择并下载你需要的单个 `.whl` 文件
|
||
4. 或直接点击 `ecoark-harmonyos-wheels` 下载汇总 zip
|
||
|
||
> 不需要 pip,不需要安装任何工具,浏览器直接下载 `.whl` 后即可用于 HarmonyOS Python 环境的 `pip install some_package.whl`。
|
||
|
||
### 方式二:Gitea Release(长期保留,需配置)
|
||
|
||
通过推 tag 触发自动发布,wheel 会以 Release 附件形式上传,长期可访问。
|
||
Release 上传通过 `scripts/upload_release_assets.py` 完成,由 `GITEA_TOKEN` +
|
||
`ENABLE_RELEASE_UPLOAD` 两个 secrets 共同控制。
|
||
Workflow 中使用 `if: secrets.GITEA_TOKEN != '' && secrets.ENABLE_RELEASE_UPLOAD == 'true'`
|
||
条件守卫,只有两个 secret 都**正确设置**后 Release 步骤才会执行。
|
||
|
||
配置步骤:
|
||
1. 在 Gitea 用户设置 → **Applications** → 创建 Access Token(`repo` scope)
|
||
2. 在仓库 → **Settings** → **Secrets** → 添加以下两个 secret:
|
||
- `GITEA_TOKEN` — 上述 token 值
|
||
- `ENABLE_RELEASE_UPLOAD` — 设为 `true` 激活发布步骤
|
||
3. 编辑 `.gitea/workflows/wheel-pipeline.yaml`,取消 `tags: ['v*']` 行的注释以启用 tag 触发
|
||
4. 推送一个 tag(例如 `git tag v0.1.0 && git push origin v0.1.0`),CI 会自动:
|
||
- 构建 wheel
|
||
- 创建/更新对应 tag 的 Gitea Release
|
||
- 将每个 `.whl` 和 zip 包上传为 Release 附件
|
||
|
||
## 限制
|
||
|
||
| 场景 | 状态 |
|
||
|------|------|
|
||
| 纯 Python wheel → 重打包安装 | ✅ 支持 |
|
||
| Pure Python → 重新打 tag | ✅ 支持 |
|
||
| Native wheel → HarmonyOS 交叉编译 + wheel 产出 | ✅ 已支持(numpy 1.26.4 验证通过,19 个 AArch64 .so) |
|
||
| 从源码编译到产出 .whl | ✅ `pipeline/rebuild.py` 含 `build_numpy_wheel()` 真实实现 |
|
||
| 依赖复杂的 native 包(scipy 等) | 🚧 需逐个包适配,底层依赖链未移植 |
|
||
| Gitea Release 自动发布 | 🚧 需配 `ENABLE_RELEASE_UPLOAD` + `GITEA_TOKEN` 两个 secrets |
|
||
|
||
### 纯 Python wheel
|
||
|
||
纯 Python wheel(文件名中包含 `py3-none-any` 等标签,且不含 `.so`/`.pyd` 文件)可以直接重打包为 `harmonyos_arm64` 标签,在 HarmonyOS Python 环境中安装运行。
|
||
|
||
```bash
|
||
python3 wheel_pipeline.py mypackage.whl -o output/
|
||
# → output/mypackage-1.0.0-py3-none-harmonyos_arm64.whl
|
||
```
|
||
|
||
### Native wheel — 交叉编译
|
||
|
||
含 C/C++/Rust 等 native 扩展的 wheel 需要:
|
||
|
||
1. HarmonyOS SDK / OHOS NDK
|
||
2. 对应架构(arm64)的交叉编译工具链
|
||
3. Python 头文件与目标 Python 版本匹配
|
||
4. 所有 C 依赖也已移植到 HarmonyOS
|
||
|
||
**当前已支持:** numpy 1.26.4 全流程交叉编译通过
|
||
|
||
| 阶段 | 状态 |
|
||
|------|------|
|
||
| meson setup + compile | ✅ 311 个编译目标全部通过 |
|
||
| .so → AArch64 ELF | ✅ 19 个 .so,逐个校验 e_machine=0xB7 |
|
||
| SOABI 修正 | ✅ `cpython-312-x86_64-linux-gnu` → `cpython-312-arm64-linux-ohos` |
|
||
| wheel 组装 | ✅ 含 19 个 .so + 纯 Python 文件 + metadata |
|
||
| 体积 | ✅ ~12.9 MB(已排除测试文件 / 构建源码) |
|
||
|
||
**使用方式:**
|
||
|
||
```bash
|
||
python3 wheel_pipeline.py --build-from-source numpy --package-version 1.26.4
|
||
```
|
||
|
||
**待收口到正式发布的问题:**
|
||
- SOABI 标签需与目标运行时完全对齐
|
||
- pyconfig.h 需为 aarch64-linux-ohos + musl 重新生成
|
||
- 如需 BLAS 性能需交叉编译 OpenBLAS(当前 `-Dallow-noblas=true`)
|
||
|
||
### 编译环境需求
|
||
|
||
执行 `--build-from-source` 交叉编译需要以下环境(当前构建机器已具备):
|
||
|
||
| 依赖 | 说明 |
|
||
|------|------|
|
||
| OHOS NDK clang(aarch64-linux-ohos) | `/home/program/tools/command-line-tools/sdk/default/openharmony/native/llvm` |
|
||
| Cython ≥0.29.34 | pip install |
|
||
| meson-python ≥0.15.0 | pip install |
|
||
| ninja | pip install |
|
||
| setuptools | pip install(Python 3.12+ 需要) |
|
||
| meson cross-compilation file | `experiments/ohos-aarch64-cross.ini` |
|
||
|
||
> 以上依赖在构建机上已安装。如需在 CI 中运行,需在 workflow 中先执行 `pip install` 安装构建时依赖。
|
||
|
||
详细实验记录见 `experiments/` 目录。
|
||
|
||
## 许可证
|
||
|
||
本项目许可证见仓库根目录。
|