🐧 Linux 総合学習プラットフォーム
クロスコンパイル ・ 上級

クロスツールチェーンの構成

クロスツールチェーンは、ターゲット向けのバイナリを作るために必要な道具一式です。中心となるのはコンパイラ(gcc)ですが、それ単体では動かず、アセンブラやリンカを含むbinutils、標準ライブラリのglibcやmuslなどがセットで必要になります。これらの実行ファイル名には arm-linux-gnueabihf- のようなトリプレットの接頭辞が付き、ホスト用の素のツールと区別されます。Debian系なら gcc-arm-linux-gnueabihf パッケージを入れると一式が揃い、本格的な構成には crosstool-NG や Yocto、Buildroot が使われます。

クロスコンパイルを実際に行うには、ターゲット向けのバイナリを作る道具が必要です。この道具一式をまとめてツールチェーン(toolchain)と呼びます。「チェーン(鎖)」という名のとおり、ソースコードを実行ファイルに変えるまでには複数の道具が鎖のようにつながって働いており、その連なり全体を指す言葉です。多くの人はコンパイラ(gcc)一つだけでビルドが完結すると思いがちですが、実際にはコンパイラの前後にいくつもの道具がいて、それらが揃ってはじめてターゲット用のバイナリが完成します。クロスツールチェーンとは、それらの道具をすべてターゲット向けに用意したセット、ということになります。

ツールチェーンを構成する道具たち

中心にいるのは、もちろんコンパイラの gcc です。これがC言語などのソースコードを、ターゲットのCPUが理解する機械語へ翻訳します。しかし gcc は単独では実行ファイルを作りきれません。翻訳された結果を実際のバイナリへまとめ上げるには、binutils(バイナリユーティリティ)と呼ばれる道具群が要ります。その代表が、アセンブリを機械語に変換するアセンブラ(as)と、複数のオブジェクトファイルやライブラリを結合して1つの実行ファイルにするリンカ(ld)です。gcc にソースを渡すと、内部では「プリプロセス→コンパイル→アセンブル→リンク」という工程が順に走りますが、このうちアセンブルとリンクを担っているのが、実はこの binutils なのです。さらに、できあがったバイナリを調べる readelf や objdump、不要なデバッグ情報を削ぎ落としてサイズを小さくする strip、ライブラリ書庫を作る ar なども、この binutils に含まれます。組込みでは容量が限られるため、出荷前に strip でバイナリを小さくする、といった場面でこれらの道具が地味に効いてきます。

もう一つ欠かせないのが標準ライブラリ(C library)です。printf や malloc のような、Cプログラムが当たり前に使う関数の実体は、コンパイラではなくこのライブラリが提供します。デスクトップやサーバで広く使われるのは glibc(GNU C Library)ですが、組込みではサイズが小さく軽量な musl や、さらに小さい uClibc-ng が選ばれることもあります。どのライブラリを使うかはターゲットの容量や用途で決まり、これがバイナリのサイズや互換性に効いてきます。加えて、ターゲットのカーネルが提供する機能を呼び出すための定義をまとめたカーネルヘッダ(Linux kernel headers)も、ライブラリと組み合わせて使われます。コンパイラ・binutils・C ライブラリ・カーネルヘッダ——この4つが揃って、はじめて使えるクロスツールチェーンになります。

ホスト用の道具と区別する命名

ここで一つ疑問が湧きます。ホストにはもともとホスト自身用の gcc や ld が入っているのに、ターゲット用のそれらをどうやって区別するのでしょうか。答えは名前です。クロスツールの実行ファイルには、arm-linux-gnueabihf- のようなトリプレットの接頭辞が付きます。つまりホスト用がただの gcc であるのに対し、Arm向けは arm-linux-gnueabihf-gcc、リンカは arm-linux-gnueabihf-ld、readelf は arm-linux-gnueabihf-readelf という名前になります。これらは多くの場合 /usr/bin の下に置かれ、ホスト用の素のツールと同じ場所に並んで共存します。この接頭辞のおかげで、両者が同じPCに同居していても取り違える心配がなく、名前を見ればその道具がどのターゲット用かが一目で分かります。逆に、接頭辞の付かない gcc を呼べばそれは常にホスト向けのコンパイラであり、ここを混同するとホスト用のバイナリができてしまいます。トリプレットそのものの読み方は次のトピックで詳しく扱いますが、まずは「ターゲット用の道具は接頭辞付きの名前で呼ぶ」という点を押さえておいてください。

ツールチェーンの入手方法

では、このツールチェーンをどう手に入れるのでしょうか。手軽なのはディストリビューションのパッケージを使う方法です。Debian/Ubuntu系なら sudo apt install gcc-arm-linux-gnueabihf と打つだけで、Arm向けの gcc・binutils・glibc が一式まとめて入り、すぐに arm-linux-gnueabihf-gcc が使えるようになります。64bit Arm向けなら gcc-aarch64-linux-gnu パッケージです。お試しや小さなプログラムなら、まずこれで十分です。一方で、ライブラリのバージョンや構成を自分で細かく決めたい本格的な開発では、ツールチェーン自体を専用ツールで構築します。代表的なのが crosstool-NG で、対話的な設定でコンパイラやライブラリの版を選んで自前のツールチェーンを組み上げられます。

さらに、組込みLinuxの製品開発では、ツールチェーンだけでなくルートファイルシステムやカーネルまでをまとめて作る統合的なビルドシステムが使われます。Buildroot は比較的シンプルにシステム全体を構築でき、Yocto Project(OpenEmbedded)はより大規模で、製品グレードのカスタムディストリビューションを作るのに使われます。これらは内部で適切なクロスツールチェーンを自動的に用意し、ターゲット向けの sysroot まで含めたSDKとして開発者へ提供してくれます。最初のうちは apt で入るツールチェーンで仕組みを体感し、扱う規模が大きくなったら crosstool-NG や Buildroot、Yocto へ——という順で触れていくと、ツールチェーンという土台の理解が無理なく深まります。どの入手方法を選んでも、コンパイラ・binutils・C ライブラリ・カーネルヘッダという構成要素は共通しているので、その中身を理解しておけば、ツールチェーンがどこから来たものでも落ち着いて扱えます。

この項目に出てくる用語

ツールチェーンつーるちぇーん
コンパイラ・アセンブラ・リンカ・ライブラリなどビルドに必要な道具一式。
トリプレットとりぷれっと
ターゲットを表す識別子。例 arm-linux-gnueabihf。
ABIえーびーあい
関数呼び出し規約やデータ配置の約束事(Application Binary Interface)。

関連コマンド

arm-linux-gnueabihf-gccreadelfobjdump

▶ 学習アプリでこの続きを学ぶ・演習する