4

非常に遅いコンパイル時間 (Linux/Unix) の原因となっている「ヘッダー スパゲッティ」をクリーンアップするための推奨される方法はありますか?

GCCで「#pragma once」に相当するものはありますか?
(これに関して矛盾するメッセージが見つかりました)

ありがとう。

4

11 に答える 11

8

「インクルード ガード」 (ヘッダーの先頭にある #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番目

于 2008-09-21T09:15:27.483 に答える
6

完全なクリーンアップを実行して実行する時間が必要な場合は、すべてのファイル(abc.cppのabc.hなどの明らかなファイルを除く)のすべての#includeを削除してから、プロジェクトをコンパイルするのが最善の解決策です。最初のエラーを修正するために必要な前方宣言またはヘッダーを追加してから、完全に完了するまで繰り返します。

これは、インクルードの問題を引き起こす可能性のある根本的な問題を修正しませんが、インクルードのみが必要なものであることを保証します。

于 2008-09-21T10:00:56.547 に答える
4

私は、GCC が#pragma once非推奨と見なしていることを読みまし#pragma onceたが、速度を上げるためにできることは限られています。

スパゲッティのもつれを解くには、doxygen#includeを調べることができます。含まれているヘッダーのグラフを生成できるはずです。これにより、物事を単純化する上で優位に立つことができます。詳細を思い出すことはできませんが、グラフ機能を使用するには、GraphVizをインストールして、GraphViz の dotty.exe を見つけることができるパスを dox​​ygen に伝える必要がある場合があります。

コンパイル時間が主な関心事である場合に検討できるもう 1 つのアプローチは、Precompiled Headersの設定です。

于 2008-09-21T07:39:47.353 に答える
3

先日、ヘッダーの依存関係を減らすための巧妙なトリックについて読みました: Write a script that will

  • すべての #include ステートメントを見つける
  • 一度に 1 つのステートメントを削除して再コンパイルする
  • コンパイルが失敗した場合は、include ステートメントを再度追加します

最後に、コードに最低限必要なインクルードが含まれていることを願っています。インクルードを再配置して、それらが自己完結型であるかどうかを調べる、またはそれらの前に他のヘッダーをインクルードする必要がある同様のスクリプトを作成できます (最初にヘッダーをインクルードし、コンパイルが失敗したかどうかを確認し、それを報告します)。これは、コードをクリーンアップするのにある程度役立つはずです。

その他の注意事項:

  • 最新のコンパイラ (特に gcc) はヘッダー ガードを認識し、pragma once と同じ方法で最適化し、ファイルを 1 回だけ開きます。
  • pragma once は、ファイルシステム内で同じファイルが異なる名前を持つ場合 (つまり、ソフトリンクを使用する場合) に問題が発生する可能性があります。

  • gcc は #pragma once をサポートしていますが、「廃止」と呼んでいます
  • pragma once はすべてのコンパイラでサポートされているわけではなく、C 標準の一部でもありません

  • 問題になる可能性があるのはコンパイラだけではありません。Incredibuild などのツールにも #pragma once に関する問題があります
于 2008-10-22T15:07:58.363 に答える
3

リチャードはある程度正しかった (なぜ彼の解決策が書き留められたのか?)。

とにかく、すべての 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 を含める必要があります (多少遅くなる可能性がありますが、最終的には、前方宣言は役に立たないインクルードをクリーンアップするため、コンパイル タイマーを高速化する必要があります)。

于 2008-09-21T10:32:20.963 に答える
2

ビルド時間を短縮するためにそれらの1つ以上を使用してください

  1. プリコンパイル済みヘッダーを使用する
  2. キャッシングメカニズムを使用する(たとえば、scons)
  3. 分散ビルドシステムを使用する(distcc、Incredibuild($))
于 2008-09-21T07:53:12.920 に答える
0

PC-Lintは、スパゲッティヘッダーのクリーンアップに大いに役立ちます。また、初期化されていない変数が見えなくなるなど、他の問題も解決します。

于 2008-09-21T10:04:48.003 に答える
0

onebyone.livejournal.com があなたの質問への回答でコメントしたように、一部のコンパイラ サポートは include guard Optimizationをサポートしています。これは、リンクしたページで次のように定義されています。

インクルード ガードの最適化は、コンパイラが上記の内部インクルード ガード イディオムを認識し、ファイルを複数回開くことを回避するための手順を実行する場合です。コンパイラは、インクルード ファイルを調べて、コメントと空白を取り除き、ファイル全体がインクルード ガード内にあるかどうかを調べることができます。そうであれば、ファイル名を保存し、ガード条件をマップに含めます。次にファイルをインクルードするようコンパイラーに要求されたときに、コンパイラーはインクルード・ガード条件をチェックして、ファイルをスキップするか、ファイルを開かずに #include するかを決定できます。

繰り返しになりますが、外部インクルードガードは質問に対する答えではないとすでに答えています。特定の順序で含める必要があるヘッダー ファイルのもつれを解くには、次のことをお勧めします。

  • .cまたは.cppファイルは最初に#include対応する.hファイルで、残りの#includeディレクティブはアルファベット順にソートする必要があります。通常、ヘッダー ファイル間の明示されていない依存関係が壊れると、ビルド エラーが発生します。
  • #defineほとんどのコードで使用される基本型またはグローバル ディレクティブのグローバル typedef を定義するヘッダー ファイルがある場合、各.hファイルは#includeそのファイルを最初に作成し、残りの#includeディレクティブはアルファベット順に並べ替える必要があります。
  • これらの変更によってコンパイル エラーが発生した場合、通常、あるヘッダー ファイルから別のヘッダー ファイルへの明示的な依存関係を#include.
  • これらの変更によってコンパイル エラーが発生しない場合でも、動作が変化する可能性があります。アプリケーションの機能を検証するために使用できる何らかのテスト スイートがあることを願っています。

また、問題の一部は、インクリメンタル ビルドが本来よりもはるかに遅いことでもあるようです。他の人が指摘しているように、この状況は前方宣言または分散ビルドシステムで改善できます。

于 2008-09-21T15:48:06.603 に答える
0

他の回答で述べたように、可能な限り前方宣言を使用する必要があります。私の知る限り、GCC には #pragma once に相当するものはありません。

于 2008-09-21T07:17:24.130 に答える
0

返信ありがとうございます。質問は、厳密な「インクルード順序」などを含む既存のコードに関するものです。質問は、実際に何が起こっているのかを明確にするためのツール/スクリプトがあるかどうかです。

ヘッダーガードは、コンパイラがファイル全体を何度も読み取るのを妨げないため、解決策ではありません...

于 2008-09-21T07:25:58.167 に答える
0

ヘッダー内: 前方宣言を使用できない場合にのみヘッダーをインクルードしますが、必要なファイルは常に #include します (インクルードの依存関係は悪です!)。

于 2008-09-21T07:07:50.177 に答える