2016-11-15 12 views
6

Miałem problemy z przygotowaniem wstępnie skompilowanych nagłówków, więc wymyśliłem następujący minimalny przykład działania.Dziwne zachowanie z prekompilowanymi nagłówkami gcc

Jest to plik nagłówka foo.h

#include <iostream> 
using namespace std; 

void hello() { 
    cout << "Hello World" << endl; 
} 

skompilować to jako g++ -c foo.h daje mi skompilowaną nagłówek foo.gch. Spodziewam się, że kiedy skompiluję następujący plik źródłowy, który zawiera foo.h, powinien wybrać nagłówek foo.h.gch i jestem dobry.

// test.cpp 
#include <cstdio> // Swap ordering later 
#include "foo.h" // ------------------ 

int main() { 
    hello(); 
} 

Ale o dziwo, to nie kompiluje używając foo.h.gch, ale raczej używa foo.h. Aby zweryfikować można skompilować to jako g++ -H test.cpp

Jednak, jeśli mogę zmienić kolejność włączonych plików nagłówkowych następująco:

// test.cpp 
#include "foo.h" // ------------------ 
#include <cstdio> // Ordering swapped 

int main() { 
    hello(); 
} 

Teraz, jeśli mogę skompilować za pomocą g++ -H test.cpp, kompiluje z foo.h.gch, uff!

Tak więc zastanawiałem się, czy jest to błąd w GCC, czy też powinniśmy używać tak skompilowanych nagłówków? W każdym razie myślę, że warto wiedzieć ..

Odpowiedz

4

z GCC, nagłówki Prekompilowane pracować tylko jeśli są one tylko nagłówek, a jeśli są one zawarte pierwszy (bez wcześniejszego nagłówka).

This answer wyjaśnia więcej dlaczego tak jest. Zobacz także Precompiled headers rozdział dokumentacji GCC, który mówi:

  • Tylko jeden prekompilowany Nagłówek może być używany w danej kompilacji.
  • Wstępnie skompilowany nagłówek nie może zostać użyty po zobaczeniu pierwszego tokena C.

BTW, może się zdarzyć, że pre-kompilacji niektóre duże nagłówek (zwłaszcza w C++) nie jest warte wysiłku. YMMV.

+1

W moim przypadku wydaje się być super skuteczny! Prekompiluję nagłówki CGAL i zmniejszyłem czas kompilacji z około 18 do 2s. – sud03r

4

Od GCC manual pages:

skompilowany nagłówka nie może być stosowany raz pierwszy C tokenu jest postrzegana.

Tak więc w tym <cstdio> w prekompilowanym nagłówku lub tym pierwszym będzie działać.

+0

Dzięki za odpowiedź! Oczywiście, jest to udokumentowane :). Gdyby tylko programiści (lub raczej niecierpliwi programiści tacy jak ja) mogli je przeczytać. – sud03r

3

W skrócie, prekompilowany nagłówek rzecz działa w następujący sposób:

Kiedy żądać, aby utworzyć plik „” .pch, kompilator przetwarza plik źródłowy, jak zwykle. Podczas gdy to robi, jego wewnętrzne struktury (głównie tabele nazw i wszystkie powiązane dane) są zapełniane. Na końcu tworzy migawkę tych wewnętrznych struktur i zapisuje ją do pliku ".pch".

Później, podczas kompilowania pliku źródłowego zawierającego nagłówek, dla którego ".istnieje plik pch, kompilator może pominąć kosztowne przetwarzanie pliku nagłówkowego i zamiast tego załadować gotową do użycia migawkę z pliku ".pch".

Oczywiście, można to zrobić bez wpływu na semantykę tylko wtedy, gdy:

  • włączenie dyrektywa wchodzi zanim cokolwiek innego;
  • opcje kompilatora są takie same.

Wszystko, co jest przed dyrektywy włączenie może:

  • dodać coś do wewnętrznych struktur danych kompilatora;
  • wpływa na przetwarzanie pliku nagłówkowego;
  • zmieniają relacje między opisanymi tam podmiotami.

Dlatego w tym przypadku załadowanie migawki wewnętrznych struktur danych byłoby błędne, ponieważ nie byłoby żadnej gwarancji, że pozostawiłoby te struktury w stanie takim, w jakim normalnie przetwarzało nagłówek.