web-dev-qa-db-ja.com

g ++のコンパイル時間を短縮する方法(多くのテンプレートを使用する場合)

この質問はおそらくどういうわけか奇妙ですが、どのようにしてg ++のコンパイル時間を短縮できますか?私のC++コードは、ブーストとテンプレートを多用しています。ヘッダーファイルから可能な限り移動し、-jオプションを使用していますが、コンパイル(およびリンク)にはかなり時間がかかります。

コードを分析し、コンパイラのボトルネックを指摘するツールはありますか?または、コードで実行されているコンパイラを何らかの形でプロファイルできますか?コンパイラーコンソールのログをじっと見つめすぎているという印象を受けることがあるので、これは本当にいいことです。

62
Danvil

私にとって最も便利だったもの:

  • RAMファイルシステムでビルドします。これはLinuxではささいなことです。RAMファイルシステムも同様です。
  • プリコンパイル済みヘッダー 。 (メジャー)ライブラリごとに1つ(例:Boost、Qt、stdlib)があります。
  • 可能な場合、インクルードクラスの代わりに宣言します。これにより依存関係が減り、ヘッダーファイルを変更するときに再コンパイルする必要があるファイルの数が減ります。
  • makeの並列化 。これは通常、ケースバイケースで役立ちますが、-j3 makeのグローバル。ただし、Makefileで依存関係グラフが正しいことを確認してください。正しくない場合、問題が発生する可能性があります。
  • 使用する -O0実行速度やコードサイズをテストしていない場合(そして、コンピューターが(おそらく小さな)パフォーマンスヒットをあまり気にしないほど高速です)。
  • 保存するたびにコンパイルします。これを好まない人もいますが、エラーを早期に確認でき、バックグラウンドで実行できるため、書き込みが完了してテストの準備が整ったときに待機する時間が短縮されます。
49
strager

ファイルをコンパイルするためにminutesについて話していると仮定します。つまり、プリコンパイル済みヘッダーまたはローカルディスクの問題は問題ではありません。

深いテンプレートコード(ブーストなど)での長いコンパイル時間は、テンプレートのインスタンス化に関しては、特に可変長テンプレートがテンプレートのデフォルト引数でエミュレートされる場合、gccの非友好的な漸近的な動作に根ざしています。

可変長テンプレートの動機として、コンパイル時間の短縮を挙げたドキュメントを次に示します。

cpptruthsには、gcc-4.5がこのためにどのように優れているか、および可変引数テンプレートでどのように見事に機能するかについての記事がありました。

IIRCの場合、BOOSTには擬似変数のテンプレートのデフォルトパラメータの生成を制限する方法があります。「g ++ -DBOOST_MPL_LIMIT_LIST_SIZE = 10」は機能するはずです(デフォルトは20)

UPDATE:ここでSO

UPDATE:これはテンプレートをコンパイルするときのパフォーマンスの問題に関するもので、受け入れられた答えはgcc-4.5も推奨しています。また、clangは肯定的な例として言及されています:

17

あなたが説明する非常によく似たシナリオ(ブースト、テンプレート、gcc)でビルドを高速化するために私がやったこと

  • nFSのようなネットワークファイルシステムの代わりにローカルディスク上に構築する
  • gccの新しいバージョンへのアップグレード
  • 調査 distcc
  • より高速なビルドシステム、特により多くのRAM
17
Sam Miller

多くの再コンパイルを行っている場合、 ccache が役立つ場合があります。実際にはコンパイルの速度は上がりませんが、何らかの理由で無駄な再コンパイルを行うと、キャッシュされた結果が得られます。間違った問題に取り組んでいる印象を与えるかもしれませんが、再構築ルールが非常に複雑であるため、実際には新しいビルド中に同じコンパイル手順を実行することになります。

追加のアイデア:コードが clang でコンパイルされる場合は、代わりに使用します。通常、gccよりも高速です。

10
viraptor

他の誰もが追加したことやすでに行っていること(並列化ビルド、コンパイラオプションなど)に加えて、インターフェイスを介してアクセスされる実装クラスのテンプレートを非表示にすることを検討してください。つまり、次のようなクラスを持つ代わりに:

// ClsWithNoTemplates.h file, included everywhere

class ClsWithTemplates
{
    ComplicatedTemplate<abc> member;
    // ...

public:
    void FunctionUsingYourMember();
};

あなたが持っている必要があります:

// ClsWithNoTemplates.h file:

class ClsWithTemplatesImplementation; // forward declaration
  // definition included in the ClsWithNoTemplates.cpp file
  // this class will have a ComplicatedTemplate<abc> member, but it is only 
  // included in your ClsWithNoTemplates definition file (that is only included once)


class ClsWithNoTemplates
{
     ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
    void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};

これはOOPデザインを少し変更しますが、それは良いことです: 'ClsWithNoTemplates'の定義を含めるとfastになり、 「ClsWithNoTemplates」を1回。

さらに、実装コードを変更した場合、ClsWithNoTemplates.hを含むコードを再定義する必要はおそらくないでしょう。

この変更により、部分的なコンパイル時間が劇的に長くなります。また、ClsWithNoTemplatesがライブラリファイルからエクスポートされたパブリックインターフェイスの場合にも役立ちます。実装を変更するだけではファイルは変更されないため、依存クライアントコードはまったく再コンパイルする必要があります。

3
utnapistim

PIMPLテクニックを試してください。この質問: C++のコンパイル時間を短縮するために使用できるテクニックは何ですか?

コンパイラは、何かをする必要があるたびに、ヘッダーファイルと実装のチェーンをたどることを防ぎます。

3
gtrak

多くのファイルがある場合、他のすべての.cppファイルを#includeする1つの.cppファイルを用意するだけで、コンパイルを大幅に高速化できます。もちろん、これにはマクロをより注意する必要があり、他のcppファイルから見えるようにファイルごとにすでに定義されている必要があります。

多くのファイルがある場合、これによりコンパイル時間が大幅に短縮されます。

2
Zitrax

より少ないテンプレートとインライン関数をインスタンス化します。すべてをゼロからコンパイルするのではなく、できる限りプリコンパイルし、リンクするだけです。 GCCの最新バージョンを使用していることを確認してください。

ただし、C++が非常に複雑な言語であり、コンパイルにはかなりの時間がかかるというのは簡単な事実です。

1
Puppy

このペーパー は、「従来の」非テンプレートオブジェクトファイルによく似たテンプレートコードのコンパイル方法を説明しています。テンプレートのインスタンス化ごとに1行のコードオーバーヘッドで、コンパイルとリンクの時間を節約します。

1
Chris Tonkinson

複数のコアを使用してg ++でコンパイルする

複数のコアを使用してg ++でコンパイルする

0
karlphillip

通常、コンパイルの最も費用のかかる部分は、(a)ソースファイルの読み取り([〜#〜] all [〜#〜])および(b)コンパイラを各ソースのメモリにロードすることです。ファイル。

52個のソース(.cc)ファイルがあり、それぞれが#includes 47個の#include(.h)ファイルを持っている場合、コンパイラーを52回ロードし、2496個のファイルを処理します。ファイル内のコメントの密度によっては、役に立たない文字を食べるのにかなりの時間を費やしている可能性があります。 (私が見たある組織では、ヘッダーファイルのコメントは66%から90%の間で変化し、ファイルの10%から33%のみが「意味のある」ものでした。最後のコメントをすべて削除し、コードのみを残します。)

プログラムがどのように物理的に編成されているかを詳しく見てください。ソースファイルを結合できるかどうかを確認し、#includeファイルの階層を単純化します。

何十年も前、IBMのような企業はこれを理解し、コンパイラーを作成して、1つのファイルだけでなく、コンパイルするファイルのリストをコンパイラーに渡し、コンパイラーを1回だけロードするようにしました。

0
John R. Strohm