第8部 演習 — ビルドとライブラリ¶
問1. 概念確認¶
次の道具はどの層のものですか(メタビルド/ビルドシステム/コンパイラ/リンカ/その他)。
- Ninja 2. CMake 3. cl.exe 4. link.exe 5. clang-tidy 6. AddressSanitizer
解答
1. ビルドシステム。2. メタビルド(設計図からNinja等を生成 — 自身はビルドしない)。3. コンパイラ(MSVC)。4. リンカ(MSVC)。5. 静的解析ツール(Clang基盤)。6. コンパイラが埋め込む実行時検査(サニタイザ)([ビルドとは](01_what_is_build.md)、[品質ツール](06_debugging_and_analysis.md))。問2. コード読解(エラーメッセージ)¶
次のエラーの原因として最も可能性が高いものと、確認手順を答えてください。
解答
physics.lib が**Release構成**(IDL=0)でビルドされ、main.objが**Debug構成**(IDL=2)——構成違いのバイナリ混在([ABI互換性](07_link_errors.md))。確認: physics.libの入手元がDebug/Release両方を提供しているか、自分のリンク設定がどちらの.libを指しているか。対処: 構成ごとに対応する.libをリンクする(CMakeなら `$問3. 問題のある構成の改善¶
「common.h に全クラスのincludeとよく使う定数を集約し、全.cppがこれをincludeしている。定数を1つ変えると全ビルド(15分)が走る」。改善案を3つ、効果順に挙げてください。
解答の要点
(1) **common.hの解体**: 定数系(高頻度変更)とライブラリinclude(低頻度)を分離し、各.cppは必要なものだけincludeする——変更の波及範囲を縮める根本対策([ビルド時間](05_build_speed.md)、[凝集度](../01_design_basics/03_cohesion_and_coupling.md)の物理版)。(2) 低頻度変更部分(標準ライブラリ等)を**PCH化**——パースの重複を除去。(3) 調整頻度の高い定数は**データファイル化**(ホットリロード)し、コンパイル自体を不要に([Type Object](../04_game_patterns/type_object_and_sandbox.md)方向)。問4. 設計比較¶
社内ライブラリ「math_utils」を、(a) ヘッダーオンリー(全部inline/テンプレート)、(b) 静的ライブラリ、(c) DLL、のどれで配るか。利用チームが5つ、更新頻度は月1、性能クリティカルな小関数中心、という条件で比較してください。
解答の要点
(a) 小関数のインライン化が効く(性能◎)、導入が楽。代償: 利用側のビルド時間増、更新が全チームの再コンパイル。(b) ビルド時間は改善するが、小関数の呼び出しコスト(LTOで緩和可)とバージョン運用が必要。(c) 月1更新でDLL差し替えは魅力だが、C++ ABI境界の危険(コンパイラ・構成の統一が必要)と小関数のDLL呼び出しコストで不利([ライブラリ](../06_cpp_internals/04_object_files_and_libraries.md))。この条件(小関数・性能重視)なら**(a)が定石**。数学ライブラリがヘッダーオンリー(glm等)なのはこの理由。問5. デバッグ問題¶
「昨日まで通っていたビルドが、ライブラリを最新版に上げたら undefined reference to Physics::Step(float) になった」。考えられる原因を2つと確認方法を書いてください。
解答の要点
(1) 新版でシグネチャが変わった(`Step(float, int)` になった等): ヘッダーは新しいが.libが古い(またはその逆)——`nm/dumpbin` で.lib側の提供シンボルを確認し、ヘッダーの宣言と突き合わせる([リンクエラー](07_link_errors.md))。(2) 新版でその関数がinline化/削除/別モジュール移動された: リリースノートとヘッダーdiffを確認。教訓: **ライブラリ更新はヘッダーとバイナリをセットで**+クリーンビルド。問6. 説明問題¶
「なぜUnityではビルドのことをほぼ考えなくてよかったのに、C++では一大テーマなのか」を、ヘッダー・テンプレート・ABIの3語を使って4文以内で説明してください。
解答例
C#はヘッダーがなく、参照アセンブリのメタデータから型情報を読むので、宣言の配布と再パースという問題自体がない。ジェネリックは実行時に実体化されるため、C++テンプレートのような「翻訳単位ごとに作っては捨てる」コンパイルコストもない。さらに.NETはABIがランタイムで統一されており、バイナリ混在の互換問題も考えなくてよい。C++はこの3つ(ヘッダーの物理コピー、コンパイル時実体化、処理系ごとのABI)を自分で管理する代わりに、実行時コストゼロの抽象と決定的な性能を得ている([ビルド時間](05_build_speed.md)、[ABI](../06_cpp_internals/03_symbols_and_linkage.md))。問7. 小規模実装問題¶
samples/cmake_demo/ を拡張してください:
- 新ライブラリ
game_ai(game_coreに依存)をターゲットとして追加 - Debug構成でのみ
GAME_DEBUG_DRAWをdefine(target_compile_definitions+$<CONFIG:Debug>) - (発展)
enable_testing()+ 最小のテスト実行ターゲット
評価基準
(a) 依存の向きが game_ai → game_core の一方向で、逆リンクがない([依存の方向](../01_design_basics/04_dependency.md)のビルドでの表現)。(2) Release構成でdefineが消えることを確認。(3) `ctest` が走れば完了。前: リンクエラー | カテゴリ目次 | 第9部: Unity/C#との対応へ