Kakehashi:在 Linux ARM 上运行 macOS 二进制的用户态翻译层
用户态macOS ARM64 → Linux aarch64 翻译层(优先支持命令行,无即时编译JIT)
可在Linux aarch64系统加载Darwin Mach-O文件,映射独立式libSystem库,转换BSD系统调用,运行真实客端程序(如Clang探针、7-Zip 7zz、curl、多线程程序)。
| 功能场景 | 支持环境 |
|---|---|
| 实时运行 | Linux aarch64(裸机、虚拟机、Colima/Docker) |
| 静态加载/程序检查 | 任意主机(含macOS) |
| 设计文档参考 | docs/目录 |
已在Docker/Colima和UTM(Linux aarch64)环境验证。一键安装:
cargo install kakehashi
# 或从源码编译安装:
cargo install --path crates/kh-cli --force
kh bottle ensure
kh install 7zip # 将Darwin版7zz安装至客端/usr/local/bin/7zz
kh install curl # 将Darwin版curl安装至客端/usr/local/bin/curl
相对路径-o或归档路径以kh进程的**主机当前工作目录(CWD)**为基准(需自行创建父目录,或依赖O_CREAT自动创建)。通过bottle机制,/Volumes/linux/…路径会映射至主机根目录(即客端/对应主机/)。
# 查看版本/帮助信息
kh run 7zz --
kh run 7zz -- --help
# 创建归档文件(相对当前目录)
kh run 7zz -- a demo.7z README.md
kh run 7zz -- t demo.7z
kh run 7zz -- l demo.7z
kh run 7zz -- x -o./out demo.7z
# 多线程压缩(正确性验证)
kh run 7zz -- a -t7z -m0=lzma2 -mx=5 -mmt=4 mt.7z README.md
kh run 7zz -- t mt.7z
# 预期结果:显示Everything is Ok,退出码0
Docker辅助脚本(输出文件存于主机.tmp/kh-out/目录):
./scripts/docker-7zz.sh --help
./scripts/docker-7zz.sh a /Volumes/linux/out/demo.7z /Volumes/linux/src/README.md
ls -lh .tmp/kh-out/demo.7z
KAKEHASHI_HYPERCALL=1 ./scripts/docker-7zz.sh a -t7z -m0=lzma2 -mx=5 -mmt=4 \
/Volumes/linux/out/mt.7z /Volumes/linux/src/README.md
./scripts/docker-7zz.sh t /Volumes/linux/out/mt.7z
# 查看版本标识(G1)
kh run curl -- --version
# HTTP GET请求并保存至文件(G3/G5),-o指定路径的父目录不存在时会自动创建
kh run curl -- -sS -o .tmp/kh-out/body http://example.com/
# 预期结果:退出码0,文件大小约559字节,HTML内容包含"Example Domain"
wc -c .tmp/kh-out/body
head -c 80 .tmp/kh-out/body; echo
# HTTP请求结果输出至标准输出
kh run curl -- -sS http://example.com/ | head -c 80; echo
# HTTPS GET请求(G4)——依赖OpenSSL + bottle证书(取自主机或curl.se下载)
kh run curl -- -sS -o .tmp/kh-out/https-body https://example.com/
wc -c .tmp/kh-out/https-body
# 异常测试:访问存在无效/自签名证书的站点应失败(退出码≠0)
kh run curl -- -sS -o /dev/null https://self-signed.badssl.com/; echo exit:$?
Docker辅助脚本:
./scripts/docker-curl.sh --version
./scripts/docker-curl.sh -sS -o /Volumes/linux/out/body http://example.com/
./scripts/docker-curl.sh -sS -o /Volumes/linux/out/https-body https://example.com/
ls -lh .tmp/kh-out/body .tmp/kh-out/https-body
# 探针日志输出至.tmp/kh-curl-probe/目录
./scripts/docker-curl-probe.sh --version
# 分阶测试curl参数组合(结果存于.tmp/kh-curl-options/)
./scripts/docker-curl-options.sh tier1
./scripts/docker-curl-options.sh tier9-10
./scripts/docker-curl-options.sh all # 测试tier1至tier10所有参数
运行过程中以下提示属于正常现象,不影响功能:
kh: open fail ENOENT(openat) path=/etc/ssl/openssl.cnf——OpenSSL配置文件为可选,HTTP/HTTPS仍可通过预置的CA证书包正常工作。WARN … skip dylib … Security/CoreFoundation——Apple框架未包含在bottle中,已通过软桩(soft stubs)处理加载路径。unresolved strong symbol; bound to named missing trampoline——未命中核心执行路径的符号,不影响程序运行。
详细说明与验证标准:docs/curl.md
| 测试场景 | 说明 |
|---|---|
| Clang/基准探针测试 | 测试代码位于tests/clang-probe/、tests/fixtures/ |
多线程7zz -mmt=4测试 |
已在Docker + UTM环境验证 |
Bottle + 独立式libSystem |
kh bottle ensure命令会自动嵌入动态库 |
| 单元测试 + clippy检查 | 执行cargo test/clippy可完成全工作区检查(kh-libsystem除外) |
目前已实现curl全功能(POST请求体、代理、端到端HTTP/3、所有协议)、真实Apple Security.framework支持、git/命令行工具(CLT)、图形界面、代码签名(codesign)。下一阶段将支持:通过kh install xcode-tools运行git——详见docs/git.md。
| 包(Crate) | 功能定位 |
|---|---|
kakehashi |
二进制程序kh(用户需安装此包) |
kh-loader |
Mach-O文件解析、映射与执行 |
kh-runtime |
内存管理、陷阱捕获、BSD系统调用转换、bottle机制;内置独立式libSystem.B.dylib |
kh-libsystem |
上述动态库的源码(仅支持aarch64-apple-darwin目标平台,非Linux主机包) |
客端动态库预置于crates/kh-runtime/resources/libSystem.B.dylib,通过include_bytes!编译进运行时。发布kh-runtime时会自动包含该动态库,终端用户无需单独下载。
环境要求
- Rust 1.88及以上版本
- Linux aarch64系统(用于
kh run/kh trace实时运行) - 支持的页面大小:4 KiB(容器环境)和16 KiB(Asahi类设备)
- 可选依赖:
curl/wget+tar(用于kh install 7zip/kh install curl命令)
cargo install kakehashi
# 或从源码编译安装:cargo install --path crates/kh-cli
kh bottle ensure
kh install 7zip
kh install curl
默认根目录:~/.local/share/kakehashi/bottle/(可通过KAKEHASHI_DATA_DIR/KAKEHASHI_ROOT环境变量覆盖)
| 主机路径 | 客端路径 |
|---|---|
…/bottle/ |
/ |
…/usr/local/bin/7zz |
/usr/local/bin/7zz |
…/usr/local/bin/curl |
/usr/local/bin/curl |
…/usr/lib/libSystem.B.dylib |
/usr/lib/libSystem.B.dylib |
…/private/etc/ssl/cert.pem |
/etc/ssl/cert.pem(取自主机CA证书或下载的Mozilla证书) |
…/Volumes/linux/… |
/Volumes/linux/…→ 映射至主机文件系统 |
Kakehashi让客端代码在CPU上原生运行,性能损耗仅来自系统调用边界(TLS切换、备用栈、NEON寄存器保存/恢复、Rust调度),损耗程度取决于客端程序调用系统调用的频率——并非指令级模拟器。
在Ubuntu aarch64裸机(UTM)环境下,对包含约8000个文件、总大小约240 MiB的目录执行多文件7zz归档(参数-t7z -m0=lzma2 -mx=5 -mmt=4):
原生Linux 7zz |
Kakehashi运行Darwin 7zz |
性能比 |
|---|---|---|
| 耗时 ~22.5秒 | 耗时 ~118秒 | ~×5.2 |
在以压缩为主、文件数量少的测试场景下,性能差距通常小得多(约×1.1–1.2)。多文件场景的性能差距主要由路径遍历+每次系统调用的边界开销导致,与LZMA算法本身无关。
所有客端线程默认启用超级调用(Hypercall),仅在调试时可通过KAKEHASHI_HYPERCALL=0关闭(关闭后会通过svc→brk/SIGTRAP处理)。
本项目针对CI场景的核心目标,并非“达到原生macOS性能”,而是在廉价的Linux aarch64运行器上运行Darwin命令行工具,替代稀缺且昂贵的macOS资源。
GitHub Actions托管运行器(私有仓库超额费率,单位:美元/分钟;详见Actions运行器定价):
| 运行器类型 | 每分钟费率 |
|---|---|
| Linux 2核arm64 | $0.005 |
| Linux 2核x64 | $0.006 |
| macOS 3–4核(M1/Intel) | $0.062 |
| macOS高配(如12核/M2 Pro) | $0.077–$0.102 |
macOS标准运行器的费率约为Linux arm64的10–12倍,且未考虑运行时间差异。即使在Linux arm64上通过Kakehashi运行作业的耗时是macOS的5倍,计费成本仍可能更低(示例:5 × $0.005 ≈ $0.025 vs 1 × $0.062)。公共仓库的免费运行时长、自托管Linux运行器会进一步放大这一成本优势;此外macOS托管资源往往排队时间更长,且在GitLab SaaS中仅Premium/Ultimate版本可用或处于测试阶段。
仍需使用macOS运行器的场景:图形界面、代码签名/公证(codesign/notarization)、Xcode UI测试,或任何依赖非纯命令行Darwin二进制文件及非独立式libSystem的工作负载。
正确性优先,性能其次:CI流程的正确性通过cargo test/冒烟测试/7zz -mmt=4验证,而非“匹配原生运行时长”。性能优化进度记录于docs/roadmap.md。
docker build -t kakehashi:dev -f Dockerfile.dev .
docker run --rm -v "$PWD":/src -w /src kakehashi:dev \
cargo test --workspace --exclude kh-libsystem
# 完整冒烟测试(编译+clippy检查+测试+微型运行验证)
./scripts/docker-smoke.sh
cargo build -p kakehashi --release
cargo test --workspace --exclude kh-libsystem
cargo clippy --workspace --exclude kh-libsystem --all-targets -- -D warnings
# 维护者注意:独立式ABI变更后需更新内置动态库
cargo build -p kh-libsystem --release --target aarch64-apple-darwin
./scripts/stage-libsystem.sh # 生成文件→crates/kh-runtime/resources/libSystem.B.dylib
libSystem库的查找优先级:--libsystem命令行参数 → KAKEHASHI_LIBSYSTEM环境变量 → kh程序所在目录 → 包资源目录resources/ → 编译进kh-runtime的内置字节码
| 测试目标 | 执行命令 | 输出结果 |
|---|---|---|
| 单元测试 | cargo test --workspace --exclude kh-libsystem |
终端输出测试结果 |
| Docker冒烟测试 | ./scripts/docker-smoke.sh |
最终输出smoke ok |
| 基准用例测试 | kh run --expect-code … tests/fixtures/… |
详见tests/fixtures/README.md |
| Clang探针测试 | kh run --root tests/fixtures/bottle tests/clang-probe/puts_hello |
标准输出hello |
真实Darwin 7zz测试 |
./scripts/docker-7zz.sh … |
输出文件存于主机.tmp/kh-out/ |
真实Darwin curl测试 |
./scripts/docker-curl.sh … |
输出文件存于主机.tmp/kh-out/;探针日志存于.tmp/kh-curl-probe/ |
| 公平CPU性能基准测试 | ./scripts/bench-fair-local.sh |
结果存于主机.tmp/kh-bench-fair/ |
.tmp/、.kh/和target/目录已被加入git忽略列表。
Bottle机制将Linux文件系统映射为客端的/Volumes/linux/…路径:
| 客端路径 | 主机对应路径 |
|---|---|
/Volumes/linux/src/README.md |
<仓库根目录>/README.md |
/Volumes/linux/out/demo.7z |
<仓库根目录>/.tmp/kh-out/demo.7z(持久化存储;docker-7zz.sh默认输出路径) |
/Volumes/linux/tmp/… |
容器内/tmp/…——docker run --rm后会被清除 |
| 脚本 | 用途 |
|---|---|
scripts/stage-libsystem.sh |
编译生成动态库并复制至crates/kh-runtime/resources/ |
scripts/install-linux.sh |
本地编译并安装kh+执行bottle ensure |
scripts/docker-smoke.sh |
在Docker镜像内执行完整冒烟测试套件 |
scripts/docker-7zz.sh |
通过Kakehashi运行Darwin版7zz(输出文件存于.tmp/kh-out) |
scripts/docker-curl.sh |
通过Kakehashi运行Darwin版curl(使用方式与docker-7zz.sh一致) |
scripts/docker-curl-probe.sh |
KH_CURL_PROBE=1模式的封装脚本(日志存于.tmp/kh-curl-probe) |
scripts/docker-curl-options.sh |
分阶测试curl参数组合(tier1…tier10、tier9-10、all,结果存于.tmp/kh-curl-options) |
scripts/docker-git.sh |
通过Kakehashi运行CLT中的Apple版git(包含软件扫描+.kh/data缓存) |
scripts/bench-fair-local.sh |
对比原生运行与Kakehashi运行的压缩性能(结果存于.tmp/kh-bench-fair) |
本项目采用Apache License 2.0许可协议。详见LICENSE.txt及.
声明:本项目并非基于Darling开发。请勿分发Apple专有SDK或二进制文件。