Pracuję nad dużym projektem C ++ w Visual Studio 2008 i jest tam dużo plików z niepotrzebnymi #include
dyrektywami. Czasami #include
s są tylko artefaktami i wszystko będzie się dobrze skompilować po ich usunięciu, aw innych przypadkach klasy mogą być zadeklarowane do przodu, a #include można przenieść do .cpp
pliku. Czy istnieją dobre narzędzia do wykrywania obu tych przypadków?
źródło
PC Lint działa całkiem dobrze w tym celu i znajduje dla ciebie również wiele innych głupich problemów. Ma opcje wiersza poleceń, których można użyć do tworzenia narzędzi zewnętrznych w programie Visual Studio, ale odkryłem, że dodatek Visual Lint jest łatwiejszy w użyciu. Pomaga nawet bezpłatna wersja Visual Lint. Ale daj PC-Lint szansę. Skonfigurowanie go tak, aby nie wyświetlał zbyt wielu ostrzeżeń, zajmuje trochę czasu, ale będziesz zaskoczony, co się pojawi.
źródło
Jest nowe narzędzie oparte na Clang, zawierające to, czego używasz , które ma to zrobić.
źródło
!!ZRZECZENIE SIĘ!! Pracuję na komercyjnym narzędziu do analizy statycznej (nie na PC Lint). !!ZRZECZENIE SIĘ!!
Istnieje kilka problemów związanych z prostym podejściem bez analizy:
1) Zestawy przeciążeniowe:
Możliwe, że przeciążona funkcja ma deklaracje pochodzące z różnych plików. Może się zdarzyć, że usunięcie jednego pliku nagłówkowego spowoduje wybranie innego przeciążenia zamiast błędu kompilacji! Rezultatem będzie cicha zmiana semantyki, która może być później bardzo trudna do wyśledzenia.
2) Specjalizacje szablonów:
Podobnie jak w przypadku przeciążenia, jeśli masz częściowe lub jawne specjalizacje dla szablonu, chcesz, aby wszystkie były widoczne, gdy szablon jest używany. Może się zdarzyć, że specjalizacje dla szablonu podstawowego znajdują się w różnych plikach nagłówkowych. Usunięcie nagłówka ze specjalizacją nie spowoduje błędu kompilacji, ale może spowodować niezdefiniowane zachowanie, jeśli ta specjalizacja została wybrana. (Zobacz: Widoczność specjalizacji szablonów funkcji C ++ )
Jak podkreśla „msalters”, przeprowadzenie pełnej analizy kodu pozwala również na analizę wykorzystania klas. Sprawdzając, w jaki sposób klasa jest używana przez określoną ścieżkę plików, możliwe jest, że definicja klasy (a tym samym wszystkie jej zależności) może zostać całkowicie usunięta lub przynajmniej przeniesiona na poziom bliżej głównego źródła w dołączaniu drzewo.
źródło
Nie znam takich narzędzi, myślałem o napisaniu takiego w przeszłości, ale okazuje się, że jest to trudny problem do rozwiązania.
Powiedz, że twój plik źródłowy zawiera ah i bh; ah zawiera
#define USE_FEATURE_X
i bh używa#ifdef USE_FEATURE_X
. Jeśli#include "a.h"
zostanie zakomentowany, plik może nadal się kompilować, ale może nie działać zgodnie z oczekiwaniami. Wykrywanie tego programowo nie jest trywialne.Jakiekolwiek narzędzie to robi, musi również znać twoje środowisko kompilacji. Jeśli ah wygląda tak:
Następnie
USE_FEATURE_X
jest definiowana tylko wtedy, gdyWINNT
jest zdefiniowana, więc narzędzie musiałoby wiedzieć, jakie dyrektywy są generowane przez sam kompilator, a także które są określone w poleceniu kompilacji, a nie w pliku nagłówkowym.źródło
Podobnie jak Timmermans, nie znam żadnych narzędzi do tego. Ale znam programistów, którzy napisali skrypt w Perlu (lub Pythonie), aby spróbować skomentować każdą linię dołączania po kolei, a następnie skompilować każdy plik.
Wygląda na to, że teraz Eric Raymond ma do tego narzędzie .
Plik cpplint.py Google zawiera regułę „uwzględnij to, czego używasz” (wśród wielu innych), ale o ile wiem, nie ma „uwzględniaj tylko to, czego używasz”. Mimo to może się przydać.
źródło
Jeśli jesteś ogólnie zainteresowany tym tematem, możesz zapoznać się z projektem oprogramowania C ++ firmy Lakos na dużą skalę . Jest trochę przestarzały, ale wiąże się z wieloma problemami z „projektami fizycznymi”, takimi jak znalezienie absolutnego minimum nagłówków, które należy uwzględnić. Tak naprawdę nie widziałem nigdzie indziej dyskusji o tego rodzaju sprawach.
źródło
Wypróbuj Include Manager . Łatwo integruje się z programem Visual Studio i wizualizuje ścieżki dołączania, co pomaga znaleźć niepotrzebne rzeczy. Wewnętrznie korzysta z Graphviz, ale jest o wiele więcej fajnych funkcji. I choć jest to produkt komercyjny to ma bardzo niską cenę.
źródło
Możesz zbudować wykres dołączania za pomocą C / C ++ Include File Dependencies Watcher i wizualnie znaleźć niepotrzebne dołączenia.
źródło
Jeśli twoje pliki nagłówkowe zwykle zaczynają się od
(w przeciwieństwie do używania #pragma raz) możesz to zmienić na:
A ponieważ kompilator wypisuje nazwę kompilowanego pliku cpp, to pozwoli ci wiedzieć przynajmniej, który plik cpp powoduje wielokrotne wstawianie nagłówka.
źródło
A.h
iB.h
że zarówno zależąC.h
i dołączyćA.h
iB.h
, ponieważ trzeba mieć, to będzie toC.h
dwa razy, ale to dobrze, bo kompilator będzie go pominąć drugi raz, a jeśli nie, to trzeba pamiętać, zawsze włączaćC.h
wcześniejA.h
lubB.h
kończyć w znacznie bardziej bezużytecznych inkluzjach.PC-Lint rzeczywiście może to zrobić. Prostym sposobem na to jest skonfigurowanie go tak, aby wykrywał tylko nieużywane pliki dołączania i ignorował wszystkie inne problemy. Jest to całkiem proste - aby włączyć tylko komunikat 766 ("Plik nagłówkowy nie jest używany w module"), wystarczy dołączyć opcje -w0 + e766 w linii poleceń.
To samo podejście można również zastosować w przypadku powiązanych komunikatów, takich jak 964 („Plik nagłówkowy nie jest bezpośrednio używany w module”) i 966 („Plik nagłówkowy dołączany pośrednio nie jest używany w module”).
FWIW Pisałem o tym bardziej szczegółowo w poście na blogu w zeszłym tygodniu pod adresem http://www.riverblade.co.uk/blog.php?archive=2008_09_01_archive.xml#3575027665614976318 .
źródło
Jeśli chcesz usunąć niepotrzebne
#include
pliki, aby skrócić czas kompilacji, Twój czas i pieniądze mogą być lepiej wydane na zrównoleglenie procesu kompilacji za pomocą cl.exe / MP , make -j , Xoreax IncrediBuild , distcc / icecream itp.Oczywiście, jeśli masz już równoległy proces kompilacji i nadal próbujesz go przyspieszyć, to na wszelki wypadek wyczyść swoje
#include
dyrektywy i usuń te niepotrzebne zależności.źródło
Zacznij od każdego pliku dołączanego i upewnij się, że każdy plik dołączany zawiera tylko to, co jest niezbędne do jego skompilowania. Wszelkie pliki dołączane, których brakuje w plikach C ++, można dodać do samych plików C ++.
Dla każdego pliku dołączania i pliku źródłowego umieść w komentarzu każdy plik dołączany pojedynczo i zobacz, czy się kompiluje.
Dobrym pomysłem jest również sortowanie plików dołączanych alfabetycznie, a jeśli nie jest to możliwe, należy dodać komentarz.
źródło
Dodanie jednego lub obu poniższych #defines spowoduje wykluczenie często niepotrzebnych plików nagłówkowych i może znacznie skrócić czas kompilacji, zwłaszcza jeśli kod nie korzysta z funkcji Windows API.
Zobacz http://support.microsoft.com/kb/166474
źródło
Jeśli jeszcze tego nie zrobiłeś, użycie wstępnie skompilowanego nagłówka, aby uwzględnić wszystko, czego nie zamierzasz zmieniać (nagłówki platformy, zewnętrzne nagłówki SDK lub statyczne już ukończone elementy projektu), spowoduje ogromną różnicę w czasie kompilacji.
http://msdn.microsoft.com/en-us/library/szfdksca(VS.71).aspx
Ponadto, chociaż może być już za późno na Twój projekt, podzielenie go na sekcje i nie wrzucanie wszystkich lokalnych nagłówków do jednego dużego nagłówka głównego jest dobrą praktyką, chociaż wymaga trochę dodatkowej pracy.
źródło
Jeśli chciałbyś pracować z Eclipse CDT, możesz wypróbować http://includator.com, aby zoptymalizować strukturę dołączania. Jednak Includator może nie wiedzieć wystarczająco dużo o predefiniowanych dołączeniach VC ++, a konfiguracja CDT do używania VC ++ z poprawnymi dołączeniami nie jest jeszcze wbudowana w CDT.
źródło
Najnowsze IDE Jetbrains, CLion, automatycznie wyświetla (na szaro) dołączenia, które nie są używane w bieżącym pliku.
Możliwe jest również posiadanie listy wszystkich nieużywanych włączeń (a także funkcji, metod itp.) Z IDE.
źródło
Niektóre z istniejących odpowiedzi mówią, że jest to trudne. To rzeczywiście prawda, ponieważ potrzebujesz pełnego kompilatora, aby wykryć przypadki, w których deklaracja forward byłaby odpowiednia. Nie możesz analizować C ++, nie wiedząc, co oznaczają symbole; gramatyka jest na to po prostu zbyt niejednoznaczna. Musisz wiedzieć, czy określona nazwa określa klasę (może być zadeklarowana do przodu), czy zmienną (nie można). Ponadto musisz być świadomy przestrzeni nazw.
źródło
Może trochę za późno, ale kiedyś znalazłem skrypt WebKit Perl, który robił dokładnie to, czego chciałeś. Uważam, że będzie to wymagało trochę adaptacji (nie jestem dobrze zorientowany w perlu), ale powinno to załatwić:
http://trac.webkit.org/browser/branches/old/safari-3-2-branch/WebKitTools/Scripts/find-extra-includes
(to jest stara gałąź, ponieważ trunk nie ma już pliku)
źródło
Jeśli istnieje konkretny nagłówek, który Twoim zdaniem nie jest już potrzebny (powiedzmy string.h), możesz skomentować, który zawiera, a następnie umieścić to poniżej wszystkich dołączeń:
Oczywiście nagłówki twojego interfejsu mogą używać innej konwencji #define do zapisywania ich włączenia do pamięci CPP. Lub brak konwencji, w takim przypadku to podejście nie zadziała.
Następnie odbuduj. Istnieją trzy możliwości:
Buduje się dobrze. string.h nie był krytyczny dla kompilacji i można go usunąć.
Wycieczki #error. string.g został w jakiś sposób dołączony pośrednio Nadal nie wiesz, czy string.h jest wymagany. Jeśli jest to wymagane, należy je bezpośrednio # uwzględnić (patrz poniżej).
Pojawia się inny błąd kompilacji. string.h był potrzebny i nie jest dołączany pośrednio, więc dołączenie było poprawne na początku.
Zwróć uwagę, że zależność od pośredniego włączenia, gdy .h lub .c bezpośrednio używa innego .h, jest prawie na pewno błędem: w efekcie obiecujesz, że twój kod będzie wymagał tylko tego nagłówka, o ile inny używany nagłówek tego wymaga, co prawdopodobnie nie jest tym, co miałeś na myśli.
Zastrzeżenia wymienione w innych odpowiedziach na temat nagłówków, które modyfikują zachowanie, a nie deklarują rzeczy powodujące awarie kompilacji, mają również zastosowanie tutaj.
źródło