コンテンツにスキップ

ビルドとは何か — コンパイラとビルドシステムの違い

一言で言うと

  • コンパイラ(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(→ 品質ツール)が門番になる

理解度チェック

  1. コンパイラとビルドシステムの役割分担を「職人と監督」以外の言葉で説明できますか。
  2. インクリメンタルビルドは何の情報を使って「再コンパイル最小集合」を決めますか。
  3. CMakeが「ビルドしない」とはどういう意味ですか。

演習

samples/tu_demo/ を、(a) 手動のg++コマンド列でビルド、(b) 1ファイルだけ変更して全再コンパイルの無駄を体感、(c) 次ページのCMake化で(b)が解決されることを確認する準備をしてください。


前: カテゴリ目次 | 次: 三大コンパイラ