動画で読む
Kakehashi は macOS の CLI バイナリを Linux ARM で「そのまま」動かす
結論から書きます。Kakehashi は、macOS 向けにビルドされた ARM64 バイナリ(Mach-O 形式)を、再コンパイルも JIT もなしに Linux の aarch64 上で直接実行するユーザースペースの翻訳層です。Wine が Windows の実行ファイルを Linux で動かすのと発想は同じで、その macOS 版にあたります。
2026 年 8 月に Show HN で流れてきたとき、正直「また動かないやつだろう」と身構えました。macOS バイナリを Linux で動かすと言われて、素直に信じられる人は少ないはずです。ところが README のデモを追うと、7-Zip の 7zz や curl といった実在の macOS CLI ツールが、Linux ARM 上でちゃんと圧縮やダウンロードをこなしている。GitHub のスター数はこの記事を書いている時点で 157、コミットは 68。まだ小さい実験プロジェクトですが、動くところは確かに動いています。
Kakehashi が面白いのは、仮想マシンやエミュレータを立てないところです。macOS を丸ごと動かすのではなく、バイナリが呼ぶ Darwin(macOS のカーネル層)のシステムコールを、実行時に Linux のシステムコールへ翻訳する。CPU 命令自体は同じ ARM64 なので変換は要らず、OS の境界だけを差し替える発想です。
仕組み: Mach-O ローダと Darwin syscall の翻訳
Kakehashi の中身は、大きく 3 つの部品でできています。バイナリを読み込むローダ、実行時の面倒を見るランタイム、そして macOS 流のシステムコールを Linux 流へ変換する syscall 翻訳です。
一つ目の kh-loader は、Mach-O(macOS の実行ファイル形式、Linux でいう ELF に相当)を解析してメモリに配置します。二つ目の kh-runtime が本体で、メモリ管理、トラップ処理、BSD 系システムコールの翻訳を担当し、さらに freestanding な libSystem(macOS の標準 C ライブラリ群)を埋め込んで、バイナリが期待する呼び出し先を用意します。
技術的に面白いのは、システムコールをまたぐたびに TLS(Thread Local Storage、スレッド固有の記憶領域)を切り替え、別スタックへ移し、NEON レジスタ(ARM の SIMD 演算レジスタ)を退避・復元している点です。macOS と Linux では、同じ ARM64 でもスレッドの状態管理やレジスタの約束事が違う。その差を syscall の 1 回ごとに橋渡ししているわけで、名前が「架け橋」なのも頷けます。
この設計は、以前読んだ Librepods が AirPods の非公開プロトコルを解いた話と質感が似ています。公式に公開されていない他社の仕様を、観察と再現で埋めていく。壊れる前提で運用する覚悟も含めて、同じ系譜の仕事だと感じました。
今どこまで動いて、どこで壊れるのか
現時点で「動く」と明言されているのは CLI ツールの一部で、GUI や署名まわりはまだ動きません。ここを取り違えると期待値がずれるので、最初に線を引いておきます。
動作が確認されているのは、7-Zip の 7zz(-mmt=4 によるマルチスレッド圧縮を含むフル操作)、curl(OpenSSL 連携での HTTP/HTTPS ダウンロードと証明書検証)、clang のコンパイル用フィクスチャ、そしてスレッド生成です。並列圧縮が通るということは、pthread まわりの翻訳が実用水準で動いている証拠で、これは地味にすごい。
一方で動かないものも、README が正直に並べています。curl のフル機能(POST ボディ、プロキシ、HTTP/3 の端から端まで、すべてのスキーム)、Apple の Security.framework 本体、git と CLT(Command Line Tools、Xcode のコマンドライン一式)、GUI、そして codesign。次の目標は kh install xcode-tools 経由での git だそうです。要件も確認しておくと、ビルドには Rust 1.88 以降、実行には Linux aarch64、ページサイズは 4 KiB か 16 KiB が前提になります。
×5.2 遅い翻訳層に、それでも意味がある理由
正直に言えば、速くはありません。README のベンチマークでは、複数ファイルの 7-Zip 圧縮でネイティブ Linux 比おおよそ ×5.2 遅い。それでも意味があるのは、CI のコスト構造がこの遅さを飲み込むからです。
内訳を見ると、単一ファイルの操作なら差は ×1.1〜1.2 程度に縮みます。遅延の主因はアルゴリズムではなく、syscall の境界を越えるたびのオーバーヘッドなので、システムコールを何度も叩く多ファイル処理ほど不利になる。逆に言えば、重い計算を一気に回すワークロードでは差が出にくいということです。
ここで効いてくるのが料金です。GitHub Actions の Linux aarch64 ランナーは 1 分あたり $0.005、対して macOS ランナーは $0.062。ざっと ×12 の開きがあります。仮に Kakehashi で ×5 遅くなっても、単価が ×12 安ければ合計コストはむしろ下がる計算です。macOS の CLI ツールを CI で回したいだけなら、高い mac ランナーを借りずに安い Linux で済ませられる。この一点に、この翻訳層の存在意義が集約されています。
余談ですが、CI を長く回す運用の落とし穴は別途 launchd で自動化を 24/7 回す話にも書きました。安いからと回しすぎると、別のところで足を掬われます。
運用者として、どこで使い、どこで避けるか
私の結論は、「動くと分かっている CLI ツールを、コスト目的で Linux ARM の CI に載せる」用途に限ればアリ、それ以外はまだ避ける、です。実験段階のプロジェクトなので、本番の署名や配布経路に組み込むのは時期尚早だと考えています。
使うと決めた場合の勘所は 3 つあります。第一に、バージョンを固定すること。68 コミットで活発に動いている以上、昨日通ったバイナリが今日壊れても不思議はありません。第二に、動作確認済みのツール(7zz や curl)から始め、git や署名を要する工程は素直に mac ランナーへ逃がすこと。第三に、Docker/Colima での smoke test が通る構成を、自分の CI にも一段挟んでおくことです。
逆に避けるべきなのは、codesign や Security.framework に依存する配布ビルド、GUI を要するテスト、そして「とりあえず全部 Linux に寄せたい」という発想です。Kakehashi は万能の互換層ではなく、macOS の CLI という限定された戦場で、コストという武器を握ったツールだと捉えるのが実態に合っています。橋は便利ですが、渡れるのは橋が架かっている場所だけです。
よくある質問
- Kakehashi は macOS そのものを Linux で動かせますか?
- いいえ。macOS を丸ごと動かすのではなく、macOS 向けにビルドされた ARM64 の CLI バイナリを、Darwin のシステムコールを Linux のものへ翻訳して実行します。GUI や OS 機能全般には対応していません。
- 遅いのに CI で使う意味があるのはなぜですか?
- Linux aarch64 ランナーは 1 分 $0.005、macOS ランナーは $0.062 とおよそ ×12 の価格差があるためです。Kakehashi で ×5 程度遅くなっても、単価が大幅に安いため合計コストは下がりえます。
- どんな macOS ツールが動きますか?
- 現時点では 7-Zip の 7zz、curl(HTTP/HTTPS ダウンロード)、clang のコンパイル用フィクスチャ、スレッド生成が確認されています。git、codesign、GUI、Security.framework は未対応です。
- 実行には何が必要ですか?
- ビルドに Rust 1.88 以降、実行に Linux aarch64 環境が必要です。ページサイズは 4 KiB または 16 KiB が前提で、バイナリ取得に curl/wget と tar があると便利です。