ビルドとは何か — コンパイラとビルドシステムの違い¶
一言で言うと¶
- コンパイラ(g++, cl.exe): 1つの翻訳単位を機械語にする「職人」
- ビルドシステム(CMake+Make/Ninja, MSBuild): 「何を・どの順で・どの設定で職人に依頼し、リンクまで完走させるか」を管理する「現場監督」
g++ main.cpp で済むのは1ファイルの時だけ。実際のゲームは数百〜数万ファイル+ライブラリ+プラットフォーム別設定であり、その管理が「ビルド」という仕事です。
ビルドの全体像(監督の仕事)¶
ソース群 ──┐
├─ ①どの.cppをコンパイルするか(ソースリスト)
設定 ──────┼─ ②どんなフラグで(-O2? -std=c++20? どのdefine?)
├─ ③どの順で(依存関係: 変更されたものと、その影響先だけ再コンパイル)
ライブラリ ─┼─ ④何とリンクするか(-lfmod、パスの解決)
└─ ⑤成果物をどこへ(bin/game.exe、シンボルファイル)
- ③がインクリメンタルビルドの核心: ファイルのタイムスタンプ+ヘッダー依存関係(コンパイラが出す依存情報)から「再コンパイルすべき最小集合」を計算する(→ ビルド速度)
- Unityで「保存すると勝手にコンパイルされる」のは、Unityエディタがこの監督業を全部やっているから。C++では自分で(またはUEのUBTのようなツールが)監督をやる必要がある
手動でやってみる(1回だけの体験として)¶
g++ -std=c++2a -c enemy.cpp -o enemy.o # ①翻訳単位ごとにコンパイル
g++ -std=c++2a -c main.cpp -o main.o
g++ main.o enemy.o -o game.exe # ②リンク
# ファイルが増えるたび・依存が増えるたび、手動管理は破綻する → ビルドシステムへ
道具の階層(混乱しやすいので整理)¶
[メタビルドシステム] CMake, Premake … ビルド設定の「設計図」を書く(プラットフォーム非依存)
↓ 生成
[ビルドシステム] Make, Ninja, MSBuild(.vcxproj), Xcode … 依存解決と実行
↓ 呼び出し
[コンパイラ/リンカ] g++, clang++, cl.exe / ld, link.exe
- CMakeはビルドしない(NinjaやVSプロジェクトを生成する)。この区別が分かるとエラーの切り分け(CMakeの設定ミスか、コンパイルエラーか)ができる
- UEのUBT(Unreal Build Tool)はこの階層を自前で持つ独自の監督(→ 第10部)
C#/Unityとの対応¶
| C#/Unity | C++ |
|---|---|
| .csproj / MSBuild(Riderが隠している) | CMakeLists.txt / vcxproj |
| Unityのスクリプトコンパイル(自動) | ビルドシステムの実行(明示的) |
| アセンブリ参照(GUIで追加) | ライブラリのリンク設定(パス・名前・順序) |
| Library/のキャッシュ | ビルドディレクトリの.oとキャッシュ |
| 「Reimport All」 | クリーンビルド |
C#で「ビルドはIDEが勝手にやるもの」だった感覚に対し、C++はビルドが構成物(コードと同じくレビュー対象)という文化の違いがあります。
ゲーム開発での現実¶
- ゲームはマルチプラットフォームビルド(Windows/PS/Switch/…)が前提になりやすく、設定の分岐管理がビルドシステムの主戦場
- アセットビルド(テクスチャ圧縮等)もビルドの一部として同じ依存グラフ思考で管理される(ビルドパイプライン)
- 「ビルドを壊した」が全員を止める——CI(→ 品質ツール)が門番になる
理解度チェック¶
- コンパイラとビルドシステムの役割分担を「職人と監督」以外の言葉で説明できますか。
- インクリメンタルビルドは何の情報を使って「再コンパイル最小集合」を決めますか。
- CMakeが「ビルドしない」とはどういう意味ですか。
演習¶
samples/tu_demo/ を、(a) 手動のg++コマンド列でビルド、(b) 1ファイルだけ変更して全再コンパイルの無駄を体感、(c) 次ページのCMake化で(b)が解決されることを確認する準備をしてください。