回答:
不要なインクルードファイルは表示されませんが、Visual Studioには、コンパイル時にすべてのインクルードファイルのツリーを出力する設定/showIncludes
(.cpp
ファイルを右クリック)がありますProperties->C/C++->Advanced
。これは、含める必要のないファイルを識別するのに役立ちます。
また、pimplイディオムを確認して、ヘッダーファイルの依存関係を減らし、削除できる残骸が見やすくなるようにすることもできます。
PC Lintはこれに対して非常にうまく機能し、他のあらゆる種類の間抜けな問題も検出します。これには、Visual Studioで外部ツールを作成するために使用できるコマンドラインオプションがありますが、Visual Lintアドインの方が扱いやすいことがわかりました。Visual Lintの無料バージョンでも役立ちます。PC-Lintを試してみてください。警告が出すぎないように設定するには少し時間がかかりますが、何が表示されるかは驚くことでしょう。
これを目的とした新しいClangベースのツールinclude-what-you-useがあります。
!!免責事項!! 商用の静的分析ツール(PC Lintではない)を使用しています。!!免責事項!!
単純な非解析アプローチにはいくつかの問題があります。
1)オーバーロードセット:
オーバーロードされた関数に異なるファイルからの宣言がある可能性があります。1つのヘッダーファイルを削除すると、コンパイルエラーではなく、異なるオーバーロードが選択される可能性があります。その結果、セマンティクスが静かに変化し、後で追跡するのが非常に困難になる可能性があります。
2)テンプレートの専門分野:
オーバーロードの例と同様に、テンプレートの部分的または明示的な特殊化がある場合、テンプレートが使用されたときにそれらすべてが表示されるようにします。プライマリテンプレートの特殊化が異なるヘッダーファイルにある可能性があります。特殊化を使用してヘッダーを削除してもコンパイルエラーは発生しませんが、その特殊化が選択されていると、未定義の動作が発生する可能性があります。(参照:C ++関数のテンプレート特殊化の可視性)
「msalters」で指摘されているように、コードの完全な分析を実行すると、クラスの使用状況の分析も可能になります。クラスがファイルの特定のパスを介してどのように使用されるかをチェックすることにより、クラスの定義(したがって、そのすべての依存関係)を完全に削除するか、少なくともインクルードのメインソースに近いレベルに移動できる可能性があります木。
私はそのようなツールを知りません、そして私は過去にそれを書くことを考えました、しかし、これは解決するのが難しい問題であることがわかりました。
ソースファイルにahとbhが含まれているとします。ahはを含み#define USE_FEATURE_X
、bhはを使用し#ifdef USE_FEATURE_X
ます。場合は#include "a.h"
コメントアウトされ、あなたのファイルがまだコンパイルかもしれないが、何を期待しないことがあります。これをプログラムで検出することは簡単ではありません。
どんなツールでもこれはあなたのビルド環境を知る必要があります。次のような場合:
#if defined( WINNT )
#define USE_FEATURE_X
#endif
次に、USE_FEATURE_X
が定義されている場合にのみ定義さWINNT
れます。したがって、ツールは、コンパイラー自体によって生成されるディレクティブと、ヘッダーファイルではなくコンパイルコマンドで指定されるディレクティブを認識する必要があります。
Timmermansのように、私はこのためのツールに精通していません。しかし、Perl(またはPython)スクリプトを作成して、各インクルード行を1つずつコメント化してから、各ファイルをコンパイルするプログラマーを知っています。
エリック・レイモンドがこのためのツールを持っているようです。
Googleのcpplint.pyには、「使用したものを含める」というルールがありますが、私が知る限り、「使用したものだけを含める」というルールはありません。そうであっても、それは便利です。
このトピック全般に興味がある場合は、LakosのLarge Scale C ++ Software Designをチェックしてください。それは少し古いですが、含まれる必要があるヘッダーの絶対最小値を見つけるなど、多くの「物理設計」の問題に入ります。この種のことについて他で議論されたことはありません。
C / C ++インクルードファイルの依存関係ウォッチャーを使用してインクルードグラフを作成し、不要なインクルードを視覚的に見つけることができます。
ヘッダーファイルが一般的に
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#endif
(#pragmaを1回使用するのではなく)次のように変更できます。
#ifndef __SOMEHEADER_H__
#define __SOMEHEADER_H__
// header contents
#else
#pragma message("Someheader.h superfluously included")
#endif
また、コンパイラーはコンパイル中のcppファイルの名前を出力するため、少なくともどのcppファイルがヘッダーを何度も呼び出しているかを知ることができます。
A.h
とB.h
の両方がに依存していることC.h
と、あなたは、A.h
とB.h
あなたは両方を必要とするので、あなたは、なりますが含まC.h
回が、コンパイラはそれを二時間をスキップしますので、それは、罰金だとあなたはしなかった場合、あなたは覚えておく必要があるだろう常にC.h
前に含めるA.h
かB.h
、はるかに役に立たない包含に終わります。
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 / icecreamなどを使用して、ビルドプロセスの並列化に時間とお金をかける方がよいでしょう。
もちろん、すでに並列ビルドプロセスがあり、それを高速化しようとしている場合は、必ず#include
ディレクティブをクリーンアップして、不要な依存関係を削除してください。
各インクルードファイルから始めて、各インクルードファイルに、それ自体のコンパイルに必要なものだけが含まれていることを確認します。C ++ファイルで欠落しているインクルードファイルは、C ++ファイル自体に追加できます。
各インクルードファイルとソースファイルについて、各インクルードファイルを1つずつコメントアウトし、コンパイルされるかどうかを確認します。
また、インクルードファイルをアルファベット順にソートすることをお勧めします。これが不可能な場合は、コメントを追加してください。
次の#defineの一方または両方を追加すると、不要なヘッダーファイルが除外され、特にWindows API関数を使用していないコードの場合、コンパイル時間が大幅に改善される可能性があります。
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
まだ行っていない場合は、プリコンパイル済みヘッダーを使用して、変更しないものすべて(プラットフォームヘッダー、外部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に精通していません)が、うまくいくはずです。
(トランクにはもうファイルがないため、これは古いブランチです)
もう必要ないと思われる特定のヘッダー(string.hなど)がある場合は、そのインクルードをコメント化して、すべてのインクルードの下に配置できます。
#ifdef _STRING_H_
# error string.h is included indirectly
#endif
もちろん、インターフェイスヘッダーが別の#define規則を使用して、CPPメモリへの組み込みを記録する場合があります。または、規約がない場合、このアプローチは機能しません。
その後、再構築します。3つの可能性があります。
それは大丈夫です。string.hはコンパイルに不可欠ではなく、そのインクルードは削除できます。
#エラーがトリップします。string.gは間接的に何らかの方法で含まれています。string.hが必要かどうかはまだわかりません。必要な場合は、直接#includeする必要があります(以下を参照)。
その他のコンパイルエラーが発生します。string.hが必要であり、間接的にインクルードされていないため、インクルードは最初は正しいものでした。
.hまたは.cが別の.hを直接使用する場合の間接的なインクルードによっては、ほぼ間違いなくバグであることに注意してください。使用している他のヘッダーが必要とする限り、コードはそのヘッダーのみを必要とすることを実際に約束しています。これはおそらくあなたが意図したものではありません。
ビルドの失敗の原因となるものを宣言するのではなく、動作を変更するヘッダーに関する他の回答で言及されている警告がここにも適用されます。