わかるUNIXの歴史 / 番外編 ③よそで作って、運ぶ・現代版

第8回「紙テープで運ぶ」の、いまの姿 ── 鶏なしで、卵を作る

クロスコンパイル ── 鶏なしで、卵を作る まだ何も動いていない新しい CPU。そこには OS もコンパイラも無い(鶏がいない)。ではどうやって最初のプログラムを用意するか ── すでに動く別の機械で、その CPU 向けの卵を焼く。 第8回の GE-635→PDP-7 と、同じ骨格の現代版です。

前提:第8回(クロスアセンブル)・第3回(着火) 種明かし:build / host / target を、ずらす

第8回で、生まれる前の PDP-7 は自分ではプログラムを作れず、GE-635 で作って紙テープで運んだ、と見ました。「よそで作って運ぶ」── この技は、今も現役どころか、あらゆる新機種の立ち上げの土台です。新しい CPU、スマホ、組込みマイコン ── どれも最初は「鶏がいない」状態から、手元の別の機械(PC)で、その機種向けの卵を焼くことで立ち上がります。これがクロスコンパイル。鶏と卵を、機械をずらして解く技です。

01三つの機械 ── build / host / target

クロスを正確に語るには、三つの役割を分けます(GNU の用語)。

三つの役割

build:コンパイラ自体をビルドする機械。

host:そのコンパイラが動く機械。

target:そのコンパイラが吐くコードが動く機械(クロスコンパイラを作るときだけ問題になる)。

この三つがどう一致・相違するかで、名前が変わります。下の図で切り替えてください。

図1:build / host / target。同じ機械には同じ色。native は三つとも同じ。cross は target だけ違う。Canadian Cross は三つとも違う

02なぜクロスか ── target に鶏がいない

新しい CPU を作ったとき、その target にはまだ何も動いていません。OS も、コンパイラも、アセンブラも無い。第8回の生まれる前の PDP-7 と同じ ── native(target 上で target 向けを作る)は、そもそも不可能。だから、すでに動く build 機(手元の PC)で、target 向けのコンパイラや OS を焼く。x86 の PC で ARM や RISC-V 向けを、あるいは OS すら載らない組込みマイコン向けを ── みなこの方式です。

# 手元の x86 PC(build=host) で、ARM(target) 向けをクロスコンパイル $ arm-linux-gnueabihf-gcc -o hello hello.c $ file hello hello: ELF 32-bit ... ARM # x86 では動かない。ARM 機に運んで動かす

03Canadian Cross ── 三つとも違う

もう一段ひねると、build・host・target が三つとも違うこともあります。これを Canadian Cross と呼びます。たとえば ── 速い Linux 機(build)で、Windows 上で動き(host)、ARM 向けコードを吐く(target)コンパイラを作る。ユーザは Windows で使い、成果物は ARM で走る、という具合。

つなぐ声 ── なぜ「カナダ風」なのか 奇妙な名前ですが、由来は政治のジョークです。この方式の整理が進んでいた当時、カナダに国政政党が三つあったことにかけて「三者三様=Canadian(Cross)」と名づけられました。技術用語にたまに紛れ込む、開発者たちの内輪ネタのひとつ。第8回の紙テープが「二つの機械(GE-635 と PDP-7)」だったのを、三つに増やしたのがこれ、と思えば十分です。
今回の急所 ── 鶏と卵を「ずらして」解く

クロスの本質は、第8回とまったく同じ ── 「target で target を作らなくていい。すでに動く build 機を借りればいい」。鶏がいない新機種でも、よその鶏から卵を得る。これは第3回「既存 cc を借りて着火」、第6回「O-code を運ぶ」、第8回「紙テープで運ぶ」と一本の同じ骨格。役割(build/host/target)をずらすことで、この機械の中では解けない鶏と卵を、別の(既に動く)機械へ移して解くのです。

◇ ◇ ◇

04やがて自立 ── target が native になる

クロスは立ち上げの手段であって、ゴールではありません。build 機で焼いたツールチェーンと OS を target に載せて起動できたら、やがて target 自身が、target 向けをビルドできるようになる ── native な自己ホスティング。これは第2回の Linux v0.11(MINIX という産室を出て自立)や、第8回の PDP-7(GECOS を卒業)と、まったく同じ筋書きです。下の図で、新アーキが「鶏なし」から「自立」まで立ち上がる流れを追ってください。

図2:新アーキの立ち上げ。target には最初なにも無い(鶏なし)。build 機でツールチェーンと OS をクロスコンパイルして載せ、起動し、やがて target が native に自己ホスティングする
正直な線 ── クロスは魔法ではない

(1) クロスは鶏と卵を解決しません。第8回と同じく、この機械の中で解くのをやめ別の(既に動く)機械へ移すだけ。連鎖は有限で、さかのぼれば最初の機械(第9・10回)に底を打ちます。(2) 実務のクロスは地味に大変です ── target 用のヘッダやライブラリ(sysroot)を揃える、libc をどう用意するか、実機が無ければ QEMU などのエミュレータでテストする、など。

(3) build/host/target は GNU の用語で、他の文脈(例:Rust など)では呼び方や区分が少し違うことがあります。(4) 「Canadian Cross」の由来は広く語られる逸話で、細部には諸説あります。要点は「三つの機械が全部違いうる」という構造です。

練習問題(今回の話だけで解けます)
  1. build・host・target をそれぞれ一言で。
    答えを見る
    build=コンパイラをビルドする機械、host=そのコンパイラが動く機械、target=そのコンパイラが吐くコードが動く機械。
  2. native・cross・Canadian Cross の違いを、三つ組の一致で説明せよ。
    答えを見る
    native=build=host=target(全部同じ)。cross=build=host で target だけ違う。Canadian Cross=build・host・target が三つとも違う。
  3. 新しい CPU の立ち上げで native が使えないのはなぜか。第8回の何と同じか。
    答えを見る
    target にまだコンパイラも OS も無い(鶏がいない)ので、target 上で target 向けを作れないから。生まれる前の PDP-7(第8回)と同じ状況で、既存の build 機を借りるしかない。
  4. クロスで立ち上げた target は、最終的にどうなるか。本編のどの回と同じ筋書きか。
    答えを見る
    やがて target 自身が target 向けをビルドできる native な自己ホスティングに到達する。第2回の Linux v0.11(産室を出て自立)や第8回の PDP-7(GECOS 卒業)と同じ。

まとめ役割をずらせば、鶏なしでも卵は焼ける

第8回「よそで作って運ぶ」の現代版がクロスコンパイル。三つの役割 ── build(ビルドする機械)・host(コンパイラが動く機械)・target(吐くコードが動く機械)── の一致/相違で、native(全部同じ)・cross(target だけ違う)・Canadian Cross(三つとも違う)が決まる。新しい CPU は最初 target に何も無い(鶏なし)ので native は不可能。だから既に動く build 機で、target 向けを焼く。

急所は第8回と同一 ── 「target で target を作らなくていい、動く build 機を借りればいい」。第3回(既存 cc)・第6回(O-code 運搬)・第8回(紙テープ)と一本の骨格で、鶏と卵を役割をずらして別の機械へ移して解く。そして立ち上げた target は、やがて native な自己ホスティングへ ── 第2回 Linux v0.11、第8回 PDP-7 の GECOS 卒業と同じ筋書き。クロスは鶏と卵を消しはしないが、有限の連鎖で、いつも「既に動く機械」から新機種を産み落とす技だった。

この文書は「わかるUNIXの歴史」番外編③です。技術:GNU の用語で、build はコンパイル作業を実行する機械、host は生成されたバイナリ(コンパイラ)が動く機械、target はクロスコンパイラを作る場合にそのコンパイラが生成するコードが動く機械。build=host=target を native、build=host かつ target が異なるものを cross、build・host・target が(build≠host を含め)すべて異なるものを Canadian Cross と呼ぶ。Canadian Cross の名は、この整理が進んだ当時カナダに三つの国政政党があったことにちなむとされる(逸話)。新アーキテクチャの立ち上げでは、target に動作環境が無いため、既存の build 機で target 向けツールチェーン・カーネル・ユーザランドをクロスコンパイルし、target で起動後にやがて native な自己ホスティングへ移行する。クロスは鶏と卵を解決せず、既に動く別機械へ移すが連鎖は有限で最初の機械に底を打つ(第9・10回)。sysroot・libc・エミュレータ(QEMU 等)による検証など実務上の課題がある。呼称・区分は文脈により差がある。 ── 印刷する場合はブラウザの「印刷」から「PDF に保存」を(印刷版では図の操作・解答は静止/非表示になります)。

印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1のボタンで native / cross / Canadian Cross を切り替え、図2のスライダーで新アーキの立ち上げを追えます。「答えを見る」で解答が開きます。