Vorkompilierte Header

Die langen Kompilationszeiten bei C++ ...

Haben Sie auch Angst vor dem nächsten recompile all? Hüten Sie sich schon seit langer Zeit davor, Änderungen an einer zentralen Basisklasse Ihres Projekts vorzunehmen, weil Sie dann erst einmal eine halbe Stunde auf den Compiler warten müssen? Dann sind vorkompilierte Header vielleicht etwas für Sie!

Vorkompilierte Header sind letztendlich ein Hack für das archaische include-System von C++ (und auch von C). Hierbei werden durch die #include-Direktive des Präprozessors benötigte Deklarationen einer .cpp Datei aus den Header-Dateien geparst. Da Header-Dateien ihrerseits meist weitere Header-Dateien inkludieren, und das Parsen eines Headers nicht-trivial sein kann (zum Beispiel wegen Templates oder ähnlichem), dauert dies oft sehr lange, und verschlingt in der Regel den größten Teil der Kompilationszeit.

In vielen Fällen inkludieren die Quelldateien eines Projekts aber die gleichen Dateien. Vorkompilierte Header verwenden heißt also, wie der Name schon andeutet, das Ergebnis des Parsens einer Header-Datei abzuspeichern und für das Kompilieren möglichst vieler Quelldateien zu nutzen. Natürlich macht das nur dann Sinn, wenn das Projekt auch wirklich viele Quelldateien enthält.

Vorkompilierte Header werden zum Beispiel von den Microsoft C++ Compilern unterstützt. Der gcc wird vorkompilierte Header ab Version 3.4 unterstützen.

Vorkompilierte Header mit Microsoft Visual C++

Visual C++ bietet eine Automatik für vorkompilierte Header an. Diese funktioniert nur in Ausnahmefällen, nämlich bei MFC-Projekten, die mit Wissen um die Automatik geschrieben sind. Zudem merkt man als Entwickler nicht, wenn die automatische Funktion die falschen Einstellungen vorgenommen hat - das Projekt kompiliert dann nur deutlich langsamer als ganz ohne vorkompilierte Header, weil die vorkompilierten Header-Dateien erzeugt und auf die Festplatte geschrieben, dann aber nicht benutzt werden! Es ist dies auch der Grund dafür, das vorkompilierte Header einen schlechten Ruf besitzen und oft empfohlen wird, sie einfach auszuschalten.

Alles in allem ist es also unbedingt empfehlenswert, die Konfiguration der vorkompilierten Header in den Projekt-Einstellungen per Hand vorzunehmen. Die Schritte dazu sind im Folgenden beschrieben.

  • Zunächst muss man eine Header-Datei identifizieren, die von möglichst allen Quelldateien benötigt und zumindest indirekt inkludiert wird. In Frage kömmt je nach verwendeten Bibliotheken zum Beispiel windows.h oder qmainwindow.h, aber auch STL-Bibliotheken wie iostream. Gibt es mehrere solcher Include-Dateien, legt man eine neue Include-Datei precompiled.h an, die genau diese fraglichen Dateien inkludiert, und sonst nichts tut. Im folgenden gehe ich davon aus, dass precompiled.h der Name der vorkompilierten Header-Datei ist.
  • Nun nimmt man in das Projekt eine Datei precompiled.cpp auf, deren einzige Nicht-Kommentar-Zeile #include "precompiled.h" ist.
  • Alle anderen Quelldateien im Projekt modifiziert man dahingehend, dass sie als erste Zeile precompiled.h inkludieren. Stellen Sie außerdem sicher, dass all diese Dateien mit den gleichen Compiler-Einstellungen kompiliert werden. Sollten diese beiden Dinge für einige Dateien nicht möglich oder sinnvoll sein, sind im nun folgenden Schritt die betroffenen Dateien von der Verwendung vorkompilierter Header auszunehmen.
  • Nun werden die Projekteinstellungen in folgender Weise verändert (in VC6: Projekt -> Einstellungen -> C/C++ -> Vorkompilierte Header):
    • Für das gesamte Projekt: Vorkompilierte Header verwenden durch Header precompiled.h.
    • Für die Datei precompiled.cpp: Vorkompilierte Header erstellen durch Header precompiled.h.
    • Für Quelldateien, in denen man in der ersten Zeile precompiled.h nicht inkludieren konnte: Vorkompilierte Header nicht verwenden
    Vergessen Sie nicht, diese Einstellungen sowohl für die Release- als auch für die Debug-Konfiguration einzustellen.
  • Dann kompilieren Sie neu, und staunen Sie über die Geschwindigkeit!

Wenn Sie einen Fehler gemacht haben, erhalten Sie glücklicherweise eine einigermaßen nachvollziehbare Fehlermeldung.

Nachteile

Vorkompilierte Header haben einen schlechten Einfluss auf die Programmier-Regel, die Anzahl der include-Abhängigkeiten möglichst gering zu halten. Durch die Aufnahme eines Headers in precompiled.h, der von vielen, aber längst nicht allen Quelldateien benötigt wird, beschleunigt sich die Kompilation im Allgemeinen! Auch wenn dies also verlockend erscheinen mag, sollte man im Sinne des Software-Engineerings darauf verzichten.

Ansonsten ist der einzige Nachteil vorkompilierter Header der, dass Ihr schöner neuer Rechner, den Sie sich extra zum Kompilieren beschaffen wollten, nun noch lange wird warten müssen. Eine Beschleunigung des Kompilierens um den Faktor zwei bis zehn ist je nach Projekt völlig realistisch.