非常に遅いコンパイル時間 (Linux/Unix) の原因となっている「ヘッダー スパゲッティ」をクリーンアップするための推奨される方法はありますか?
GCCで「#pragma once」に相当するものはありますか?
(これに関して矛盾するメッセージが見つかりました)
ありがとう。
非常に遅いコンパイル時間 (Linux/Unix) の原因となっている「ヘッダー スパゲッティ」をクリーンアップするための推奨される方法はありますか?
GCCで「#pragma once」に相当するものはありますか?
(これに関して矛盾するメッセージが見つかりました)
ありがとう。
「インクルード ガード」 (ヘッダーの先頭にある #ifdef ..) に慣れていると仮定すると、ビルド時間を短縮するもう 1 つの方法は、外部インクルード ガードを使用することです。「大規模な C++ ソフトウェア設計」で説明されています。#pragma once とは異なり、従来のインクルード ガードは、2 回目以降はヘッダーを無視するために必要なプリプロセッサの解析を惜しみません (つまり、インクルード ガードの開始と終了を解析して探す必要があります。 #ifdef を #include 行自体の周りに配置する外部インクルード ガード。
したがって、次のようになります。
#ifndef MY_HEADER
#include "myheader.h"
#endif
そしてもちろん、Hファイル内には古典的なインクルードガードがあります
#ifndef MY_HEADER
#define MY_HEADER
// content of header
#endif
このように、myheader.h ファイルはプリプロセッサによって開かれたり解析されたりすることはなく、特にヘッダー ファイルが共有されたリモートの場所に置かれている場合など、大規模なプロジェクトで多くの時間を節約できます。
繰り返しますが、それはすべてその本にあります。h番目
完全なクリーンアップを実行して実行する時間が必要な場合は、すべてのファイル(abc.cppのabc.hなどの明らかなファイルを除く)のすべての#includeを削除してから、プロジェクトをコンパイルするのが最善の解決策です。最初のエラーを修正するために必要な前方宣言またはヘッダーを追加してから、完全に完了するまで繰り返します。
これは、インクルードの問題を引き起こす可能性のある根本的な問題を修正しませんが、インクルードのみが必要なものであることを保証します。
私は、GCC が#pragma once
非推奨と見なしていることを読みまし#pragma once
たが、速度を上げるためにできることは限られています。
スパゲッティのもつれを解くには、doxygen#include
を調べることができます。含まれているヘッダーのグラフを生成できるはずです。これにより、物事を単純化する上で優位に立つことができます。詳細を思い出すことはできませんが、グラフ機能を使用するには、GraphVizをインストールして、GraphViz の dotty.exe を見つけることができるパスを doxygen に伝える必要がある場合があります。
コンパイル時間が主な関心事である場合に検討できるもう 1 つのアプローチは、Precompiled Headersの設定です。
先日、ヘッダーの依存関係を減らすための巧妙なトリックについて読みました: Write a script that will
最後に、コードに最低限必要なインクルードが含まれていることを願っています。インクルードを再配置して、それらが自己完結型であるかどうかを調べる、またはそれらの前に他のヘッダーをインクルードする必要がある同様のスクリプトを作成できます (最初にヘッダーをインクルードし、コンパイルが失敗したかどうかを確認し、それを報告します)。これは、コードをクリーンアップするのにある程度役立つはずです。
その他の注意事項:
リチャードはある程度正しかった (なぜ彼の解決策が書き留められたのか?)。
とにかく、すべての C/C++ ヘッダーは内部インクルード ガードを使用する必要があります。
これは、次のいずれかです。
1 - あなたのレガシーコードはもはや実際には維持されておらず、プリコンパイルされたヘッダーを使用する必要があります (これはハックですが、... 必要なのはコンパイルを高速化することであり、維持されていないコードをリファクタリングすることではありません)。
2 - レガシ コードはまだ生きています。次に、一時的な解決策としてプリコンパイル済みヘッダーおよび/またはガード/外部ガードを使用しますが、最終的には、一度に .C または .CPP を 1 つずつすべてのインクルードを削除し、それぞれをコンパイルする必要があります。 C または .CPP ファイルを一度に 1 つずつ、前方宣言または必要に応じてインクルードを使用してそれらのインクルードを修正します (または、各 .C または .CPP ファイルが必要なヘッダーのみを確実に取得するように、大きなインクルードを小さなインクルードに分割することもできます)。とにかく、廃止されたインクルードのテストと削除はプロジェクトのメンテナンスの一部なので...
プリコンパイル済みヘッダーに関する私自身の経験は、正確には良いものではありませんでした.半分の時間、コンパイラーは私が定義したシンボルを見つけることができなかったので、プリコンパイル済みヘッダーではないことを確認するために完全な「クリーン/リビルド」を試みました.それは時代遅れでした。だから私の推測では、触れることさえない外部ライブラリ(STL、C APIヘッダー、Boostなど)に使用することです。それでも、私自身の経験では Visual C++ 6 を使用していたので、彼らはそれを正しく理解していると思います (希望はありますか?)。
最後に、ヘッダーは常に自己完結型であるべきです。つまり、ヘッダーのインクルードがインクルードの順序に依存する場合、問題があることを意味します。たとえば、次のように記述できる場合:
#include "AAA.hpp"
#include "BBB.hpp"
だがしかし:
#include "BBB.hpp"
#include "AAA.hpp"
BBB は AAA に依存しているため、コード内で確認したことのない依存関係しかありません。定義でそれを認めないことは、コンパイルを悪夢にするだけです。BBB にも AAA を含める必要があります (多少遅くなる可能性がありますが、最終的には、前方宣言は役に立たないインクルードをクリーンアップするため、コンパイル タイマーを高速化する必要があります)。
ビルド時間を短縮するためにそれらの1つ以上を使用してください
PC-Lintは、スパゲッティヘッダーのクリーンアップに大いに役立ちます。また、初期化されていない変数が見えなくなるなど、他の問題も解決します。
onebyone.livejournal.com があなたの質問への回答でコメントしたように、一部のコンパイラ サポートは include guard Optimizationをサポートしています。これは、リンクしたページで次のように定義されています。
インクルード ガードの最適化は、コンパイラが上記の内部インクルード ガード イディオムを認識し、ファイルを複数回開くことを回避するための手順を実行する場合です。コンパイラは、インクルード ファイルを調べて、コメントと空白を取り除き、ファイル全体がインクルード ガード内にあるかどうかを調べることができます。そうであれば、ファイル名を保存し、ガード条件をマップに含めます。次にファイルをインクルードするようコンパイラーに要求されたときに、コンパイラーはインクルード・ガード条件をチェックして、ファイルをスキップするか、ファイルを開かずに #include するかを決定できます。
繰り返しになりますが、外部インクルードガードは質問に対する答えではないとすでに答えています。特定の順序で含める必要があるヘッダー ファイルのもつれを解くには、次のことをお勧めします。
.c
または.cpp
ファイルは最初に#include
対応する.h
ファイルで、残りの#include
ディレクティブはアルファベット順にソートする必要があります。通常、ヘッダー ファイル間の明示されていない依存関係が壊れると、ビルド エラーが発生します。#define
ほとんどのコードで使用される基本型またはグローバル ディレクティブのグローバル typedef を定義するヘッダー ファイルがある場合、各.h
ファイルは#include
そのファイルを最初に作成し、残りの#include
ディレクティブはアルファベット順に並べ替える必要があります。#include
.また、問題の一部は、インクリメンタル ビルドが本来よりもはるかに遅いことでもあるようです。他の人が指摘しているように、この状況は前方宣言または分散ビルドシステムで改善できます。
他の回答で述べたように、可能な限り前方宣言を使用する必要があります。私の知る限り、GCC には #pragma once に相当するものはありません。
返信ありがとうございます。質問は、厳密な「インクルード順序」などを含む既存のコードに関するものです。質問は、実際に何が起こっているのかを明確にするためのツール/スクリプトがあるかどうかです。
ヘッダーガードは、コンパイラがファイル全体を何度も読み取るのを妨げないため、解決策ではありません...
ヘッダー内: 前方宣言を使用できない場合にのみヘッダーをインクルードしますが、必要なファイルは常に #include します (インクルードの依存関係は悪です!)。