簡體   English   中英

如何在大型C ++項目中檢測不必要的#include文件?

[英]How should I detect unnecessary #include files in a large C++ project?

我正在研究Visual Studio 2008中的一個大型C ++項目,並且有很多文件帶有不必要的#include指令。 有時#include只是工件,一切都會被刪除,但是在其他情況下,類可以向前聲明,#include可以移動到.cpp文件。 是否有任何好的工具可以檢測這兩種情況?

雖然它不會顯示不需要的包含文件,但Visual Studio有一個設置/showIncludes (右鍵單擊.cpp文件, Properties->C/C++->Advanced ),它將在編譯時輸出所有包含文件的樹。 這有助於識別不需要包含的文件。

您還可以查看pimpl習慣用法,以便減少頭文件依賴性,從而更容易看到可以刪除的內容。

PC Lint對此非常有效,它也為您找到各種其他愚蠢的問題。 它具有可用於在Visual Studio中創建外部工具的命令行選項,但我發現Visual Lint插件更易於使用。 即使是免費版的Visual Lint也有幫助。 但給PC-Lint一個機會。 配置它以便它不會給你太多的警告需要一點時間,但你會驚訝於它出現了什么。

有一個新的基於Clang的工具, 包括你使用什么 ,旨在實現這一目標。

!!免責聲明! 我從事商業靜態分析工具(不是PC Lint)。 !!免責聲明!

簡單的非解析方法有幾個問題:

1)過載集:

重載函數可能具有來自不同文件的聲明。 可能是刪除一個頭文件會導致選擇不同的重載而不是編譯錯誤! 結果將是語義的靜默變化,之后可能很難跟蹤。

2)模板專業化:

與重載示例類似,如果您對模板有部分或顯式特化,則希望在使用模板時它們都可見。 可能是主模板的特化是在不同的頭文件中。 使用特化刪除標頭不會導致編譯錯誤,但如果選擇了該特化,則可能導致未定義的行為。 (參見: C ++函數模板特化的可見性

正如'msalters'所指出的那樣,對代碼進行全面分析還可以分析類的使用情況。 通過檢查文件的特定路徑如何使用類,有可能可以完全刪除類的定義(以及它的所有依賴性),或者至少移動到更接近包含主要源的級別樹。

我不知道有任何這樣的工具,我曾考慮過寫一個這樣的工具,但事實證明這是一個難以解決的問題。

說你的源文件包含啊和bh; 啊包含#define USE_FEATURE_X ,bh使用#ifdef USE_FEATURE_X 如果注釋掉了#include "ah" ,那么您的文件仍然可以編譯,但可能無法達到預期效果。 編程方式檢測這一點並非易事

無論使用什么工具,您都需要了解構建環境。 如果啊看起來像:

#if defined( WINNT )
   #define USE_FEATURE_X
#endif

然后,只有在定義了WINNT時才定義USE_FEATURE_X ,因此該工具需要知道編譯器本身生成的指令以及編譯命令而不是頭文件中指定的指令。

像Timmermans一樣,我對此並不熟悉任何工具。 但我知道編寫Perl(或Python)腳本的程序員嘗試一次注釋掉每個include行,然后編譯每個文件。


看來現在Eric Raymond 有了這個工具

谷歌的cpplint.py有一個“包含你使用的”規則(以及其他許多規則),但據我所知,沒有“ 包括你使用的內容”。 即便如此,它也很有用。

如果您對這個主題感興趣,可能需要查看Lakos的大規模C ++軟件設計 這有點過時了,但是會遇到許多“物理設計”問題,例如找到需要包含的標題的絕對最小值。 我還沒有真正看到其他任何地方討論過這種事情。

試試Include Manager 它可以在Visual Studio中輕松集成,並可視化您的包含路徑,幫助您查找不必要的東西。 在內部,它使用Graphviz,但還有許多很酷的功能。 雖然它是商業產品,但價格非常低廉。

您可以使用C / C ++ Include File Dependencies Watcher構建包含圖,並直觀地查找不需要的包含。

如果您的頭文件通常以

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

(而不是使用#pragma一次)您可以將其更改為:

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

並且由於編譯器輸出正在編譯的cpp文件的名稱,這將使您至少知道哪個cpp文件導致多次引入標頭。

PC-Lint確實可以做到這一點。 一種簡單的方法是將其配置為僅檢測未使用的包含文件並忽略所有其他問題。 這非常簡單 - 只啟用消息766(“模塊中未使用的頭文件”),只需在命令行中包含選項-w0 + e766即可。

相同的方法也可以與相關的消息一起使用,例如964(“未在模塊中直接使用的頭文件”)和966(“間接包含的未在模塊中使用的頭文件”)。

我在上周的博客文章http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318上更詳細地寫了這篇文章。

如果您希望刪除不必要的#include文件以減少構建時間,那么使用cl.exe / MPmake -jXoreax IncrediBuild ,distcc / icecream等可以更好地花時間和金錢來構建進程。

當然,如果您已經有一個並行構建過程並且仍在嘗試加速它,那么一定要清理#include指令並刪除那些不必要的依賴項。

從每個包含文件開始,並確保每個包含文件僅包含編譯自身所需的內容。 然后,C ++文件中缺少的任何包含文件都可以添加到C ++文件本身。

對於每個包含文件和源文件,一次注釋掉每個包含文件,看它是否編譯。

按字母順序對包含文件進行排序也是一個好主意,如果不可能,請添加注釋。

最新的Jetbrains IDE,CLion,自動顯示(灰色)當前文件中未使用的包含。

也可以從IDE中獲取所有未使用的包括(以及函數,方法等)的列表。

如果您使用Eclipse CDT,可以嘗試http://includator.com來優化您的包含結構。 但是,Includator可能對VC ++的預定義包含知識不夠,並且設置CDT以使用正確包含的VC ++還沒有內置到CDT中。

添加以下一個或兩個#defines將排除經常不必要的頭文件,並且可能大大改善編譯時間,尤其是在不使用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

此外,盡管對您的項目來說可能為時已晚,但將項目組織成各個部分而不是將所有本地標題集中到一個大的主標題是一個很好的做法,盡管需要一些額外的工作。

如果你認為不再需要一個特定的標題(比如string.h),你可以注釋掉include然后把它放在所有包含的下面:

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

當然,您的接口標頭可能使用不同的#define約定來記錄它們包含在CPP內存中。 或者沒有慣例,在這種情況下這種方法不起作用。

然后重建。 有三種可能性:

  • 它構建好了。 string.h不是編譯關鍵的,可以刪除它的include。

  • #error之旅。 string.g以某種方式間接包含你仍然不知道是否需要string.h。 如果需要,您應該直接#include它(見下文)。

  • 你得到一些其他編譯錯誤。 string.h是必需的,並沒有間接包含,所以包含是正確的開始。

請注意,當您的.h或.c直接使用另一個.h時,取決於間接包含。幾乎肯定是一個錯誤:您實際上承諾,只要您使用的其他標頭需要它,您的代碼將只需要該標頭,這可能不是你的意思。

在其他答案中提到的關於修改行為的標題而不是聲明導致構建失敗的事情的注釋也適用於此處。

也許有點晚了,但我曾經發現一個WebKit perl腳本可以完成你想要的。 它需要一些適應我相信(我不熟悉perl),但它應該做的伎倆:

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

(這是一個舊分支,因為trunk不再有文件)

一些現有的答案表明它很難。 確實如此,因為您需要一個完整的編譯器來檢測前向聲明適合的情況。 你不能解析C ++而不知道符號是什么意思; 語法對此來說太模糊了。 您必須知道某個名稱是否命名一個類(可以是前向聲明的)還是一個變量(不能)。 此外,您需要知道名稱空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM