C ++(またはC)で大規模なプロジェクトに携わったすべての人は、長いコンパイル時間の恐怖を感じました。 私が取り組んだ最初の「大きな」C ++プロジェクトは約10分でした。 それは私が以前働いていたものよりもはるかに長かったです。 キャリアの後半、ゲーム開発業界に参加したとき、本当に大きなプロジェクトをコンパイルする問題を感じました。 私たちのゲームは約1時間でした。
そして、ここに実装したソリューションがあります: Unity Builds (以降-UB )。
CおよびC ++に精通している読者の中には、以下で説明するものが何らかの「ハック」であると判断する人もいます。 これについては特に意見はありません。 もちろん、このアイデアには「ハッキング」なものがありますが、ほとんどのプラットフォームおよびほとんどのコンパイラーでの長いコンパイルの問題を本当に解決します。
詳細を掘り下げてUBの構成方法を説明する前に、このメカニズムがソリューションのリリースバージョンをビルドする通常の方法を置き換えるものではないことを明確にしたいと思います。 主なアイデアは、コードを変更するために毎日少なくとも8時間忙しい開発者のビルド時間を大幅に短縮することです。 バグの修正と機能の追加は、常に再コンパイルすることを意味します。 それぞれの編集は、誰もが彼ができる限り最善を尽くすことを期待しています。
それでも、各コンパイルは貴重な時間の損失であり、開発者の生産性の低下です。 これは、小さなソリューションをコンパイルするときでさえ悲しいことであり、大きなソリューションであっても、それが一番の問題になります。 ただし、プロジェクトの通常のリリースバージョンは、別々のコンピューターで、そしてもちろん通常の方法で収集する必要があることを忘れないでください。 つまり、この手順では変更は発生しません。
UBの基本原理は非常に単純です。 削減で構成されます。
- 個々のソースファイルのオープン数。
- コンパイル中に開かれるファイルの数。
各ソースファイル(.c、.cxx、.cc、.cppなど)は、オブジェクトファイルにコンパイルされます。 すべてのソースファイルがオブジェクトファイルにコンパイルされると、リンカーはすべてのオブジェクトファイルを収集し、それらから実行可能プログラムを作成します。 知らない人のために:ディスクへの読み取り\ディスクへの書き込みが最も遅い操作であり、コンパイラーに最も時間がかかります(検索(ポジショニング)時間のように読み取りと書き込みの問題ではありませんが、これは私たちのためではありません)本質が重要です)。 したがって、コンパイル時間を短縮したい場合は、入力/出力操作の数を減らすことから始めるとよいでしょう。
この記事をC ++プログラムのコンパイル方法に関するレッスンにしたくないので、いくつかの詳細を思い出させてください。 プリプロセッサは、コンパイルする前にすべてのファイルを解析することを知っています(このため、ファイルを開いて読み取ります)。 後で、コンパイラーは既に解析済みのファイルを再び開きます。 各オブジェクトファイルの作成と書き込みは、時間の無駄です。 最後に、オブジェクトファイルを読み取り、実行可能ファイルを作成するための手順を備えたリンカ。 それはすべて時間がたてば地獄に行く。
そして、この全体を大幅に高速化する方法があります。プロジェクト内の個々のソースファイルをコンパイルしません。 はい、できません。 代わりに、includeディレクティブを使用してプロジェクト内の他のすべてのファイルを含めるマスターファイルを作成します。 これは、コンパイルするマスターファイルです。
次に、Visual Studioで実際のアイデアを実証してみましょう(ただし、この原則は他のIDEや他のコンパイラで使用できます)。 最初の手順は、個別のビルド構成を作成することです。この構成では、標準のビルド手順を壊すことなく実験を行います。 Configuration Managerを開き、[ 新しい構成 ]をクリックして、 デバッグ構成に基づいて新しい構成を作成します( UnityDebugと呼びましょう)。 次に、プロジェクトにマスターファイルを追加し(UnityBuild.cppと呼びましょう)、プロジェクトソースコードの他のすべてのファイルをincludeディレクティブを使用してインクルードします。
現時点でプロジェクトをコンパイルしようとすると、当然、さまざまなクラス、関数、その他のものの複製に関する大量のメッセージを受け取ります。 これを修正するために、 UnityDebug構成のコンパイルファイルのリストからUnityBuild.cppを除くすべてのファイルを除外し、残りの構成のUnityBuild.cppファイルを除外します。 (コンパイルリストからファイルを除外するには、そのプロパティを開き、 「ビルドから除外」項目を見つけて、必要なすべての構成に対して「はい」に設定します)。
ほとんどすべての準備が整っており、ソリューションのコンパイルを試みることができます。 さらに2つのオプションがあります。すべてをコンパイルするかしないかです。 最初のケースでは、おめでとうございます-あなたはすでにパフォーマンスの向上を評価することができます。 2番目のケースでは、考える必要があります。 アセンブリスキームでは、プリプロセッサがすべてのソースファイルを1つの大きなファイルに収集することを理解してから考える必要があります。 そのため、一部の場所で名前を繰り返すことができるグローバルおよび静的変数と関数に関連するエラーが発生する可能性があります。 良い方法では、そのようなものはほとんどないはずですよね? まあ、彼らの数とお互いへの影響を減らすもう一つの理由があるでしょう。
次に、パフォーマンスの向上を評価しましょう。 私が働いていたあるgamedev会社でUBが導入されたとき、完全なコンパイルの時間は55分から6分に短縮されました。 別のケースでは、時間が10分から2分強に変更されました。
プロジェクトアセンブリの以前の構成が残っていることを忘れないでください。また、各アセンブリで好みに合わせてそれらを使用したり、 UBを使用したりできます。 また、プロジェクトに新しいソースファイルを追加するときにマスターファイルを更新する必要があることを忘れないでください。 もちろん、これはプロセスを多少複雑にしますが、マスターファイルに1行を追加するための数秒は、作業の大幅な高速化によって完全に補償されます。
そして最後に、 ビデオへのリンクがあります 。これは、記事で議論されたすべてを実際に示しています。