it-swarm.com.de

Welche Techniken können verwendet werden, um die C ++ - Kompilierungszeiten zu beschleunigen?

Welche Techniken können verwendet werden, um die C++ - Kompilierungszeiten zu beschleunigen?

Diese Frage tauchte in einigen Kommentaren zur Stapelüberlauf-Frage C++ - Programmierstil auf, und ich bin interessiert, welche Ideen es gibt sind.

Ich habe eine verwandte Frage gesehen, Warum dauert die C++ - Kompilierung so lange?, aber das bietet nicht viele Lösungen .


Stimmen Sie hier ab, wenn Visual Studio die Freigabe vorkompilierter Header zwischen Projekten unterstützt

236
Scott Langham

Sprachtechniken

Pimpl Idiom

Schauen Sie sich das Pimpl-Idiomhier und hier an , auch bekannt als ndurchsichtiger Zeiger oder handle Klassen. Dies beschleunigt nicht nur die Kompilierung, sondern erhöht auch die Ausnahmesicherheit in Kombination mit der Funktion nicht werfender Tausch . Mit dem Pimpl-Idiom können Sie die Abhängigkeiten zwischen den Kopfzeilen verringern und den Neukompilierungsaufwand verringern.

Erklärungen weiterleiten

Verwenden Sie nach Möglichkeit Forward-Deklarationen . Wenn der Compiler nur wissen muss, dass SomeIdentifier eine Struktur oder ein Zeiger oder was auch immer ist, schließen Sie nicht die gesamte Definition ein, und zwingen Sie den Compiler, mehr Arbeit zu leisten als nötig. Dies kann einen Kaskadeneffekt haben, wodurch der Vorgang langsamer als erforderlich wird.

Die Ströme I/O sind besonders dafür bekannt, Builds zu verlangsamen. Wenn Sie sie in einer Header-Datei benötigen, versuchen Sie, #including <iosfwd> anstatt <iostream> und #include the <iostream> Header nur in der Implementierungsdatei. Das <iosfwd> Header enthält nur Forward-Deklarationen. Leider haben die anderen Standardheader keinen entsprechenden Deklarationsheader.

Bevorzugen Sie die Referenzübergabe gegenüber der Wertübergabe bei Funktionssignaturen. Dadurch müssen Sie die entsprechenden Typdefinitionen nicht mehr in die Header-Datei aufnehmen, und Sie müssen den Typ nur noch weiterleiten. Natürlich bevorzugen Sie konstante Verweise gegenüber nicht konstanten Verweisen, um unklare Fehler zu vermeiden, aber dies ist ein Problem für eine andere Frage.

Wachbedingungen

Verwenden Sie Schutzbedingungen, um zu verhindern, dass Header-Dateien mehrmals in einer einzelnen Übersetzungseinheit enthalten sind.

#pragma once
#ifndef filename_h
#define filename_h

// Header declarations / definitions

#endif

Indem Sie sowohl das Pragma als auch das ifndef verwenden, erhalten Sie die Portabilität der einfachen Makrolösung sowie die Optimierung der Kompilierungsgeschwindigkeit, die einige Compiler in Gegenwart des pragma once Richtlinie.

Reduzieren Sie die gegenseitige Abhängigkeit

Je modularer und weniger voneinander abhängig Ihr Code-Design im Allgemeinen ist, desto seltener müssen Sie alles neu kompilieren. Sie können auch den Arbeitsaufwand reduzieren, den der Compiler für einen einzelnen Block gleichzeitig leisten muss, da er weniger Zeit hat, um den Überblick zu behalten.

Compiler-Optionen

Vorkompilierte Header

Diese werden verwendet, um einen gemeinsamen Abschnitt der enthaltenen Überschriften für viele Übersetzungseinheiten einmal zu kompilieren. Der Compiler kompiliert es einmal und speichert seinen internen Zustand. Dieser Status kann dann schnell geladen werden, um einen Vorsprung beim Kompilieren einer anderen Datei mit derselben Gruppe von Headern zu erlangen.

Achten Sie darauf, dass Sie nur selten geänderte Inhalte in die vorkompilierten Header aufnehmen, da Sie sonst häufiger als nötig vollständige Neuerstellungen durchführen können. Dies ist ein guter Ort für STL Header und andere Bibliothek-Include-Dateien.

ccache ist ein weiteres Dienstprogramm, das Caching-Techniken nutzt, um die Dinge zu beschleunigen.

Verwenden Sie Parallelität

Viele Compiler/IDEs unterstützen die gleichzeitige Kompilierung mehrerer Cores/CPUs. Verwenden Sie in GNU Make (normalerweise mit GCC verwendet) das -j [N] Möglichkeit. In Visual Studio gibt es unter Einstellungen eine Option, mit der mehrere Projekte gleichzeitig erstellt werden können. Sie können auch die /MP Option für Paralellismus auf Dateiebene, anstatt nur für Paralellismus auf Projektebene.

Andere parallele Dienstprogramme:

Verwenden Sie eine niedrigere Optimierungsstufe

Je mehr der Compiler zu optimieren versucht, desto schwerer muss es arbeiten.

Shared Libraries

Das Verschieben Ihres weniger häufig geänderten Codes in Bibliotheken kann die Kompilierungszeit verkürzen. Mithilfe von gemeinsam genutzten Bibliotheken (.so oder .dll) können Sie auch die Verbindungszeit verkürzen.

Holen Sie sich einen schnelleren Computer

Mehr RAM, schnellere Festplatten (einschließlich SSDs) und mehr CPUs/Kerne sorgen für eine schnellere Kompilierung.

246
Eclipse

Ich arbeite am STAPL-Projekt, bei dem es sich um eine stark vorgefertigte C++ - Bibliothek handelt. Hin und wieder müssen wir alle Techniken überprüfen, um die Kompilierungszeit zu verkürzen. Hier habe ich die Techniken zusammengefasst, die wir verwenden. Einige dieser Techniken sind bereits oben aufgeführt:

Finden Sie die zeitaufwändigsten Abschnitte

Obwohl es keine nachgewiesene Korrelation zwischen Symbollängen und Kompilierungszeit gibt, haben wir festgestellt, dass kleinere durchschnittliche Symbolgrößen die Kompilierungszeit auf allen Compilern verbessern können. So ist es Ihr erstes Ziel, die größten Symbole in Ihrem Code zu finden.

Methode 1 - Sortieren Sie die Symbole nach der Größe

Sie können den Befehl nm verwenden, um die Symbole nach ihrer Größe aufzulisten:

nm --print-size --size-sort --radix=d YOUR_BINARY

In diesem Befehl können Sie mit --radix=d Die Größen in Dezimalzahlen anzeigen (Standard ist Hex). Sehen Sie sich nun das größte Symbol an, und ermitteln Sie, ob Sie die entsprechende Klasse aufteilen und neu gestalten können, indem Sie die nicht mit Vorlagen versehenen Teile in eine Basisklasse einbeziehen oder die Klasse in mehrere Klassen aufteilen.

Methode 2 - Sortieren Sie die Symbole nach Länge

Sie können den regulären Befehl nm ausführen und an Ihr Lieblingsskript weiterleiten ( AWK , Python usw. ), um die Symbole nach ihrer Länge zu sortieren. Basierend auf unserer Erfahrung identifiziert diese Methode die größten Probleme, die Kandidaten besser machen als Methode 1.

Methode 3 - Verwenden Sie Templight

" Templight ist ein Clang - basiertes Tool, um die Zeit und den Speicherverbrauch von Template-Instantiierungen zu analysieren und interaktive Debugging-Sitzungen durchzuführen, um einen Einblick in den Template-Instantiierungsprozess zu erhalten".

Sie können Templight installieren, indem Sie LLVM und Clang ( Anweisungen ) auschecken und den Templight-Patch darauf anwenden. Die Standardeinstellung für LLVM und Clang ist Debugging und Assertions. Dies kann sich erheblich auf Ihre Kompilierungszeit auswirken. Templight benötigt anscheinend beides, daher müssen Sie die Standardeinstellungen verwenden. Die Installation von LLVM und Clang sollte ungefähr eine Stunde dauern.

Nach dem Anwenden des Patches können Sie templight++ Verwenden, das sich in dem bei der Installation angegebenen Erstellungsordner befindet, um Ihren Code zu kompilieren.

Stellen Sie sicher, dass sich templight++ In Ihrem PFAD befindet. Fügen Sie nun zum Kompilieren die folgenden Schalter zu Ihrem CXXFLAGS in Ihrem Makefile oder zu Ihren Befehlszeilenoptionen hinzu:

CXXFLAGS+=-Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system

Oder

templight++ -Xtemplight -profiler -Xtemplight -memory -Xtemplight -ignore-system

Nachdem die Kompilierung abgeschlossen ist, werden im selben Ordner ein .trace.memory.pbf und ein .trace.pbf erstellt. Um diese Spuren zu visualisieren, können Sie die Templight Tools verwenden, die diese in andere Formate konvertieren können. Befolgen Sie diese Anweisungen , um templight-convert zu installieren. Wir verwenden normalerweise die Callgrind-Ausgabe. Sie können die GraphViz-Ausgabe auch verwenden, wenn Ihr Projekt klein ist:

$ templight-convert --format callgrind YOUR_BINARY --output YOUR_BINARY.trace

$ templight-convert --format graphviz YOUR_BINARY --output YOUR_BINARY.dot

Die generierte Callgrind-Datei kann mit kcachegrind geöffnet werden, wobei Sie die zeit- und speicherintensivste Instanziierung verfolgen können.

Reduzierung der Anzahl der Template-Instantiierungen

Obwohl es keine genaue Lösung für die Reduzierung der Anzahl der Vorlageninstanziierungen gibt, gibt es einige Richtlinien, die helfen können:

Refaktorklassen mit mehr als einem Vorlagenargument

Wenn Sie zum Beispiel eine Klasse haben,

template <typename T, typename U>
struct foo { };

und sowohl T als auch U können 10 verschiedene Optionen haben. Sie haben die möglichen Template-Instanziierungen dieser Klasse auf 100 erhöht. Eine Möglichkeit, dies zu beheben, besteht darin, den gemeinsamen Teil des Codes zu abstrahieren eine andere Klasse. Die andere Methode ist die Inversion der Vererbung (Umkehren der Klassenhierarchie). Stellen Sie jedoch sicher, dass Ihre Entwurfsziele nicht beeinträchtigt werden, bevor Sie diese Technik verwenden.

Refactor-Code ohne Vorlage für einzelne Übersetzungseinheiten

Mit dieser Technik können Sie den allgemeinen Abschnitt einmal kompilieren und später mit Ihren anderen TUs (Übersetzungseinheiten) verknüpfen.

Externe Template-Instanziierungen verwenden (seit C++ 11)

Wenn Sie alle möglichen Instanzen einer Klasse kennen, können Sie mit dieser Technik alle Fälle in einer anderen Übersetzungseinheit kompilieren.

Zum Beispiel in:

enum class PossibleChoices = {Option1, Option2, Option3}

template <PossibleChoices pc>
struct foo { };

Wir wissen, dass diese Klasse drei mögliche Instanzen haben kann:

template class foo<PossibleChoices::Option1>;
template class foo<PossibleChoices::Option2>;
template class foo<PossibleChoices::Option3>;

Fügen Sie das Obige in eine Übersetzungseinheit ein und verwenden Sie das Schlüsselwort extern in Ihrer Header-Datei unterhalb der Klassendefinition:

extern template class foo<PossibleChoices::Option1>;
extern template class foo<PossibleChoices::Option2>;
extern template class foo<PossibleChoices::Option3>;

Mit dieser Technik können Sie Zeit sparen, wenn Sie verschiedene Tests mit einem gemeinsamen Satz von Instanziierungen kompilieren.

HINWEIS: MPICH2 ignoriert zu diesem Zeitpunkt die explizite Instanziierung und kompiliert immer die instanziierten Klassen in allen Kompilierungseinheiten.

Verwenden Sie Unity Builds

Die Idee hinter Unity Builds besteht darin, alle von Ihnen verwendeten .cc-Dateien in eine Datei aufzunehmen und diese Datei nur einmal zu kompilieren. Mit dieser Methode können Sie vermeiden, gemeinsame Abschnitte verschiedener Dateien erneut zu aktivieren, und wenn Ihr Projekt viele gemeinsame Dateien enthält, würden Sie wahrscheinlich auch Festplattenzugriffe sparen.

Nehmen wir als Beispiel an, Sie haben drei Dateien foo1.cc, foo2.cc, foo3.cc Und alle enthalten Tuple from STL . Sie können einen foo-all.cc Erstellen, der wie folgt aussieht:

#include "foo1.cc"
#include "foo2.cc"
#include "foo3.cc"

Sie kompilieren diese Datei nur einmal und reduzieren möglicherweise die allgemeinen Instanziierungen zwischen den drei Dateien. Es ist schwer allgemein vorherzusagen, ob die Verbesserung signifikant sein kann oder nicht. Eine offensichtliche Tatsache ist jedoch, dass Sie die Parallelität in Ihren Builds verlieren würden (Sie können die drei Dateien nicht mehr gleichzeitig kompilieren).

Wenn eine dieser Dateien sehr viel Speicherplatz beansprucht, ist möglicherweise tatsächlich kein Speicher mehr verfügbar, bevor die Kompilierung abgeschlossen ist. Bei einigen Compilern, z. B. GCC , kann dies zu einem ICE (Internal Compiler Error) Ihres Compilers führen, da nicht genügend Arbeitsspeicher vorhanden ist. Wenden Sie diese Technik nur an, wenn Sie alle Vor- und Nachteile kennen.

Vorkompilierte Header

Vorkompilierte Header (PCHs) können Ihnen beim Kompilieren viel Zeit sparen, indem Sie Ihre Header-Dateien zu einer vom Compiler erkennbaren Zwischendarstellung kompilieren. Um vorkompilierte Header-Dateien zu generieren, müssen Sie Ihre Header-Datei nur mit Ihrem regulären Kompilierungsbefehl kompilieren. Zum Beispiel auf GCC:

$ g++ YOUR_HEADER.hpp

Dies erzeugt einen YOUR_HEADER.hpp.gch file (.gch Ist die Erweiterung für PCH-Dateien in GCC) im selben Ordner. Wenn Sie also YOUR_HEADER.hpp In eine andere Datei einfügen, verwendet der Compiler Ihr YOUR_HEADER.hpp.gch Anstelle von YOUR_HEADER.hpp In demselben Ordner wie zuvor.

Es gibt zwei Probleme mit dieser Technik:

  1. Sie müssen sicherstellen, dass die Header-Dateien, die vorkompiliert werden, stabil sind und sich nicht ändern ( Sie können Ihr Makefile jederzeit ändern )
  2. Sie können nur einen PCH pro Kompilierungseinheit einschließen (bei den meisten Compilern). Dies bedeutet, dass Sie mehrere Header-Dateien, die vorkompiliert werden sollen, in eine Datei aufnehmen müssen (z. B. all-my-headers.hpp). Das bedeutet aber, dass Sie die neue Datei an allen Stellen einfügen müssen. Zum Glück hat GCC eine Lösung für dieses Problem. Verwenden Sie -include Und geben Sie ihm die neue Header-Datei. Mit dieser Technik können Sie verschiedene Dateien durch Kommas trennen.

Beispielsweise:

g++ foo.cc -include all-my-headers.hpp

Verwenden Sie unbenannte oder anonyme Namespaces

nbenannte Namespaces (a.k.a. anonyme Namespaces) kann die generierten Binärgrößen erheblich reduzieren. Unbenannte Namespaces verwenden interne Verknüpfungen, was bedeutet, dass die in diesen Namespaces generierten Symbole für andere TU (Übersetzungs- oder Kompilierungseinheiten)) nicht sichtbar sind Du hast eine Datei foo.hpp:

namespace {

template <typename T>
struct foo { };
} // Anonymous namespace
using A = foo<int>;

Und Sie fügen diese Datei zufällig in zwei TUs ein (zwei .cc-Dateien und kompilieren sie separat). Die beiden Instanzen der foo-Vorlage sind nicht identisch. Dies verstößt gegen die One Definition Rule (ODR). Aus dem gleichen Grund wird von der Verwendung unbenannter Namespaces in den Header-Dateien abgeraten. Sie können sie auch in Ihren .cc - Dateien verwenden, um zu vermeiden, dass Symbole in Ihren Binärdateien angezeigt werden. In einigen Fällen führte das Ändern aller internen Details für eine .cc - Datei zu einer Reduzierung der generierten Binärgrößen um 10%.

Sichtbarkeitsoptionen ändern

In neueren Compilern können Sie Ihre Symbole so auswählen, dass sie in den Dynamic Shared Objects (DSOs) entweder sichtbar oder unsichtbar sind. Wenn Sie die Sichtbarkeit ändern, können Sie im Idealfall die Compilerleistung verbessern, die Verbindungszeit optimieren (LTOs) und Binärgrößen generieren. Wenn Sie sich die STL-Header-Dateien in GCC ansehen, können Sie feststellen, dass sie weit verbreitet sind. Um Sichtbarkeitsoptionen zu aktivieren, müssen Sie Ihren Code pro Funktion, pro Klasse, pro Variable und vor allem pro Compiler ändern.

Mithilfe der Sichtbarkeit können Sie die Symbole, die Sie als privat betrachten, für die generierten freigegebenen Objekte ausblenden. In GCC können Sie die Sichtbarkeit von Symbolen steuern, indem Sie die Option -visibility Ihres Compilers als Standard oder ausgeblendet angeben. Dies ähnelt in gewissem Sinne dem unbenannten Namespace, ist jedoch aufwändiger und aufdringlicher.

Wenn Sie die Sichtbarkeiten pro Fall festlegen möchten, müssen Sie Ihren Funktionen, Variablen und Klassen die folgenden Attribute hinzufügen:

__attribute__((visibility("default"))) void  foo1() { }
__attribute__((visibility("hidden")))  void  foo2() { }
__attribute__((visibility("hidden")))  class foo3   { };
void foo4() { }

Die Standardsichtbarkeit in GCC ist default (public), dh wenn Sie die oben genannte Methode als Shared Library (-shared) Kompilieren, sind foo2 Und die Klasse foo3 Nicht sichtbar in anderen TUs (foo1 und foo4 werden angezeigt). Wenn Sie mit -visibility=hidden Kompilieren, wird nur foo1 Angezeigt. Sogar foo4 Wäre versteckt.

Weitere Informationen zur Sichtbarkeit finden Sie unter GCC-Wiki .

35
Mani Zandifar

Ich würde diese Artikel von "Games from Within, Indie Game Design und Programmierung" empfehlen:

Zugegeben, sie sind ziemlich alt - Sie müssen alles mit den neuesten Versionen (oder Versionen, die Ihnen zur Verfügung stehen) erneut testen, um realistische Ergebnisse zu erzielen. In jedem Fall ist es eine gute Quelle für Ideen.

31
Paulius

Eine Technik, die in der Vergangenheit ganz gut funktioniert hat: Kompilieren Sie nicht mehrere C++ - Quelldateien unabhängig voneinander, sondern generieren Sie eine C++ - Datei, die alle anderen Dateien enthält, wie folgt:

// myproject_all.cpp
// Automatically generated file - don't edit this by hand!
#include "main.cpp"
#include "mainwindow.cpp"
#include "filterdialog.cpp"
#include "database.cpp"

Dies bedeutet natürlich, dass Sie den gesamten enthaltenen Quellcode neu kompilieren müssen, falls sich eine der Quellen ändert, damit sich der Abhängigkeitsbaum verschlechtert. Das Kompilieren mehrerer Quelldateien zu einer Übersetzungseinheit ist jedoch schneller (zumindest in meinen Experimenten mit MSVC und GCC) und generiert kleinere Binärdateien. Ich vermute auch, dass der Compiler mehr Optimierungspotential hat (da er mehr Code auf einmal sehen kann).

Diese Technik bricht in verschiedenen Fällen ab; Der Compiler kann beispielsweise aussteigen, wenn zwei oder mehr Quelldateien eine globale Funktion mit demselben Namen deklarieren. Ich konnte diese Technik in keiner der anderen Antworten finden, deshalb erwähne ich sie hier.

Für das, was es wert ist, verwendete das KDE-Projekt genau dieselbe Technik seit 1999, um optimierte Binärdateien zu erstellen (möglicherweise für eine Veröffentlichung). Der Wechsel zum Build-Konfigurationsskript hatte den Namen --enable-final. Aus archäologischen Gründen habe ich den Beitrag ausgegraben, in dem dieses Feature angekündigt wurde: http://lists.kde.org/?l=kde-devel&m=92722836009368&w=2

16
Frerich Raabe

Zu diesem Thema gibt es ein ganzes Buch mit dem Titel C++ - Software-Design im großen Maßstab (geschrieben von John Lakos).

Das Buch datiert Vorlagen vor. Fügen Sie daher zum Inhalt dieses Buches "Auch die Verwendung von Vorlagen kann den Compiler verlangsamen" hinzu.

15
ChrisW

Ich werde nur auf meine andere Antwort verweisen: Wie können Sie die Kompilierungszeit und die Verknüpfungszeit für Visual C++ - Projekte (natives C++) verringern?. Ein weiterer Punkt, den ich hinzufügen möchte, der jedoch häufig Probleme verursacht, ist die Verwendung vorkompilierter Header. Verwenden Sie sie jedoch nur für Teile, die sich kaum ändern (z. B. GUI-Toolkit-Header). Andernfalls kosten Sie mehr Zeit als Sie am Ende sparen.

Wenn Sie mit GNU make arbeiten, können Sie auch die Option -j<N> aktivieren:

  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg.

Normalerweise habe ich es bei 3, da ich hier einen Doppelkern habe. Anschließend werden Compiler für verschiedene Übersetzungseinheiten parallel ausgeführt, sofern zwischen ihnen keine Abhängigkeiten bestehen. Eine parallele Verknüpfung ist nicht möglich, da nur ein Linker alle Objektdateien miteinander verknüpft.

Aber der Linker selbst kann eingefädelt werden, und dies ist der GNU gold[~ # ~] elf [~ # ~] Linker tut. Es handelt sich um optimierten Thread-C++ - Code, der ELF-Objektdateien um eine Größenordnung schneller als die alten ld verknüpfen soll (und tatsächlich in binutils enthalten war).

Wenn Sie alle oben genannten Code-Tricks angewendet haben (Forward-Deklarationen, Reduzierung der Header-Inklusion auf das Minimum in öffentlichen Headern, Verschieben der meisten Details in der Implementierungsdatei mit Pimpl ...) und nichts anderes kann mehr erreicht werden Betrachten Sie Ihr Build-System. Wenn Sie Linux verwenden, ziehen Sie die Verwendung von distcc (Distributed Compiler) und ccache (Cache-Compiler) in Betracht.

Der erste, distcc, führt den Präprozessor-Schritt lokal aus und sendet die Ausgabe an den ersten verfügbaren Compiler im Netzwerk. Es erfordert die gleichen Compiler- und Bibliotheksversionen auf allen konfigurierten Knoten im Netzwerk.

Letzteres, ccache, ist ein Compiler-Cache. Es führt den Präprozessor erneut aus und prüft dann mit einer internen Datenbank (die sich in einem lokalen Verzeichnis befindet), ob diese Präprozessor-Datei bereits mit denselben Compiler-Parametern kompiliert wurde. In diesem Fall wird nur die Binärdatei angezeigt und die Ausgabe beim ersten Start des Compilers ausgegeben.

Beide können gleichzeitig verwendet werden, sodass ccache, wenn keine lokale Kopie vorhanden ist, diese über das Netz an einen anderen Knoten mit distcc senden oder die Lösung einfach ohne weitere Verarbeitung injizieren kann.

Hier sind einige:

  • Verwenden Sie alle Prozessorkerne, indem Sie einen Mehrfachkompilierungsjob starten (make -j2 Ist ein gutes Beispiel).
  • Deaktivieren Sie Optimierungen oder verringern Sie diese (zum Beispiel ist GCC mit -O1 Viel schneller als mit -O2 Oder -O3).
  • Verwenden Sie vorkompilierte Header .
11
Milan Babuškov

Als ich das College verließ, hatte der erste echte produktionswürdige C++ - Code, den ich sah, diese geheimen #ifndef ... #endif-Direktiven zwischen sich, in denen die Header definiert wurden. Ich fragte den Mann, der den Code über diese übergeordneten Dinge auf sehr naive Weise schrieb und wurde in die Welt der groß angelegten Programmierung eingeführt.

Um noch einmal auf den Punkt zurückzukommen: Das Verwenden von Direktiven, um doppelte Header-Definitionen zu vermeiden, war das erste, was ich gelernt habe, wenn es darum ging, die Kompilierzeiten zu verkürzen.

9
questzen

Mehr RAM.

Jemand sprach über RAM Laufwerke in einer anderen Antwort. Ich tat dies mit einem 80286 und Turbo C++ (zeigt Alter) und die Ergebnisse waren phänomenal Ebenso wie der Datenverlust beim Absturz der Maschine.

8
mr calendar

Sie könnten nity Builds verwenden.

Für den Fall, dass Sie nicht mehr weiterkommen möchten

6
OJ.

Verwenden Sie Forward-Deklarationen, wo Sie können. Wenn eine Klassendeklaration nur einen Zeiger oder eine Referenz auf einen Typ verwendet, können Sie diese einfach weiterleiten und den Header für den Typ in die Implementierungsdatei aufnehmen.

Beispielsweise:

// T.h
class Class2; // Forward declaration

class T {
public:
    void doSomething(Class2 &c2);
private:
    Class2 *m_Class2Ptr;
};

// T.cpp
#include "Class2.h"
void Class2::doSomething(Class2 &c2) {
    // Whatever you want here
}

Weniger Einschlüsse bedeuten weitaus weniger Arbeit für den Präprozessor, wenn Sie dies ausreichend tun.

6
Evan Teran

Der Vollständigkeit halber: Ein Build kann langsam sein, da das Build-System sowohl dumm ist als auch der Compiler viel Zeit für seine Arbeit benötigt.

Lesen Sie Rekursiv Als schädlich einstufen (PDF), um eine Erläuterung dieses Themas in Unix-Umgebungen zu erhalten.

5
dmckee

Verwenden

#pragma once

wenn die Header-Dateien mehrmals in einer Übersetzungseinheit enthalten sind, wird der Text des Headers nur einmal eingeschlossen und analysiert.

5
Scott Langham

Ich hatte eine Idee über mit einem RAM Laufwerk . Es stellte sich heraus, dass es für meine Projekte keinen großen Unterschied macht. Aber dann sind sie es Ich würde gerne hören, wie sehr es geholfen hat.

4
Vilx-
  • Rüsten Sie Ihren Computer auf

    1. Holen Sie sich einen Quad-Core (oder ein Dual-Quad-System)
    2. Holen Sie sich viel RAM.
    3. Verwenden Sie ein RAM Laufwerk, um die Verzögerung der Datei-E/A drastisch zu reduzieren. (Es gibt Unternehmen, die IDE und SATA RAM) Laufwerke, die sich wie Festplatten verhalten).
  • Dann haben Sie alle Ihre anderen typischen Vorschläge

    1. Verwenden Sie vorkompilierte Header, falls verfügbar.
    2. Reduzieren Sie das Ausmaß der Kopplung zwischen Teilen Ihres Projekts. Das Ändern einer Header-Datei sollte normalerweise kein erneutes Kompilieren des gesamten Projekts erfordern.
4
Uhall

Nicht über die Kompilierungszeit, sondern über die Erstellungszeit:

  • Verwenden Sie ccache, wenn Sie dieselben Dateien neu erstellen müssen, wenn Sie an Ihren Build-Dateien arbeiten

  • Verwenden Sie Ninja-Build anstelle von make. Ich kompiliere gerade ein Projekt mit ~ 100 Quelldateien und alles wird von ccache zwischengespeichert. Mache braucht 5 Minuten, Ninja weniger als 1.

Sie können Ihre Ninja-Dateien aus cmake mit -GNinja Generieren.

3
thi gg

Wo verbringst du deine Zeit? Sind Sie CPU gebunden? Speicher gebunden? Festplatte gebunden? Können Sie mehr Kerne verwenden? Mehr RAM? Benötigen Sie RAID? Möchten Sie einfach die Effizienz Ihres aktuellen Systems verbessern?

.

Haben Sie sich unter gcc/g ++ ccache angesehen? Es kann hilfreich sein, wenn Sie make_clean _; _ viel machen.

3
Mr.Ree

Dynamische Verknüpfungen (.so) können sehr viel schneller sein als statische Verknüpfungen (.a). Besonders wenn Sie ein langsames Netzlaufwerk haben. Dies liegt daran, dass Sie den gesamten Code in der .a-Datei haben, der verarbeitet und ausgeschrieben werden muss. Außerdem muss eine viel größere ausführbare Datei auf die Festplatte geschrieben werden.

3
Juan

Netzwerkfreigaben verlangsamen Ihren Build drastisch, da die Suchwartezeit hoch ist. Für so etwas wie Boost hat es einen großen Unterschied für mich gemacht, obwohl unser Netzwerklaufwerk ziemlich schnell ist. Die Zeit zum Kompilieren eines Toy Boost-Programms ging von etwa 1 Minute auf 1 Sekunde zurück, als ich von einer Netzwerkfreigabe zu einer lokalen SSD wechselte.

2
Mark Lakata

Unter Linux (und vielleicht einigen anderen * NIXen) können Sie die Kompilierung wirklich beschleunigen, indem Sie NOT STARING am Ausgang ausführen und zu another TTY wechseln.

Hier ist das Experiment: printf verlangsamt mein Programm

2
Flavius

Wenn Sie einen Multicore-Prozessor haben, unterstützen sowohl Visual Studio (2005 und höher) als auch GCC Multiprozessor-Kompilierungen. Es ist etwas zu aktivieren, wenn Sie die Hardware haben, sicher.

2
archimedes

Schnellere Festplatten.

Compiler schreiben viele (und möglicherweise riesige) Dateien auf die Festplatte. Arbeiten Sie mit SSD anstelle einer typischen Festplatte, und die Kompilierungszeiten sind viel geringer.

2
linello

Obwohl keine "Technik", konnte ich nicht herausfinden, wie Win32-Projekte mit vielen Quelldateien schneller kompiliert wurden als mein leeres Projekt "Hello World". Daher hoffe ich, dass dies jemandem hilft, wie es mir gelungen ist.

In Visual Studio ist Incremental Linking (/ INCREMENTAL) eine Option zum Erhöhen der Kompilierzeiten. Es ist nicht kompatibel mit der Link-Time-Code-Generierung (/ LTCG). Denken Sie also daran, die inkrementelle Verknüpfung zu deaktivieren, wenn Sie Release-Builds ausführen.

1
Nathan Goings