
2026/08/03 1:26
Show HN: Kakehashi – Linux ARM で macOS バイナリを実行するための実験的なユーザースペース
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Kakehashi は、JIT コンパイルや Apple の専用 SDK に依存せず、Linux aarch64 上で実際の macOS ARM64 ゲストを実行するためのオープンソースで CLI ファーストのユーザースペース翻訳層です。中心となるクリート(
kh-loader、kh-runtime、埋め込まれた libSystem.B.dylib)を中心に構成され、システムコールを翻訳するとともに、ゲストのファイルシステムをホストに /Volumes/linux/… を介して橋渡しします。具体的には、ゲストの /usr/local/bin をホストのバイナリに、/etc/ssl/cert.pem を CA バンドルにマッピングします。インストールは cargo install kakehashi(ソース:crates/kh-cli)で行い、事前に kh bottle ensure でボトルを確保します。ツールの追加は kh install、実行は kh run によって行われます(例:マルチスレッド圧縮用の kh run 7zz -- -mmt=4 や、単に kh run curl -- など)。Linux aarch64 ベアメタル、VM、Docker/Colima(ヘルパーがアーティファクトを .tmp/kh-out/ に出力)上で動作し、Rust 1.88 以上(Linux aarch64)、コンテナの種類に応じて 4 KiB または 16 KiB のページサイズに対応します。ベンチマークの結果では、Linux 側のマルチファイル 7-Zip 圧縮とネイティブ実行を比較した場合の全実行数のギャップは約 5.2 倍ですが、単一ファイルまたは圧縮負荷の重いワークロードではオーバーヘッドは約 1.1〜1.2 倍に留まります。Darwin クライアントツールを高価な macOS ランナー($0.062〜$0.102/分)ではなく、低価格な Linux ARM64 ランナー($0.005/分)上で実行できるため、パフォーマンスのオーバーヘッドがあっても Kakehashi は多くの場合で費用対効果に優れています。Apache 2.0 ライセンスの下にあり、Darling から派生していない本ツールは、自動化された CLI ワークフローのためにエコシステムを橋渡しする無料の代替手段を提供します。本文
Userspace macOS ARM64 → Linux aarch64 トランスレーションレイヤー
Linux aarch64 アーキテクチャ上で Darwin Mach-O ビナリを実行し、自立型の
libSystem をマッピングして BSD システムコールを翻訳することで、実際のゲスト環境(clang probes, 7-Zip 7zz, curl, スレッドなど)を動作させます。
概要
- 実行中の処理 (Live execution):
- Linux aarch64(ベアメタル、VM、Colima/Docker など)
- 読み込み/検査のみ (Dry-load / inspect):
- 任意のホスト(macOS を含む)
- 設計参照:
docs/
動作確認済み機能
Docker/Colima および UTM (Linux aarch64) 環境で検証済み。一度インストールするだけで以下が利用可能です。
cargo install kakehashi # またはチェックアウトしたリポジトリから: cargo install --path crates/kh-cli --force
ボトル(Bottle)の管理
kh bottle ensure
ゲストアプリのインストール
kh install 7zip # Darwin の 7zz → ゲスト環境 /usr/local/bin/7zz kh install curl # Darwin の curl → ゲスト環境 /usr/local/bin/curl
注意: 相対パス
とアーカイブのパスは、-oプロセスが実行されているホストの現在作業ディレクトリ(CWD)に対して解決されます。親ディレクトリを独自に作成するか、khの自動作成機能を利用してください。O_CREAT
- ボトルを通じて、
はホストのルートディレクトリにブリッジされ、**/Volumes/linux/…**となります。/ → /host
7-Zip (7zz) の使用方法
バージョン表示とヘルプ
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
マルチスレッド圧縮の検証(正しさゲート)
# マルチスレッドで圧縮する (-mmt=4) 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/ 下にアサート物が生成されます。
Hypercall はデフォルトで有効です(KAKEHASHI_HYPERCALL=1)。
./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 # Hypercall 有効状態での圧縮テスト 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
curl の使用方法
バナー表示 (G1)
kh run curl -- --version
HTTP GET → ファイルへ保存 (G3 / G5)
親ディレクトリが存在しない場合は自動作成されます。
- 期待される動作: 終了コード 0、約 559 バイト、HTML が "Example Domain" を含む。
# ファイルへの保存 kh run curl -- -sS -o .tmp/kh-out/body http://example.com/ 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 CA
ホストまたは
curl.se からダウンロードして使用します。
kh run curl -- -sS -o .tmp/kh-out/https-body https://example.com/ wc -c .tmp/kh-out/https-body
負のケース:不正な証明書
失敗する必要があります(
rc ≠ 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 # オプション行列(大規模テスト)→ .tmp/kh-curl-options/ ./scripts/docker-curl-options.sh tier1 ./scripts/docker-curl-options.sh tier9-10 ./scripts/docker-curl-options.sh all # tier1..10 をすべて実行
複数回実行時の無害なノイズ
— OpenSSL のオプション構成ファイル;HTTP/HTTPS はシードされた CA バンドルを通じて引き続き動作します。kh: open fail ENOENT(openat) path=/etc/ssl/openssl.cnf
— ボトルに含まれていない Apple フレームワーク;ロードパスをカバーするための**ソフトステブ(スタブライブラリ)**が機能します。WARN … skip dylib … Security/CoreFoundation
— ハッピーパス(正常な場合)では触られないシンボルです。unresolved strong symbol; bound to named missing trampoline
詳細とゲート:
を参照してください。docs/curl.md
プロジェクト構造と検証ゲート (Gates)
| 表面層 (Surface) | 備考 |
|---|---|
| Clang / フィキスチャープローブ | , |
| マルチスレッド 7zz -mmt=4 | Docker および UTM で検証済み |
| ボトル + 自立型 libSystem | を使用して dylib を埋め込みます |
| 単体テスト + clippy | ワークスペース全体でのテスト( は除外) |
まだ製品としての保証ではありません
- curl の完全な機能セット(POST ボディ、プロキシ、HTTP/3 全体エンドツーエンド、全てのスキームなど)。
- 本物の Apple Security.framework。
- 含まれていないもの: git / CLT (Command Line Tools)、GUI アプリ、codesign など。
- 次の製品スライス:
を用いたkh install xcode-tools
— 詳細はgit
を参照。docs/git.md
ライブラリ(Crates)一覧
| Crate | ロール |
|---|---|
| kakehashi | バイナリ (これをインストールする) |
| kh-loader | Mach-O のパース、マッピング、実行 |
| kh-runtime | メモリ管理、トラップ処理、BSD システムコール、ボトル機能;自立型 を埋め込みます |
| kh-libsystem | その dylib のソースコード(aarch64-apple-darwin 用のみで、Linux ホスト用の Crate ではありません) |
ゲスト用 dylib は
にベンダリングされ、コンパイル時にcrates/kh-runtime/resources/libSystem.B.dylibを使用して runtime に組み込まれます。include_bytes!を公開すると dylib が含まれるため、エンドユーザーは別途ダウンロードする必要はありません。kh-runtime
要件事項
- Rust: 1.88 以上
- ホスト: 実機実行 (
) /kh run
には Linux aarch64が必要ですkh trace - ページサイズ: コンテナ用 4 KiB、Asahi クラス機器用 16 KiB
- オプション:
/kh install 7zip
を行うために curl/wget + tar が望ましい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
ホストとゲストのパスマッピング
| ゲスト | ホスト |
|---|---|
| |
| |
| |
| |
| (ホスト CA またはダウンロードした Mozilla CA) |
| |
パフォーマンスに関する正直な評価
Kakehashi はゲストコードを CPU でネイティブに実行します。課税されるのはシステムコール境界(TLS 切り替え、別スタック、NEON の保存/復元、Rust デスパッチなど)であり、ゲストがどれだけ頻繁にその境界を渡るかによって変動します。命令セットエミュレーターではありません。
測定結果のギャップ
Ubuntu aarch64 ベアメタル(UTM)環境において、複数ファイルを対象とした 7zz アーカイブ(
-t7z -m0=lzma2 -mx=5 -mmt=4、約 8k ファイル / 約 240 MiB ツリー)の場合:
| メトリック | ネイティブ Linux 7zz | kh 下の Darwin 7zz | レーシオ |
|---|---|---|---|
| Wall time (実時間) | ~22.5 s | ~118 s | ~×5.2 |
- 圧縮負荷が高くファイル数が少ないサンプルでは、ギャップははるかに小さくなることが多い (~×1.1–1.2)。
- 大規模なマルチファイルのギャップは、「間違った LZMA アルゴリズム」によるものではなく、パスウォークと各システムコール境界のコストが支配的です。
- Hypercall はデフォルトで全てのゲストスレッドに対して有効です。デバッグ用のみ
で無効化してください(残存するKAKEHASHI_HYPERCALL=0
/svc→brk
など)。SIGTRAP
なぜ約×5 の遅さでも CI では有用なのか
CI における本製品の目標は「ネイティブ macOS と同じ速さ」ではなく、稀少かつ高価な macOS リソースの代わりに、安価な Linux aarch64 ランナー上で Darwin CLI ツールを実行することです。
GitHub 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 ランナー上の kh 実行が、同じ作業を macOS ランナー上で行った場合と比較して約×5 遅いとしても、請求されるコストは依然として低くなる可能性があります(例:
5 × $0.005 ≈ $0.025 vs 1 × $0.062)。
- macOS ランナーが優位になるケース: GUI アプリ、codesign/notarization、Xcode UI テスト、または自立型 libSystem 下の純粋な CLI Darwin バイナリではないワークロード。
- ゲート(Gates)としての位置づけ: CI の正しさは
/ Smoke テスト /cargo test
で保証され、「ネイティブのウォールクロックを一致させる」ことが目的ではありません。パフォーマンスに関する作業は7zz -mmt=4
で追跡されています。docs/roadmap.md
クイックスタート(Apple Silicon 上の Docker / Colima)
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- Crate の resources/ ディレクトリ
に埋め込まれたバイト列kh-runtime
テストマッピング
| ゴール | コマンド | アサート物 (Artifacts) |
|---|---|---|
| 単体テスト | | ターミナル出力 |
| Docker スモーク | | "smoke ok" で終了 |
| フィキスチャー | | を参照 |
| Clang プローブ | | 標準出力: |
| リアルな Darwin 7zz | | ホスト |
| リアルな Darwin curl | | ホスト ; プローブ → |
| 公平な CPU ベンチマーク | | ホスト |
注意:
,.tmp/, および.kh/は gitignore されています。target/
ゲストパスとホストパス(Docker 補助スクリプト)
ボトルは Linux FS を
としてブリッジします:/Volumes/linux/…
| ゲストパス | ホストパス |
|---|---|
| |
| (永続的;デフォルト出力先) |
| コンテナ内の — で消失します |
スクリプト参照表
| スクリプト | 目的 |
|---|---|
| 製品ビルド → |
| ローカルビルド + kh インストール + ボトル確保 |
| Dockerfile イメージ内のスモークスイート |
| kh 下の Darwin 7zz(出力先は ) |
| kh 下の Darwin curl( と同じ形状) |
| KH_CURL_PROBE=1 をラップするスクリプト(ログ → ) |
| 段階的な curl フラグスモーク(tier1…tier10、tier9-10、all → ) |
| CLT 下の Apple git(kh 経由で動作; + キャッシュ) |
| ネイティブ vs kh 圧縮ベンチマーク(アサート物 → ) |
ライセンス
Apache License 2.0。
および LICENSE.txt
を参照してください。NOTICE
免責事項: このプロジェクトは Darling から派生したものではありません。プロプライエタリな Apple SDK や blobs をベンダリングしないでください。