[C++] Header-Organisation

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

[C++] Header-Organisation

Beitrag von Artificial Mind »

Hallo Community,

ich würde gerne mal wissen, wie Ihr momentan eure C++ Header/Source Files organisiert, um Compile-Zeiten zu minimieren.

Eigene Header für alle Bibliotheken zu schreiben werden wir wahrscheinlich nicht machen können, aber es gibt hoffentlich noch andere Tricks.

Außerdem habe ich gerade http://www.altdevblogaday.com/2012/09/0 ... der-files/ gelesen, wie findet Ihr das?

Cheers
Mind
Florian Keßeler
Beiträge: 75
Registriert: 24.07.2002, 00:00
Wohnort: Bremen
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Florian Keßeler »

Ich finde das nicht so dolle. Ja, man kann sicher kurzfristig ein wenig Compilezeit sparen, aber erstens wird es dadurch unübersichtlich und man hat irgendwann eine 30.000 Zeilen Monsterdatei und spätestens dann ist der Geschwindigkeitsvorteil auch wieder hinüber, wenn jede Quelldatei diese 30.000 Zeilen einbindet.

Außerdem muss man sich über Compilezeiten nicht so viele Sorgen machen, wie es manche tun und deswegen sogar langsameren Code in Kauf nehmen. Es ist ja nicht so, als würde man ständig das ganze Projekt neu übersetzen.
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: [C++] Header-Organisation

Beitrag von Artificial Mind »

Florian Keßeler hat geschrieben:Ich finde das nicht so dolle. Ja, man kann sicher kurzfristig ein wenig Compilezeit sparen, aber erstens wird es dadurch unübersichtlich und man hat irgendwann eine 30.000 Zeilen Monsterdatei und spätestens dann ist der Geschwindigkeitsvorteil auch wieder hinüber, wenn jede Quelldatei diese 30.000 Zeilen einbindet.
Ich bin zwar auch skeptisch, was den Artikel angeht, allerdings sind 30k Zeilen ohne viel Maschinencode (aka Funktionen) glaube ich kein großes Problem für den Compiler.
Florian Keßeler hat geschrieben:Außerdem muss man sich über Compilezeiten nicht so viele Sorgen machen, wie es manche tun und deswegen sogar langsameren Code in Kauf nehmen. Es ist ja nicht so, als würde man ständig das ganze Projekt neu übersetzen.
Wenn man in irgendeiner .cpp was ändert und das Programm erst 5 Minuten später startet, weil Build und Linken von einer Datei im Debug Mode so lange dauert, dann macht das Programmieren keinen Spaß.
Florian Keßeler
Beiträge: 75
Registriert: 24.07.2002, 00:00
Wohnort: Bremen
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Florian Keßeler »

Hab ich noch nicht erlebt, dass eine einzige C++-Datei solange braucht, wenn sie nicht grade irgendwelche Template-Magie betreibt. Und dann hilft auch eine kleinere Header-Datei nicht. Und beim Linken sowieso nicht...
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Krishty »

Artificial Mind hat geschrieben:
Florian Keßeler hat geschrieben:Ich finde das nicht so dolle. Ja, man kann sicher kurzfristig ein wenig Compilezeit sparen, aber erstens wird es dadurch unübersichtlich und man hat irgendwann eine 30.000 Zeilen Monsterdatei und spätestens dann ist der Geschwindigkeitsvorteil auch wieder hinüber, wenn jede Quelldatei diese 30.000 Zeilen einbindet.
Ich bin zwar auch skeptisch, was den Artikel angeht, allerdings sind 30k Zeilen ohne viel Maschinencode (aka Funktionen) glaube ich kein großes Problem für den Compiler.
30k Zeilen sind ein Furz, der nicht einmal einen Sekundenbruchteil dauert. Die meisten Dateien, die <Windows.h> und noch eine Fremdbibliothek einbinden, kommen auf 100k.
Florian Keßeler hat geschrieben:Außerdem muss man sich über Compilezeiten nicht so viele Sorgen machen, wie es manche tun und deswegen sogar langsameren Code in Kauf nehmen. Es ist ja nicht so, als würde man ständig das ganze Projekt neu übersetzen.
Wenn man in irgendeiner .cpp was ändert und das Programm erst 5 Minuten später startet, weil Übersetzen und Linken von einer Datei im Debug Mode so lange dauert, dann macht das Programmieren keinen Spaß.
Bei 5 Minuten ist irgendwas falsch. Ich habe hier ein extrem chaotisches Projekt von mehreren 100k Zeilen, bei dem eine Änderung in einer .cpp trotzdem in 10 Sekunden angewandt ist. Sicher, dass du nicht versehentlich einen Release Build mit globalen Optimierungen machst? Falls du Visual C++ nutzt: Enable Minimal Rebuild ist scheiße und sollte für Enable Multi-Processor Compilation deaktiviert werden.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8267
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Krishty »

Das Problem an den Kompilierzeiten ist, dass sie bei n #includes und m Übersetzungseinheiten im Schnitt mit O(n•m) wachsen. Daran lässt sich bei Standard-konformem Text auch nichts ändern – es ist ein C++ innewohnendes Problem, das nur durch Visual C++’ vorkompilierte Header zu O(n) + O(m) zusammenschrumpft – und darum müssen wir entweder n oder m möglichst kleinkriegen.

Die Anzahl der Übersetzungseinheiten kleinzukriegen ist nicht unbedingt wünschenswert, weil das längere .cpps bedeutet. Das wird nicht nur unübersichtlich, sondern bereitet dann auch noch IntelliSense Probleme (das funktioniert nämlich über vorkompilierte Header).

Nun zu den Headern: Eure Übersetzungseinheiten sind Module, die durch eine Schnittstelle mit anderen Modulen verbunden werden. Diese Schnittstelle ist ein Header.

Die erste Optimierung: Eure Übersetzungseinheit muss nicht die Schnittstelle aller anderen Übersetzungseinheiten einbinden, sondern nur die, die für sie interessant sind. Darum sind Master Headers Irrsinn.

Folgt man der Devise Eine Klasse pro Datei (oder, weil ich kaum noch Klassen benutze, Ein Thema pro Datei), korrelieren wenige Abhängigkeiten der Klassen untereinander also automatisch wenigen Abhängigkeiten der Übersetzungseinheiten untereinander. Das Ziel ist also, die Übersetzungseinheiten möglichst gut zu kapseln, wie auch Klassen in einem Programm möglichst gut gekapselt werden sollen. Damit schrumpfen die Schnittstellen, die eine Übersetzungseinheit einbindet, auf ein Minimum zusammen.

Was viele nicht begreifen ist, dass sich das vor allem, wenn nicht exklusiv, auf Fremdbibliotheken bezieht. Falls ein Header boost voraussetzt, habt ihr boost zur öffentlichen Schnittstelle aller Überstetzungseinheiten deklariert, die diesen Header einbinden. Also mal schnell 50k Zeilen extra für jedes Modul, das diesen Header einbindet. Dasselbe gilt für Direct3D (kaum Müll), die WinAPI (sehr viel Müll), und die STL (viel Müll). Darum: Haltet Fremdbibliotheken aus den Schnittstellen raus.

Das große Problem an den Fremdbibliotheken ist, dass sie keine minimale Schnittstelle anbieten. In vielen Fällen muss man Windows.h einbinden nur, weil man irgendwo ein HANDLE-Attribut in einer Klasse hat, die anderweitig die WinAPI nur in ihrer Implementierung verwendet.

Falls ihr dann keine eigenen Header schreiben könnt, habt ihr einfach Pech gehabt.

Ich liste übrigens gemäß Verzicht auf Master Headers alle #include am Anfang einer Übersetzungseinheit einzeln auf. Es muss seelische Schmerzen bereiten, neue Abhängigkeiten hinzuzufügen, sonst lernt man keine Genügsamkeit.

Das Resultat bei 40k Zeilen in knapp 40 .cpps:
1>
1>Build succeeded.
1>
1>Time Elapsed 00:00:01.17
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
Zuletzt geändert von Krishty am 04.09.2012, 12:07, insgesamt 4-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: [C++] Header-Organisation

Beitrag von Artificial Mind »

Krishty hat geschrieben:
Florian Keßeler hat geschrieben:Außerdem muss man sich über Compilezeiten nicht so viele Sorgen machen, wie es manche tun und deswegen sogar langsameren Code in Kauf nehmen. Es ist ja nicht so, als würde man ständig das ganze Projekt neu übersetzen.
Wenn man in irgendeiner .cpp was ändert und das Programm erst 5 Minuten später startet, weil Übersetzen und Linken von einer Datei im Debug Mode so lange dauert, dann macht das Programmieren keinen Spaß.
Bei 5 Minuten ist irgendwas falsch. Ich habe hier ein extrem chaotisches Projekt von mehreren 100k Zeilen, bei dem eine Änderung in einer .cpp trotzdem in 10 Sekunden angewandt ist. Sicher, dass du nicht versehentlich einen Release Build mit globalen Optimierungen machst? Falls du Visual C++ nutzt: Enable Minimal Rebuild ist scheiße und sollte für Enable Multi-Processor Compilation deaktiviert werden.
Wir benutzen den QtCreator und gcc unter Linux. Bei der entsprechenden Datei ist eine Abhängigkeit auf Qt und Bullet drin, außerdem auf einen OpenGL-Wrapper/High-Level-Grafik-Lib vom Lehrstuhl, die viel mit Templates arbeitet (nicht unbedingt "Magie", aber trotzdem viel). Ich bin mir nicht sicher, wieviele unserer externen Libs gelinkt werden müssen, wenn man was an einer Datei ändert, aber tendentiell ist halt noch ogg, vorbis, lua, slb und glfw mit drin.
Es kann bei uns allerdings sein, dass ein Großteil der Compile-Zeit daher kommt, dass wir Netzwerklaufwerke haben, das müsste ich mal genauer untersuchen.

Gibt es trotzdem irgendwelche Richtlinien, an die man sich halten sollte, um nicht unnötig viel Compile-Zeit zu brauchen (z. B. kein globaler Sammel-Header für alle eigenen Header) und trotzdem einigermaßen angenehm programmieren zu können? (Mit forward declarations kann man es auch übertreiben. Wer schonmal mit VTK gearbeitet hat kennt das ... pro .cpp darf man mindestens 10 weitere VTK-Header einbinden, weil nahezu alles forward deklariert ist, selbst die meisten Rückgabetypen von Funktionen.)

EDIT: Krishty war schneller ;) Danke für die Tipps.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von kimmi »

Ich kann Krishty hier nur zustimmen: spart wo immer es geht. Ab einer gewissen Code-Größe ( so ab 100.000 LOC aufwärts, gel. schon früher ) kann der Aufwand für einen Rebuild signifikant werden. Ich warte hier gerne mal auf einen Build 2-3 Stunden.

Gruß Kimmi
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: [C++] Header-Organisation

Beitrag von kaiserludi »

2-3 Stunden? Das hört sich eher nach 100.000.000 LOC an.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Florian Keßeler
Beiträge: 75
Registriert: 24.07.2002, 00:00
Wohnort: Bremen
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Florian Keßeler »

Und gilt vermutlich nur für einen kompletten Rebuild?
antisteo
Establishment
Beiträge: 854
Registriert: 15.10.2010, 09:26
Wohnort: Dresdem

Re: [C++] Header-Organisation

Beitrag von antisteo »

Florian Keßeler hat geschrieben:Und gilt vermutlich nur für einen kompletten Rebuild?
Um den dreht es sich ja gerade.

Ich persönlich finde, dass allein schon das Übersetzen einer Übersetzungseinheit zu lange dauert.
http://fedoraproject.org/ <-- freies Betriebssystem
http://launix.de <-- kompetente Firma
In allen Posts ist das imo und das afaik inbegriffen.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von kimmi »

Kompletter Rebuild: japp. Und 100.000 aufwärts, nicht 100.000. Allerdings spielen noch andere Dinge hier eine Rolle:
  • Framework mit nicht optimal geschnittenen Interfaces und Abhängigkeiten
  • In die Jahre gekommenes Build-System
  • STL-Includes in öffentlichen Schnittstellen.
  • Viel Inline-Code in Headern
  • Teilweise re-generierter Code, weill man Roundtrips in Rhapsody für eine gute Idee hielt
  • etc.
Man hatte sich nie die Zeit genommen, wirklich etwas zu drehen. Nun arbeiten wir uns gerade an diesen Designschulden ab.

Gruß Kimmi
Florian Keßeler
Beiträge: 75
Registriert: 24.07.2002, 00:00
Wohnort: Bremen
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von Florian Keßeler »

Wie oft macht man schon einen kompletten Rebuild? Alle paar Wochen mal, wenn man nicht grade irgendeinen überall benutzen Header anfasst...
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von kimmi »

Wir hier? Fast täglich, ich etwa alle 3 Tage. Deswegen machen wir den in der Nacht. Gerade für Continuous Integration ist so etwas gängig. Und wenn man generierten Code mit hand-geschriebenen mischt, wollen wir auf Debugging-Sessions ausgelöst von durch fehlerhaften Artefakten auf embedded Devices per Remote-Debugging gern verzichten. Und bei gewissen sicherheits-relevanten Dingen ist das von den Normen sogar gefordert. Und es ist etwas vollkommen anderes, ob man allein oder in einem sehr großen Team arbeitet.
Diese Probleme sind übrigens nicht nur bei uns alltäglich, andere Unternehmen haben den Build in c++ ebenfalls als Hemmschuh vor Jahren schon erkannt und setzen hier nicht ohne Grund die besten Leute ein: Google zum Beispiel.

Gruß Kimmi
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: [C++] Header-Organisation

Beitrag von kaiserludi »

Florian Keßeler hat geschrieben:Wie oft macht man schon einen kompletten Rebuild? Alle paar Wochen mal, wenn man nicht grade irgendeinen überall benutzen Header anfasst...
In VS? Eigentlich nur, wenn das Buildfile ich ein neues Release packagen lasse.
In anderen IDEs? Oft mehrmals stündlich, weil das oft die einzige praktikable Möglichkeit ist, der IDE zu sagen, dass ich die statische Lib neu gebaut habe und entsprechend die App, mit der ich die Änderung testen will, gefälligst auch die neue Version der Lib nutzen soll.


Habe hier auch eine Solution, die mittlerweile eher in der Größenordnung 500.000 Lines of Code ist, Templates ohne Ende, 3 verschiedene Programmiersprachen, über 50 Projekte, ein Rebuild der gesamten Solution dauert 35 Sekunden, obwohl sich nie wer darum gekümmert hat, die Builddauer zu optimieren.
Das Geheimnis:
Keine WinAPI, keine STL, kein DirectX, kein Boost 8-)

Wenn ich ein Release mache, dauert der Build der nötigen Packages allerdings dennoch über eine Stunde, da 6 Plattformen, bis zu 3 Architekturen pro Platform, alles jeweils Debug und Release und das für 9 Libs und 6 Demos + Dokugeneration und automatisches Durchlaufen der Tests auf mehreren Plattformen in mehren Sprachen, dann Files umherkkopieren und zippen für 2 alternative Packages pro Plattform, da bräuchte unser Buildsystem wohl einen Monat für, wenn ein Rebuild bei mir so lange dauern würde wie bei euch :mrgreen:
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Header-Organisation

Beitrag von kimmi »

In unserem Rebuild sind Debug + Release für mehrere Plattformen ebenfalls enthalten. Allerdings glaube ich, wir haben die Mio. Grenze schon x-fach überschritten. Und viel Zeit geht auch wirklich über ein veraltetes Build-System von dannen. UNd unsere Infrastruktur ist ebenfalls nicht so dolle.
Anders formuliert: wir haben noch Platz nach oben :).

Gruß Kimmi
Antworten