C / C ++で余分な#includeを検出していますか?


289

ファイルのヘッダーセクションが常に大きくなるのに、小さくならないことがよくあります。ソースファイルの存続期間を通じて、クラスは移動してリファクタリングされている可能性があり、そこに存在する#includes必要のないものも少なくない可能性があります。それらをそこに残すと、コンパイル時間が長くなり、不要なコンパイル依存関係が追加されます。どれがまだ必要かを理解しようとするのは、かなり退屈な作業です。

不要な#includeディレクティブを検出して、安全に削除できるものを提案できるツールはありますか?
リントは多分これをしますか?



1
リンクされた質問は、特にVisual Studioを使用するWindowsでの問題に対処しているようです。
D'Nabre 2014年

7
複製はVisual Studioの使用に関するものなので、これを再度開くよう投票します。
Drew Dormann、2015年

回答:


42

自動ではありませんが、doxygen#includedファイルの依存関係図を作成します。それらを視覚的に確認する必要がありますが、何が何を使用しているかの画像を取得するのに非常に役立ちます。


5
これはチェーンを見るのに最適な方法です。A-> B-> C-> DおよびA-> Dを見ると、冗長性がすぐにわかります。
トム

34
@Tom:それは恐ろしい考えです:1つには、それらのインクルードが必要かどうかは示されていません。次に、インクルードのリストは、将来変更される可能性がある間接インクルードに依存するべきではありません(冗長インクルードは通常そのようなものではありません)いずれにせよ、ガードとコンパイラマジックのおかげで大きな問題ですが、どのクラス/関数が実際にファイルで使用されているか(コンパイラは、インスタンス化されない数千行のテンプレートコードを実行する必要がないはずです)
MikeMB

@albert、これのスクリーンショットを含めて、doxygen出力のどこをクリックするかを簡単に説明できますか?
ガブリエルステープルズ

@GabrielStaplesこれは私の答えではないので、情報を追加したくありません。私はリンクのみを修正しました(ホスティングされた場所が停止した/差し押さえられていたため)。
アルバート

177

Googleのcppclean(リンク先:ダウンロードドキュメント)は、C ++の問題のいくつかのカテゴリを見つけることができ、今では余分な#includeを見つけることができます。

これを行うことができるClangベースのツールinclude-what-you-useもあります。include-what-you-useは、前方宣言を提案し(#includeをあまり必要としないため)、オプションで#includesをクリーンアップできます。

Eclipse CDTの現在のバージョンにも、この機能が組み込まれています。[ソース]メニューの下にある[インクルードの整理]をクリックすると、#includeがアルファベット順に並べられ、Eclipseが使用していると思われるヘッダーが直接追加されずに追加され、ヘッダーがコメント化されます。あなたが必要だとは思わない。ただし、この機能は100%信頼できるわけではありません。


2
今はそうです。使い始めたばかりです。ここに私のメモを参照してください。 stackoverflow.com/questions/1301850/...
チャンス

1
cppcleanリポジトリがダウンしているので、ここで入手できます:bitbucket.org/robertmassaioli/cppclean(元のサイトは、まだいくつかの使用例に役立ちます)
Nick

3
メンテナンスされたcppcleanフォークへのリンクを更新しました:github.com/myint/cppclean
BenC '29

1
cppcleanは、ドキュメント「cheadファイルに不要な#includes」から、cppファイルではなく、ヘッダーファイルでのみそれらを見つけるように見えることに注意してください。
Zitrax

1
@wizurd-私はEclipse CDTの最近の開発に追いついていませんが、そうは思いません。iwyuは完全で比較的遅いです。Eclipse CDTの分析は高速(対話型)であり、私がテストしたところ、精度が低くなっています。
ジョシュケリー

65

同様の問題を解決するinclude-what-you-useも確認してください。


6
私見では、この答えにはさらに多くの賛成票が必要です。問題が解決したら、GoogleのIWYUツールがこのタスクの決定的なツールになるからです。
Dan Olson、

5
sudo apt-get install iwyu
Andrew Wagner

素晴らしいようです-2つのキャベツが含まれています1)最終更新2月2106 2)Gogole自身はC ++ではなく、OPが要求したCに対してのみ使用します。
Mawgはモニカを2016

ユーザーがそれをどのように使用すべきかを少し説明できますか?READMEには、Pythonスクリプトの出力が何を含んでいるかについては明確ではありません。
キングの道化師2017

私はこれを使用していますが、常に100%正しいとは限りません。たぶん70%倍、それは正しい提案をします。
InQusitive 2018

25

余分なインクルードを検出する際の問題は、単なる型依存関係チェッカーではないということです。余分は、コンパイルに価値の何も提供していないファイルで含めると、他のファイルが依存して他の項目を変更しません。ヘッダーファイルがコンパイルを変更する方法はたくさんあります。たとえば、定数を定義したり、使用済みのマクロを再定義または削除したり、名前空間を追加して名前の検索を変更したりします。名前空間のようなアイテムを検出するには、プリプロセッサよりもはるかに多くのものが必要ですが、実際には、ほぼ完全なコンパイラが必要です。

Lintはよりスタイルチェッカーであり、確かにこの完全な機能はありません。

不要なインクルードを検出する唯一の方法は、スイートを削除、コンパイル、実行することだと思います。


8
インクルードファイルが適切にレイアウトされている場合、これは問題になりません。ファイルAをファイルBの前にインクルードする必要がある場合、それは間違っています(そして、私はプロジェクトが間違って行ったプロジェクトに取り組みました)。
David Thornley、

9
@David、そうですが、それを正しく行う前の開発者の年数に依存します。私はそれが起こる確率があなたではなく家に有利であると確信できます:(
JaredPar

はい、しかし、私はプログラムを変更するときに一般的にそれについて知っています、そして突然、私は(私が運が良ければ)コンパイルエラーまたは不明瞭なバグを受け取りました。これは、少なくとも長期的には#includeファイルを正直に保つようです。
David Thornley、

正反対です。必要なのは、型依存関係チェッカーだけです。インクルードを適切に調整した後はコンパイルされない可能性がありますが、これらはいずれにしても対処する必要がある問題です。
–Benoît

1
@Benoitの場合、コンパイルするが意味的にプログラムの意味を変更するクラスの問題は無視します。あるファイルの#defineが別のファイルの#ifブランチをどのように変更できるかを検討してください。ヘッダーを削除しても、これをコンパイルしてさまざまな結果を得ることができます
JaredPar

15

PCLintでこれができると思っていましたが、これを見てから数年になります。あなたはそれをチェックするかもしれません。

私はこのブログを見て、筆者はPCLintを構成して未使用のインクルードを見つける方法について少し話しました。一見の価値があるかもしれません。


良い発見!私はそれを使わなければならないでしょう。
crashmstr 2009年

4
PCLintを定期的に使用していますが、未使用のヘッダーが表示されます。ヘッダー#includeをコメントアウトし、ヘッダーが本当に未使用であることを確認するために再コンパイルするように注意しています...
Harold Bamford

確認をありがとう、ハロルド。
itsmatt 2009年

5
高過ぎ。大衆にとって実行可能なツールではありません。

7

CScoutリファクタリングブラウザは余分検出することができるC(残念ながらいないC ++)コードの指令を含みます。このジャーナルの記事でそれがどのように機能するかの説明を見つけることができます。


5

単一の#includeディレクティブを消去してプロジェクトをコンパイルし、#includeに名前を記録する簡単なスクリプトと、コンパイルエラーが発生しなかった場合に削除されたファイルを記述できます。

夜間に実行すると、翌日、削除できるインクルードファイルの100%正しいリストが表示されます。

ときどきブルートフォースが機能するだけです:-)


編集:そしてそれは時々:-)しません。ここにコメントからの情報の少しがあります:

  1. 2つのヘッダーファイルを個別に削除できる場合がありますが、両方を一緒に削除することはできません。解決策は、実行中にヘッダーファイルを削除し、元に戻さないことです。これにより、安全に削除できるファイルのリストが見つかりますが、このアルゴリズムでは検出されない、削除するファイルの数が多い解決策があるかもしれません。(これは、削除するインクルードファイルのスペースに対する貪欲な検索です。ローカルの最大値のみを検出します)
  2. いくつかの#ifdefsに応じて異なる方法で再定義されたマクロがある場合、動作に微妙な変化が生じる可能性があります。これらは非常にまれなケースだと思います。ビルドの一部である単体テストはこれらの変更をキャッチする必要があります。

1
これに注意してください-何かの定義を含む2つのヘッダーファイルがあるとします。どちらかを削除できますが、両方は削除できません。ブルートフォースアプローチでは、もう少し徹底する必要があります。
ドミニクロジャー

多分これはあなたが意図したことですが、単一のインクルードを削除し、最後に削除されたインクルードが正常に削除された場合にそれを残すスクリプトは、トリックを実行します。
ドミニクロジャー

1
悪いアイデア。ヘッダーファイルが定数BLAHを#defineし、別のヘッダーファイルが#ifdef BLAHをチェックする場合、最初のヘッダーファイルを削除してもコンパイルは成功する可能性がありますが、動作が変更されています。
Graeme Perrow

1
#include <vector>に含まれる実装が異なる可能性があるため、これもシステムヘッダーで問題を引き起こす可能性があります。1つのコンパイラーを使用する場合でも、ヘッダーは異なるバージョンで変更される可能性があります。
David Thornley

2
これは、本当に必要なヘッダーを含むヘッダーを含めているケースを見つけられません。
bk1e 2009年

5

ここに(再)投稿して申し訳ありませんが、人々はコメントを展開しないことがよくあります。

crashmstrへの私のコメントを確認してください。FlexeLint/ PC-Lintがこれを行います。情報メッセージ766。マニュアル(バージョン8.0)のセクション11.8.1でこれについて説明しています。

また、これは重要ですメッセージが消えるまで繰り返します。つまり、未使用のヘッダーを削除した後、lintを再実行すると、不要なヘッダーを削除すると、より多くのヘッダーファイルが「不要」になる可能性があります。(ばかげているように聞こえるかもしれませんが、ゆっくり読んで解析してください。理にかなっています。)


私はあなたが何を意味するのか正確に知っており、私の反応は「Ewwww」でした。そのようなコードは嫌いです。
David Thornley

5

私はあなたが求めていることを達成する本格的なツールを見つけたことがありません。私が使用した最も近いものはIncludeManagerです。これは、ヘッダーインクルードツリーをグラフ化するため、1つのファイルにのみ含まれるヘッダーや循環ヘッダーインクルードなどを視覚的に見つけることができます。


4

Flexelint(UNIX版のPC-Lint)を使用してみましたが、結果はやや複雑でした。これは、私が非常に大きくて節のあるコードベースに取り組んでいるためと考えられます。未使用として報告された各ファイルを注意深く調べることをお勧めします。

主な心配は誤検知です。同じヘッダーの複数のインクルードは、不要なヘッダーとして報告されます。Flexelintは、ヘッダーが含まれている行やヘッダーが以前どこに含まれていたかを通知しないため、これは悪いことです。

自動化ツールがこれを誤る可能性がある方法の1つ:

A.hppの場合:

class A { 
  // ...
};

B.hppの場合:

#include "A.hpp

class B {
    public:
        A foo;
};

C.cppの場合:

#include "C.hpp"  

#include "B.hpp"  // <-- Unneeded, but lint reports it as needed
#include "A.hpp"  // <-- Needed, but lint reports it as unneeded

Flexelintからのメッセージを盲目的にフォローすると、#includeの依存関係が崩れます。もっと病理的なケースがありますが、基本的には最良の結果を得るために自分でヘッダーを検査する必要があります。

ブログゲームの物理構造とC ++に関するこの記事を内側から強くお勧めします。彼らは#includeの混乱をクリーンアップするための包括的なアプローチを推奨しています:

ガイドライン

これは、ファイル間の物理的な依存関係の数を最小限に抑えるLakosの本からの抜粋した一連のガイドラインです。私はそれらを何年も使用しており、常に結果に本当に満足しています。

  1. すべてのcppファイルには、最初に独自のヘッダーファイルが含まれます。[をちょきちょきと切る]
  2. ヘッダーファイルには、解析に必要なすべてのヘッダーファイルを含める必要があります。[をちょきちょきと切る]
  3. ヘッダーファイルには、それを解析するために必要な最低限の数のヘッダーファイルが必要です。[をちょきちょきと切る]

Lakosの本は、コンパイラテクノロジーに関する彼の古い観察を除いて、教育に最適です。
トム

4

Eclipse CDTを使用している場合、http://includator.comを試すことができます(これは、この記事の執筆時点で)ベータテスターに​​は無料であり、不要な#includeを自動的に削除したり、欠落しているものを追加したりできます。FlexeLintまたはPC-Lintを使用していて、Elicpse CDTを使用しているユーザーの場合、http: //linticator.com がオプションになる場合があります(ベータテストも無料)。Lintの分析を使用しながら、余分な#includeステートメントを自動的に削除するためのクイックフィックスを提供します。


その理由は、簿記部門がそれより少ない金額を請求することができないためです。あなたが節約できる時間を数えるなら、それはそれほど不合理ではありません。一度、私たちは大幅に価格を下げることができるクレジットカードの支払いを取得する機能を持っています。別のオプションは、私たちの開発努力のスポンサーです。私たちの資金調達モデルでは、研究活動に資金を提供するために利益を得る必要があります。ライセンスをもっと安く販売したいのですが、できません。それをCDTに寄付して無料で手に入れられるかもしれませんが、なんとかして資金を調達する必要があります。忘れました、無料で試すことができます!
PeterSom 2013

2

この記事では、Doxygenの解析を使用して#includeを削除する手法について説明します。これは単なるperlスクリプトなので、非常に簡単に使用できます。


1
スクリプトは、削除するいくつかのインクルードを検出しますが、削除できない多くのインクルードも提供します。それはクラス列挙型をサポートしていないようです、それはまた、マクロと時々名前空間で悪い時間を持っているようです。
Baptiste Wicht 2012年

1

少し遅いかもしれませんが、私はかつてあなたが望んでいたことを実行するWebKit perlスクリプトを見つけました。私は信じているいくつかの適応が必要になります(私はperlに精通していません)が、それでうまくいくはずです。

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

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



1

余分な#includeファイルには2つのタイプがあります。

  1. 実際にはモジュール(.c、.cpp)ではまったく必要ないヘッダーファイル
  2. ヘッダーファイルはモジュールで必要ですが、直接または間接的に複数回インクルードされています。

私の経験には、それをうまく検出するための2つの方法があります。

  • gcc -Hまたはcl.exe / showincludes(問題2を解決)

    実際には、すべてのMakefileがCFLAGSオプションをオーバーライドしない場合は、makeの前にCFLAGS = -Hをエクスポートできます。または、私が使用したように、cc / g ++ラッパーを作成して、$(CC)および$(CXX)の各呼び出しに-Hオプションを強制的に追加できます。ラッパーのディレクトリを$ PATH変数の前に付加すると、makeはすべてラッパーコマンドを代わりに使用します。もちろん、ラッパーは実際のgccコンパイラーを呼び出す必要があります。Makefileが直接gccを使用する場合、このトリックを変更する必要があります。$(CC)または$(CXX)の代わり、または暗黙のルールによる。

    コマンドラインで微調整することにより、単一のファイルをコンパイルすることもできます。ただし、プロジェクト全体のヘッダーをクリーンアップする場合。次の方法ですべての出力をキャプチャできます。

    きれいにする

    make 2>&1 | Tシャツのresult.txt

  • PC-Lint / FlexeLint(1と2の両方で問題を解決)

    + e766オプションを追加してください。この警告は、未使用のヘッダーファイルに関するものです。

    pclint / flint -vf ...

    これにより、pclint出力にヘッダーファイルが含まれ、ネストされたヘッダーファイルは適切にインデントされます。


1

この議論を終わらせるために:c ++プリプロセッサが完成しつつあります。インクルードが不必要かどうかは、セマンティックプロパティです。したがって、ライスの定理から、インクルードが不必要かどうかは決定できないということになります。インクルードが不要かどうかを(常に正しく)検出するプログラムは存在できません。


5
「常に正しい」ソリューションを求めましたか?この答えは、議論にとってあまり生産的ではありません。
2014

1
まあ、そのようなプログラムが対処しなければならない問題を議論する多くの投稿がありました。私の投稿は、議論のその部分に決定的で正しい答えを与えます。そして、私はそれが好きではありません、プログラムが私に言った場合、私は#includeを安全に削除することができ、その後私のコードはもうコンパイルされません。(さらに悪いことに-コンパイルはしますが別のことをします)。そのようなプログラムはこのリスクを負います。
アルゴマン2014

4
それがどれほど難しいかについてのすべての推測と、ある障害を別の障害を解決する可能性について、私は100%だけ正しい答えを与えました。これが生産的ではなかったと言うのは非常に
無分別だと思い

1
ライスの定理が「与えられたプログラムがこの余分なインクルード問題を解決するかどうかを常にチェックできるプログラムはあり得ない」と述べていることを思い出しました。余分なインクルードの問題を解決するプログラムがいくつかある場合があります。
Zhe Yang

1
個人的に私は@Algomanの入力がとても役に立ったと感じました。この問題の難しさを実感します。
bogardon 2017


0

Gimpel SoftwareのPC Lintは、インクルードファイルがコンパイルユニットに2回以上インクルードされたことをレポートできますが、探している方法で不要なインクルードファイルを見つけることができません。

編集:できます。itsmattの答えを見てください


あなたは必ずそのことについて?FlexeLint(PCLと同じ)をC ++コードで数年使用していませんが、最近のCコードでも、未使用のヘッダーファイルに関するいくつかのメッセージ(コード766だと思いますか?)が表示されたことがわかりました。チェック済み(v8.0)、セクション11.8.1を参照。マニュアルの。
Dan

0

JetBrainsのC / C ++ IDEであるCLionは、冗長なインクルードをすぐに検出します。これらはエディターではグレー表示されますが、現在のファイルまたはプロジェクト全体のインクルード最適化する関数もあります

ただし、この機能は有料であることがわかりました。CLionが最初にロードされたとき、プロジェクトのスキャンと分析にしばらく時間がかかります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.