クロスコンパイラは簡単に言うと、「今使っているパソコンとは違う種類の機械で動くアプリを作るためのコンパイラ」です。
「クロスコンパイラって何?」「どんな時に使うの?」と疑問に思ったことはありませんか?
例えば、Windows PCでAndroid向けのアプリをビルドしたり、MacでiPhone向けのアプリを作ったりするときに使われています。
この記事では、仕組みの説明に加えて、普段使っているWindows PC(x64)から、実際にLinux ARM64向けのバイナリをビルドして、本当にCPUとOSが違うファイルができているかを検証します。読み終えると、クロスコンパイラの仕組みと試験でよく出るポイントをマスターできると思いますので、ぜひ最後まで読んでいただけると嬉しいです。
クロスコンパイラとは?
クロスコンパイラは、次の2つが異なるときに使うコンパイラです。
- プログラムを作るPC(ホスト環境/ビルド環境)
- そのプログラムを動かす機械(ターゲット環境)
通常のコンパイラ(ネイティブコンパイラ)は、同じPC上で動くプログラムを作りますが、クロスコンパイラは別の環境で動くプログラムを作ります。
スマホの例で考えると
- Windows PC → Android向けアプリのビルド
- Mac → iPhone(iOS)向けアプリのビルド
このように別の環境で動くバイナリを作るコンパイラがクロスコンパイラです。
【試験ポイント】基本情報技術者試験では、「ホスト環境」と「ターゲット環境」という用語が頻出します。
なぜクロスコンパイラが必要なの?
理由1:CPUが違うと理解できる命令が違う
スマホとPCでは、搭載されているCPUが異なります。
- PC:Intel / AMD(x86系、x64系)
- Android:Snapdragon、Mediatek(ARM系)
- iPhone:Aシリーズ(ARM系)
CPUが違うと、機械語の形式(命令セット)も変わるため、PC用にビルドしたものをスマホでは動かせません。
理由2:OSが違うから
OSごとに実行ファイルの形式も、利用できる機能の呼び出し方も違います。
- Windows(実行ファイル形式:PE、拡張子.exe)
- Linux(実行ファイル形式:ELF、拡張子なし)
- iOS(実行ファイル形式:Mach-O)
そのため、動作させたいOS・CPUに合わせたバイナリを作る必要があります。これらを一括で解決してくれるのがクロスコンパイラです。
過去問例(基本情報技術者試験)
基本情報技術者試験では、次のような問題が出題されています。
問題:
あるコンピュータ上で,異なる命令形式をもつ別のコンピュータで
実行できる目的プログラムを生成する言語処理プログラムはどれか。
(基本情報技術者平成17年秋期 午前問36)
この問題の答えが、まさにクロスコンパイラです。
キーワードは「別の機械用のプログラムをPCで作る」。これが出てきたらクロスコンパイラの合図です。
【実測】Windows(x64)からLinux ARM64向けに実際にビルドしてみる
百聞は一見にしかずなので、手元のWindows PC(x64)から、追加のツールを何もインストールせずに.NET SDKだけでクロスコンパイルを試してみます。.NETはターゲットを指定するだけで、対応する実行ファイルを生成してくれます。
# ①ホストと同じ環境向け(比較用・ネイティブビルド)
dotnet publish -c Release -r win-x64 --self-contained true -o out_win_x64
# ②クロスコンパイル:Linux ARM64向け
dotnet publish -c Release -r linux-arm64 --self-contained true -o out_linux_arm64①はいつも通りビルドが終わり、生成されたCrossDemo.exeはそのままダブルクリックで実行できました。
Hello from a cross-compiled binary!
target RID: win-x64問題は②です。Windows機であるこのPCの中には、Linux ARM64を実行できる環境はどこにもありません。それでも本当に「別の機械用の実行ファイル」ができているのか、生成されたファイルの中身を直接読んで確かめてみました。
data = open("out_linux_arm64/CrossDemo", "rb").read(20)
print("magic:", data[0:4])
print("class:", "ELF64" if data[4] == 2 else "ELF32")
e_machine = data[18] | (data[19] << 8)
print("e_machine:", hex(e_machine))①のWindows向けexeと②のLinux ARM64向けバイナリ、それぞれの実行ファイル形式のヘッダーを実際に読んだ結果を並べます。
[① out_win_x64/CrossDemo.exe … ホスト向けネイティブビルド]
magic: b'MZ' (Windows PE形式)
PE sig: b'PE\x00\x00'
machine: 0x8664 = x64 (AMD64)
[② out_linux_arm64/CrossDemo … クロスコンパイル]
magic: b'\x7fELF' (Linux ELF形式)
class: ELF64
endian: little
e_machine: 0xb7 = AArch64 (ARM64)結果は一目瞭然でした。①は先頭2バイトが”MZ”のWindows PE形式で、CPU種別を示すmachineは0x8664=x64。一方②は先頭4バイトが”\x7fELF”のLinux ELF形式で、CPU種別を示すe_machineは0xb7=AArch64(ARM64)でした。同じソースコード・同じ開発機から、実行ファイルの形式(PE⇔ELF)もCPU種別(x64⇔ARM64)も全く別のバイナリが2種類生成されたことが、ヘッダーの実測値から確認できます。
もちろん②のCrossDemoファイルはこのWindows機では実行できません(ELF形式のバイナリをWindowsが直接実行する仕組みはないため)。実行するには実際のLinux ARM64環境(Raspberry Piなど)が必要ですが、「動かせる環境がなくても、正しい形式のファイルは作れる」のがクロスコンパイラの本質だと、このヘッダー比較でよく分かると思います。
よくある失敗例と対処法
失敗例1:PC用ライブラリをそのまま使おうとする
症状:リンク時に「file not recognized」「wrong ELF class」などのエラーが出る
原因:ホスト環境(PC)用にビルドされたライブラリを、ターゲット環境(スマホや組み込み機器)用のビルドでリンクしようとしている。上の実測のとおり、x64向けとARM64向けでは実行ファイルの中身(machine種別)がそもそも違うため、混ぜることはできません。
解決策:
- ターゲット環境用にクロスコンパイルされたライブラリを用意する
- 本記事のように、実行ファイルのmachine種別を直接確認する癖をつける
失敗例2:実機でテストせずに開発を進める
症状:ビルドは通るが、実機に持っていくと動かない、または動作が遅い
原因:クロスコンパイルは「正しい形式のファイルを作る」ところまでしか保証しません。実機の性能やOSの細かい挙動までは、実際に動かさないと分かりません。
解決策:
- 早い段階から実機でテストする
- 実機の性能制約(CPU、メモリ)を考慮したコードを書く
失敗例3:エンディアンの違いを考慮していない
症状:数値データが正しく読み込めない、画像が壊れる
原因:PCとターゲット機器でエンディアン(バイトオーダー)が異なる。今回のバイナリ確認でもendian: littleと実際に読み取ったように、ヘッダーにエンディアン情報が明記されているのはこのためです。
- PC(x86)・多くのARM機器:リトルエンディアン
- 一部の組み込み機器:ビッグエンディアン
解決策:
- バイナリデータを扱う際はエンディアン変換関数を使う
htonl()、ntohl()などの標準関数を活用
基本情報技術者試験での出題ポイント
クロスコンパイラは基本情報・応用情報の両方で頻出です。特に、以下のポイントがよく問われます。
出題ポイント①:ホスト環境とターゲット環境
- ホスト(Host):コンパイルする側(今回でいうWindows x64のPC)
- ターゲット(Target):実際にプログラムを動かす側(今回でいうLinux ARM64機器)
クロスコンパイラは「ホストとターゲットが異なる」状況で用います。試験ではこの関係性を問う問題が非常に多いです。
出題ポイント②:バイナリ形式の違い
今回の実測で確認したとおり、実行ファイルの形式そのものがOSごとに違います。
- PE形式(先頭”MZ”)→ Windows用
- ELF形式(先頭”\x7fELF”)→ Linux用
- x64 / AArch64(ARM64) → machine種別で判別できるCPUアーキテクチャ
これを理解しておくとアーキテクチャ問題にも強くなるので、基礎知識として覚えておきたい部分です。
出題ポイント③:ネイティブコンパイラとの違い
- ネイティブコンパイラ:ホスト=ターゲット(同じ環境で動く)
- クロスコンパイラ:ホスト ≠ ターゲット(別の環境で動く)
この対比は試験で頻出です。
【試験頻出問題例】
問:Windows PC上でLinux組み込み機器向けのプログラムを作成する場合、
使用するコンパイラはどれか?
答:クロスコンパイラ
まとめ
クロスコンパイラについてまとめます。
- クロスコンパイラは「別の環境で動くプログラムを作るコンパイラ」
- PCとスマホ(Android/iPhone)など、CPUやOSが違うと必要になる
- 実際にWindows(x64)からLinux ARM64向けにビルドすると、PE形式(0x8664)からELF形式(0xb7=AArch64)へ、実行ファイルの正体そのものが変わることをヘッダー実測で確認できた
- 基本情報では「ホストとターゲットの違い」が頻出
- すべての依存ライブラリもターゲット環境用に用意する必要がある
- エミュレータだけでなく、実機でのテストが必須
- ネイティブコンパイラとの違いを明確に理解する
「動かせる環境が手元になくても、正しいファイル形式は作れる」というのがクロスコンパイラの面白いところです。気になった方は、dotnet publish -r <RID>だけで手軽に試せるので、実際に生成されたファイルの先頭バイトを覗いてみてください。
ここまで読んでくださり、ありがとうございました。
この記事が皆様の学習に役立てば幸いです。


