大規模な C++ プロジェクトで不要な #include ファイルを検出するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/74326

質問

Visual Studio 2008 で大規模な C++ プロジェクトに取り組んでいますが、不要なファイルがたくさんあります。 #include 指令。時々、 #includeは単なるアーティファクトであり、それらを削除してもすべてが正常にコンパイルされます。また、他の場合には、クラスを前方宣言して #include を .cpp ファイル。これら両方のケースを検出するための優れたツールはありますか?

役に立ちましたか?

解決

不要なインクルード ファイルは表示されませんが、Visual Studio には設定があります。 /showIncludes (右クリックすると .cpp ファイル、 Properties->C/C++->Advanced) コンパイル時にインクルードされたすべてのファイルのツリーを出力します。これは、含める必要のないファイルを識別するのに役立ちます。

また、pimpl イディオムを参照して、ヘッダー ファイルの依存関係を減らして、削除できる問題を簡単に確認できるようにすることもできます。

他のヒント

PC 糸くず これには非常にうまく機能し、他のあらゆる種類の愚かな問題も見つけてくれます。Visual Studio で外部ツールを作成するために使用できるコマンド ライン オプションがありますが、 視覚的な糸くず アドインの方が扱いやすいです。Visual Lint の無料版でも役に立ちます。しかし、PC-Lint を試してみてください。警告が多すぎないように設定するには少し時間がかかりますが、その結果には驚かれるでしょう。

新しい Clang ベースのツールがあります。 使用したものを含める, 、これを目的としています。

!!免責事項!!私は商用の静的解析ツール (PC Lint ではありません) に取り組んでいます。!!免責事項!!

単純な非解析アプローチにはいくつかの問題があります。

1) オーバーロード セット:

オーバーロードされた関数に別のファイルからの宣言が含まれている可能性があります。1 つのヘッダー ファイルを削除すると、コンパイル エラーではなく、別のオーバーロードが選択される可能性があります。その結果、セマンティクスにサイレントな変更が生じ、後で追跡するのが非常に困難になる可能性があります。

2) テンプレートの特殊化:

オーバーロードの例と同様に、テンプレートに部分的または明示的な特殊化がある場合、テンプレートの使用時にそれらをすべて表示する必要があります。プライマリ テンプレートの特殊化が別のヘッダー ファイルにある可能性があります。特殊化を使用してヘッダーを削除してもコンパイル エラーは発生しませんが、その特殊化が選択されている場合は未定義の動作が発生する可能性があります。(見る: C++ 関数のテンプレート特殊化の可視性)

「msalters」によって指摘されているように、コードの完全な分析を実行すると、クラスの使用状況を分析することもできます。ファイルの特定のパスを通じてクラスがどのように使用されているかをチェックすることにより、クラスの定義 (したがってそのすべての依存関係) を完全に削除するか、少なくともインクルード内のメイン ソースに近いレベルに移動できる可能性があります。木。

私はそのようなツールを知りませんし、過去にツールを作成しようと考えたこともありましたが、これは解決するのが難しい問題であることがわかりました。

ソース ファイルに a.h と b.h が含まれているとします。a.hには含まれています #define USE_FEATURE_X そしてb.hは使用します #ifdef USE_FEATURE_X. 。もし #include "a.h" がコメントアウトされている場合でも、ファイルはコンパイルできますが、期待どおりに動作しない可能性があります。これを検出する プログラム的に は自明ではありません。

どのようなツールでこれを実行する場合でも、ビルド環境についても把握する必要があります。a.h が次のようになった場合:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

それから USE_FEATURE_X は次の場合にのみ定義されます WINNT が定義されているため、ツールはコンパイラ自体によってどのディレクティブが生成されるか、またどのディレクティブがヘッダー ファイルではなくコンパイル コマンドで指定されているかを知る必要があります。

Timmermans と同様に、私もこのためのツールに慣れていません。しかし、私が知っているプログラマーは、Perl (または Python) スクリプトを作成して、各インクルード行を一度に 1 つずつコメントアウトしてから、各ファイルをコンパイルしようとしました。


今はエリック・レイモンドのようだ このためのツールがあります.

Googleの cpplint.py (他の多くのルールの中でも特に)「使用するものを含める」ルールがありますが、私の知る限り、「含める」ルールはありません のみ 使っているもの。」 それでも、役に立つことはあります。

このトピック全般に興味がある場合は、Lakos の記事をチェックしてください。 大規模な C++ ソフトウェア設計. 。少し古いですが、含める必要がある絶対最小限のヘッダーを見つけるなど、多くの「物理設計」の問題について説明しています。この種のことが議論されているのを他では見たことがありません。

与える マネージャーを含める 試してみてください。Visual Studio に簡単に統合でき、インクルード パスが視覚化されるので、不要なものを見つけるのに役立ちます。内部的には Graphviz を使用していますが、他にも多くの優れた機能があります。そして、業務用商品でありながら、価格も非常に安いのが特徴です。

次を使用してインクルード グラフを構築できます。 C/C++ インクルードファイル依存関係ウォッチャー, 、不要なインクルードを視覚的に見つけます。

ヘッダー ファイルが通常次で始まる場合は、

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif

(#pragma Once を使用するのとは対照的に) これを次のように変更できます。

#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else 
#pragma message("Someheader.h superfluously included")
#endif

また、コンパイラはコンパイル中の cpp ファイルの名前を出力するため、少なくともどの cpp ファイルがヘッダーを複数回取り込む原因になっているかを知ることができます。

PC-Lint は実際にこれを実行できます。これを行う簡単な方法の 1 つは、未使用のインクルード ファイルのみを検出し、その他の問題をすべて無視するように設定することです。これは非常に簡単です。メッセージ 766 (「モジュールでヘッダー ファイルが使用されていません」) だけを有効にするには、コマンド ラインにオプション -w0 +e766 を含めるだけです。

同じアプローチは、964 (「モジュールで直接使用されていないヘッダー ファイル」) や 966 (「モジュールで使用されていない間接的に含まれたヘッダー ファイル」) などの関連メッセージにも使用できます。

FWIW これについては、先週のブログ投稿で詳しく書きました。 http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318.

不要なものを削除したい場合 #include ビルド時間を短縮するために、ファイルを使用してビルド プロセスを並列化することに時間と費用を費やしたほうが良いかもしれません。 cl.exe /MP, make -j, Xoreax IncrediBuild, 、distcc/アイスクリーム, 、など。

もちろん、すでに並列ビルド プロセスがあり、それをさらに高速化しようとしている場合は、ぜひ、ビルド プロセスをクリーンアップしてください。 #include ディレクティブを削除し、不要な依存関係を削除します。

各インクルード ファイルから始めて、各インクルード ファイル自体のコンパイルに必要なものだけが含まれていることを確認します。C++ ファイルに欠落しているインクルード ファイルは、C++ ファイル自体に追加できます。

各インクルード ファイルとソース ファイルについて、各インクルード ファイルを一度に 1 つずつコメント アウトし、コンパイルされるかどうかを確認します。

インクルード ファイルをアルファベット順に並べ替えることもお勧めします。これが不可能な場合は、コメントを追加します。

次の#definesの1つまたは両方を追加すると、しばしば不要なヘッダーファイルが除外され、特にWindows API関数を使用していないコードの場合、コンパイル時間を大幅に改善する場合があります。

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

見る http://support.microsoft.com/kb/166474

まだ行っていない場合は、プリコンパイル済みヘッダーを使用して、変更しないすべてのもの (プラットフォーム ヘッダー、外部 SDK ヘッダー、またはプロジェクトの既に完了した静的な部分) を含めると、ビルド時間に大きな違いが生じます。

http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx

また、プロジェクトには遅すぎるかもしれませんが、プロジェクトをセクションに編成し、すべてのローカル ヘッダーを 1 つの大きなメイン ヘッダーにまとめないようにすることは、少し追加の作業が必要になりますが、良い習慣です。

Eclipse CDT を使用する場合は、試してみてください http://includator.com インクルード構造を最適化します。ただし、Includator は VC++ の事前定義されたインクルードについて十分に理解していない可能性があり、正しいインクルードで VC++ を使用するための CDT のセットアップはまだ CDT に組み込まれていません。

最新の Jetbrains IDE、CLion は、現在のファイルで使用されていないインクルードを自動的に (灰色で) 表示します。

IDE からすべての未使用のインクルード (および関数、メソッドなど) のリストを取得することもできます。

既存の回答の中には、それは難しいと述べているものもあります。それは確かに真実です。前方宣言が適切なケースを検出するには完全なコンパイラが必要だからです。シンボルの意味を知らなければ C++ を解析することはできません。そのためには文法が曖昧すぎます。特定の名前がクラス (前方宣言できる) を表すのか、それとも変数 (前方宣言できない) を表すのかを知る必要があります。また、名前空間を意識する必要もあります。

少し遅れたかもしれませんが、私はかつて、あなたが望んでいたとおりのことを行う WebKit Perl スクリプトを見つけました。多少の調整が必要だと思いますが (私は Perl に詳しくありません)、うまくいくはずです。

http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes

(トランクにはもうファイルがないため、これは古いブランチです)

もう必要ないと思われる特定のヘッダーがある場合(String.hなど)、これを含めてコメントアウトできます。

#ifdef _STRING_H_
#  error string.h is included indirectly
#endif

もちろん、インターフェイスヘッダーは、CPPメモリへの包含を記録するために、異なる#defineコンベンションを使用する場合があります。または慣習はありません。その場合、このアプローチは機能しません。

その後、再構築します。次の 3 つの可能性があります。

  • それは大丈夫です。string.hはCompile-criticalではなく、そのための含有は削除できます。

  • #error がトリップします。string.gは間接的に含まれていました。string.hが必要かどうかはまだわかりません。必要がある場合は、直接#includeをする必要があります(以下を参照)。

  • 他のコンパイル エラーが発生します。string.hが必要であり、間接的に含まれていないため、含まれるのは正しいものでした。

.hまたは.cが別の.hを直接使用する場合、間接的な包含に応じて、ほぼ確実にバグであることに注意してください。あなたは、あなたが使用している他のヘッダーがそれを必要とする限り、あなたのコードがそのヘッダーのみを要求することを要求することを実際に約束しています。

ビルドの障害を引き起こすものを宣言する動作を変更するヘッダーについての他の回答で言及されている警告もここにも適用されます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top