C++ Modules
C++ Modules
Hey,
hat schon jemand Erfahrung mit C++ Modulen gesammelnt? Es scheint ja zumindest ansatzweise in VC 2017 implementiert zu sein, ich habe vor längerem mal ein Video dazu gesehen, und frage mich, inwieweit das schon benutzbar ist.
https://blogs.msdn.microsoft.com/vcblog ... udio-2017/
hat schon jemand Erfahrung mit C++ Modulen gesammelnt? Es scheint ja zumindest ansatzweise in VC 2017 implementiert zu sein, ich habe vor längerem mal ein Video dazu gesehen, und frage mich, inwieweit das schon benutzbar ist.
https://blogs.msdn.microsoft.com/vcblog ... udio-2017/
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Habe es zur Zeit des Blog-Posts genutzt. Benutzbar sind sie mit der Einschränkung, dass du exakt in der richtigen Reihenfolge kompilieren musst (indem die Module in alphabetisch sortierten Namen vorliegen und das Kompilieren auf einen CPU-Kern beschränkt ist). Das war mir ein Bisschen viel Aufwand, und dann habe ich sie zur Seite gelegt.
Keine Ahnung, wie weit sie heute sind. Ich möchte sie auch unbedingt in der nächsten Zeit wieder testen.
Keine Ahnung, wie weit sie heute sind. Ich möchte sie auch unbedingt in der nächsten Zeit wieder testen.
Re: C++ Modules
1.5 Jahre später. Ich überlege fast, sie mir nochmal anzusehen. Hat in der Zwischenzeit jemand damit Erfahrung gesammelt?
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Ich nicht. Bin vor allem daran interessiert, ob MSBuild nun endlich die Build-Reihenfolge auf die Kette kriegt … sonst lohnt sich das Ausprobieren gar nicht.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Ein Jahr nach meinem letzten Experiment. Visual Studio 2019 16.5.0 Preview 1.0 erkennt noch immer nicht die korrekte Reihenfolge der Abhängigkeiten; also noch immer unbrauchbar.
Ein halbwegs praktisch einsetzbarer Weg ist, die .vcxproj-Datei von Hand zu ändern, so dass alle Module in der korrekten Reihenfolge eingetragen sind. Dann muss allerdings auch parallele Kompilierung abgeschaltet werden. Bei dem Vergleich 12 Threads mit Headern gegen einen Thread mit Modules gewinnt nunmal die Header-Variante.
Ein halbwegs praktisch einsetzbarer Weg ist, die .vcxproj-Datei von Hand zu ändern, so dass alle Module in der korrekten Reihenfolge eingetragen sind. Dann muss allerdings auch parallele Kompilierung abgeschaltet werden. Bei dem Vergleich 12 Threads mit Headern gegen einen Thread mit Modules gewinnt nunmal die Header-Variante.
Re: C++ Modules
Vielen Dank für das Update, auch wenn es eher deprimierend ausfällt. Ugh...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Besserung ist absehbar: https://devblogs.microsoft.com/cppblog/ ... sion-16-7/
Ich muss noch testen, ob diese Information nun endlich in MSBuild verwertet wird.
Ich muss noch testen, ob diese Information nun endlich in MSBuild verwertet wird.
Re: C++ Modules
Habe die Hoffnung relativ aufgegeben. Vielleicht in 10 Jahren.
Also ich mache alle meine neuen Abhängigkeiten als Header-Only, dann habe ich quasi Module.
D.h. alle Funktionen/Variablen werden inline, static inline, constexpr und/oder sind templates.
Dann einfach #include und fertig.
Ich habe nur noch eine main.cpp, alles andere sind *.h
Module dauern einfach zu lange... macht keinen Sinn zu warten.
Ansonsten auch einfach D benutzen, die haben seit Jahren ordentliche Module und generieren den Code ja letztlich auch über LLVM, ist also auch schnell - und da kann man auch die Abhängigkeiten zwischen Klassen definieren, anstatt zwischen Files - das wird nie was ordentliches werden in C++.
Also ich mache alle meine neuen Abhängigkeiten als Header-Only, dann habe ich quasi Module.
D.h. alle Funktionen/Variablen werden inline, static inline, constexpr und/oder sind templates.
Dann einfach #include und fertig.
Ich habe nur noch eine main.cpp, alles andere sind *.h
Module dauern einfach zu lange... macht keinen Sinn zu warten.
Ansonsten auch einfach D benutzen, die haben seit Jahren ordentliche Module und generieren den Code ja letztlich auch über LLVM, ist also auch schnell - und da kann man auch die Abhängigkeiten zwischen Klassen definieren, anstatt zwischen Files - das wird nie was ordentliches werden in C++.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
In meinen Experimenten waren Module ganz brauchbar – eben so lange die Abhängigkeiten alphabetisch sortiert sind.
Header-only ist mir viel zu langsam, weil die Abhängigkeiten viel zu schnell wachsen (A #includet B, das wiederum #includet C und D, …). Ich habe ja schonmal geschätzt, dass ohne Header die Kompilierzeit großer Projekte ungefähr auf ein Hundertstel(!) sinken dürfte: viewtopic.php?f=9&t=1929&p=62362#p62362
Um das zu stützen, habe ich letztens noch keine wirklichen Analysen finden können. Nur einen Kommentar des LLVM-Teams, dass ihnen kein einziges Projekt bekannt wäre, das durch Modules nicht schneller kompilieren würde.
Nachtrag: Visual Studio 16.8.0 Preview 1.0 kann die Reihenfolge noch immer nicht automatisch bestimmen.
Header-only ist mir viel zu langsam, weil die Abhängigkeiten viel zu schnell wachsen (A #includet B, das wiederum #includet C und D, …). Ich habe ja schonmal geschätzt, dass ohne Header die Kompilierzeit großer Projekte ungefähr auf ein Hundertstel(!) sinken dürfte: viewtopic.php?f=9&t=1929&p=62362#p62362
Um das zu stützen, habe ich letztens noch keine wirklichen Analysen finden können. Nur einen Kommentar des LLVM-Teams, dass ihnen kein einziges Projekt bekannt wäre, das durch Modules nicht schneller kompilieren würde.
Nachtrag: Visual Studio 16.8.0 Preview 1.0 kann die Reihenfolge noch immer nicht automatisch bestimmen.
Re: C++ Modules
Freue mich, dass sie für dich funktioniert haben, das gibt zumindest etwas Hoffnung.
Und klar, richtige Module sind natürlich die beste Lösung.
Aber macht euch mal auf ein paar Überraschungen gefasst, was den Performance-Gewinn angeht.
Schlechtes Design einer Applikation bleibt langsam, egal ob mit Modulen oder ohne.
Leider schaut man überhaupt nicht darauf, welche Probleme FORTRAN, Java, C# oder D bei der Implementierung hatten/haben.
Ich denke der Kommentar der LLVM Entwickler ist... sagen wir mal... etwas zu blauäugig :-P
... und ein Grund, warum Module so lange dauern, und auch noch dauern werden.
Und das wissen wir doch eigentlich alle: nichts vermuten, sondern profilen!
Ich sage nur: "export import ..." => killt die Performance und alle werden es nutzen. Für andere Sprachen ein "Klassiker" :-)
Hier mal ein paar Links dazu:
https://vector-of-bool.github.io/2019/0 ... s-doa.html
https://bfgroup.github.io/cpp_tooling_s ... 441R1.html
http://www.open-std.org/jtc1/sc22/wg21/ ... 1427r0.pdf
Zu meinem Vorgehen:
Ich kompiliere bei mir natürlich auch kein Chromium, sondern nur einige hunderttausend LOC.
Und man findet nicht für alles Header-Only Libraries, also nicht für jedes Projekt einsetzbar.
Alles was größer ist, verteile ich auf mehrere .dll/.so => Problem "gelöst" :-)
Was ich aber auch gut daran finde ist das "Build-Framework", habe nämlich keins und brauche auch keins:
Das war jetzt mal nur der Linux build, generiert eine Binary, die quasi auf jeder Linux-Distro lauffähig ist (weil alle Dependencies mit reincompiliert werden).
Geschwindigkeit? für die o.g. ca. 300.000 LOC: < 3 Sekunden (inkrementell, macht alles zig für mich) und < 8 Sekunden (komplettes Projekt, aber ohne libc++ und musl).
Ist mMn auch einer der großen Vorteile von Modulen: Ich brauche dem Compiler nicht die ganzen Abhängigkeiten zu verklickern; wenns denn klappt (siehe mein letzter Link oben).
Und klar, richtige Module sind natürlich die beste Lösung.
Aber macht euch mal auf ein paar Überraschungen gefasst, was den Performance-Gewinn angeht.
Schlechtes Design einer Applikation bleibt langsam, egal ob mit Modulen oder ohne.
Leider schaut man überhaupt nicht darauf, welche Probleme FORTRAN, Java, C# oder D bei der Implementierung hatten/haben.
Ich denke der Kommentar der LLVM Entwickler ist... sagen wir mal... etwas zu blauäugig :-P
... und ein Grund, warum Module so lange dauern, und auch noch dauern werden.
Und das wissen wir doch eigentlich alle: nichts vermuten, sondern profilen!
Ich sage nur: "export import ..." => killt die Performance und alle werden es nutzen. Für andere Sprachen ein "Klassiker" :-)
Hier mal ein paar Links dazu:
https://vector-of-bool.github.io/2019/0 ... s-doa.html
https://bfgroup.github.io/cpp_tooling_s ... 441R1.html
http://www.open-std.org/jtc1/sc22/wg21/ ... 1427r0.pdf
Zu meinem Vorgehen:
Ich kompiliere bei mir natürlich auch kein Chromium, sondern nur einige hunderttausend LOC.
Und man findet nicht für alles Header-Only Libraries, also nicht für jedes Projekt einsetzbar.
Nach meiner Erfahrung für kleine bis mittlere Projekte völlig ok. Für Chromium natürlich eher nicht so pralle...when you #include a bunch of source files together then the compiler treats them as one translation unit
Alles was größer ist, verteile ich auf mehrere .dll/.so => Problem "gelöst" :-)
Was ich aber auch gut daran finde ist das "Build-Framework", habe nämlich keins und brauche auch keins:
Code: Alles auswählen
zig c++ -O3 -std=c++20 -target x86_64-linux-musl -o app app.cpp
Geschwindigkeit? für die o.g. ca. 300.000 LOC: < 3 Sekunden (inkrementell, macht alles zig für mich) und < 8 Sekunden (komplettes Projekt, aber ohne libc++ und musl).
Ist mMn auch einer der großen Vorteile von Modulen: Ich brauche dem Compiler nicht die ganzen Abhängigkeiten zu verklickern; wenns denn klappt (siehe mein letzter Link oben).
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Danke für die Links, die kannte ich noch nicht!
Die Messung der Build-Parallelität im zweiten Link ist super. Deren Zusammenfassung im ersten Link finde ich aber völlig daneben:
Und das kann ich gar nicht genug betonen: In den Diagrammen unten (128 Threads) dauert es zwar vier Mal so lange, bis die Module fertig sind (12 vs 3.5 s), aber die CPU-Auslastung ist ungefähr hundert Mal so hoch! Da wir hier über Parallelität sprechen, die auf Einzelrechnern eher selten ist, würde ich das eher für Module auslegen und behaupten, dass ein Build Server oder ein Job-System nun mindestens zehn Mal so viele Versionen parallel verarbeiten kann wie vorher?!
Meinst du, du machst Unity Builds? Aller Code in ein Modul?NytroX hat geschrieben: ↑16.08.2020, 14:44Zu meinem Vorgehen: […]Nach meiner Erfahrung für kleine bis mittlere Projekte völlig ok. Für Chromium natürlich eher nicht so pralle...when you #include a bunch of source files together then the compiler treats them as one translation unit
Alles was größer ist, verteile ich auf mehrere .dll/.so => Problem "gelöst" :-)
Die Messung der Build-Parallelität im zweiten Link ist super. Deren Zusammenfassung im ersten Link finde ich aber völlig daneben:
Gezeigt wurde doch, dass die Header-Parallelität bei 16–32 CPU-Kernen mit Modulen gleichzieht. Darunter – also auf so ziemlich jedem Entwickler-Computer – sind Module schneller fertig. Darüber – also vor allem auf Build Servern oder auf Job Distribution-Systemen – sind Header schneller kompiliert, aber bei einem Vielfachen der CPU-Zeit.Are modules fast? Spoiler alert: No. Or, more accurately: It’s subtle, but mostly no.
Und das kann ich gar nicht genug betonen: In den Diagrammen unten (128 Threads) dauert es zwar vier Mal so lange, bis die Module fertig sind (12 vs 3.5 s), aber die CPU-Auslastung ist ungefähr hundert Mal so hoch! Da wir hier über Parallelität sprechen, die auf Einzelrechnern eher selten ist, würde ich das eher für Module auslegen und behaupten, dass ein Build Server oder ein Job-System nun mindestens zehn Mal so viele Versionen parallel verarbeiten kann wie vorher?!
Re: C++ Modules
Ja, könnte man Unity-Builds nennen, weil das ja dabei rauskommt, wenn man nur Header #included (sieht ja für den Compiler so aus, als wärs nur eine große Datei).
Wichtig ist halt wie gesagt, dass man ne ordentliche Abhängigkeitsstruktur in seinem Programm hat, "#pragma once" o.ä. verwendet und halt auch mit "inline" arbeitet und wenig Preprocessor-Quatsch benutzt. Aber ich denke das ist ja logisch ;-)
Zu deinem letzten Abschnitt: ja, gebe ich dir vollkommen recht.
Ich denke Multithreading ist generell noch nicht so in den Compilern angekommen, sondern eher noch eine Baustelle. Hat aber ja nix mit der Sprache an sich zu tun. Man merkt halt, dass vor allem C++ Compiler mehrere Jahrzehnte auf dem Buckel haben.
Wichtig ist halt wie gesagt, dass man ne ordentliche Abhängigkeitsstruktur in seinem Programm hat, "#pragma once" o.ä. verwendet und halt auch mit "inline" arbeitet und wenig Preprocessor-Quatsch benutzt. Aber ich denke das ist ja logisch ;-)
Zu deinem letzten Abschnitt: ja, gebe ich dir vollkommen recht.
Ich denke Multithreading ist generell noch nicht so in den Compilern angekommen, sondern eher noch eine Baustelle. Hat aber ja nix mit der Sprache an sich zu tun. Man merkt halt, dass vor allem C++ Compiler mehrere Jahrzehnte auf dem Buckel haben.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Ja; ich stimme übrigens auch den Artikeln in vielem zu. Dass Modules unausgereift sind und monströse Komplexität mit sich bringen, steht kaum zur Debatte.
Ich würde mich sehr freuen, wenn hier mehr in die IDE verlagert würde. Jede moderne IDE parst sowieso das ganze Projekt um daraus Browsing-Informationen zu erzeugen. Da kann man im Hintergrund den AST speichern und die Kompilierzeit locker halbieren. Natürlich wird dadurch kein Buildserver schneller, aber der Entwickler würde viel schneller Feedback für den Code bekommen, an dem er gerade arbeitet.
Wo du Präprozessor-Quatsch erwähnst: Der Präprozesser ist meiner Erfahrung nach rasend schnell; viel schneller z. B. als constexpr. Ich kann auch hier nur Profiling empfehlen. Meine Erfahrung ist bspw., bei Visual C++ ist die Definition von 20 leeren Namespaces in einem Header zeitintensiver als 2000 Zeilen dichter Präprozessorquatsch und Funktionsdeklarationen direkt darüber.
Ich würde mich sehr freuen, wenn hier mehr in die IDE verlagert würde. Jede moderne IDE parst sowieso das ganze Projekt um daraus Browsing-Informationen zu erzeugen. Da kann man im Hintergrund den AST speichern und die Kompilierzeit locker halbieren. Natürlich wird dadurch kein Buildserver schneller, aber der Entwickler würde viel schneller Feedback für den Code bekommen, an dem er gerade arbeitet.
Wo du Präprozessor-Quatsch erwähnst: Der Präprozesser ist meiner Erfahrung nach rasend schnell; viel schneller z. B. als constexpr. Ich kann auch hier nur Profiling empfehlen. Meine Erfahrung ist bspw., bei Visual C++ ist die Definition von 20 leeren Namespaces in einem Header zeitintensiver als 2000 Zeilen dichter Präprozessorquatsch und Funktionsdeklarationen direkt darüber.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Visual Studio hat’s vollbracht: https://devblogs.microsoft.com/cppblog/ ... sion-16-8/
Und mit diesem, von mir seit fünf Jahren entgegengefieberten, Feature kommen sie natürlich drei Minuten nachdem ich im Bett sein müsste.The project build will automatically scan the Modules and Header Unit files (according to their Compile As setting), for other Module and Header Units dependencies in the same project, and build them in the correct dependency order.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Ich komme nicht klar.
Sinnhaftes Beispiel (tatsächlicher Code deutlich komplexer). Ich deklariere ein Modul:
Ich nutze es in einer anderen Übersetzungseinheit:… und nun kompiliert nichts mehr weil
error C2668: 'std::strlen': ambiguous call to overloaded function
Okaaaay. Also vertausche ich das #include mit dem import und
error: 'std::strlen' has already been defined
Das Problem scheint zu sein, dass ich zwei Mal #include <cstring> habe – einmal im Modul und einmal in der Übersetzungseinheit, die das Modul benutzt. Dadurch ist die Funktion doppelt deklariert(!).
Ich bin baff weil ich dachte, aus einem Modul würden nur Symbole exportiert werden, die export deklariert sind?! Der Compiler schlägt mir die Definition doppelt als Kandidat vor, und sagt nicht, worin sie sich die beiden Versionen unterscheiden. Ich kann das auch static, inline oder als template deklarieren – es bleibt doppelt definiert.
Schiebe ich das export module Test hinter das #include, kompiliert nichts mehr, weil die Module Declaration am Anfang der Datei stehen muss.
Ich bin perplex, denn letztes Jahr ging all das noch.
Entweder ist Visual Studio hier Schrott, oder Modules sind im finalen Standard nochmal deutlich schwieriger nutzbar geworden.
HOLY SHIT ich hab’s
Aus einem Module wird alles exportiert, was static oder inline ist. Ein anonymes Namespace (namespace { size_t strlen(); }) ist das einzige, was den Export verhindert. static exportiert, inline exportiert, beide lösen doppelt definierte Symbole aus. Nur namespace nicht.
Das kann doch nicht richtig sein?!
Nachtrag 2: Mit anonymen Namespaces statt static klappt die Übersetzung, aber der Linker findet nicht eine einzige Funktion aus den Modulen. Ich geh pennen
Sinnhaftes Beispiel (tatsächlicher Code deutlich komplexer). Ich deklariere ein Modul:
Code: Alles auswählen
export module Test;
#include <cstring>;
export size_t strlen_wrapper(char const * string) {
return std::strlen(string);
}
Code: Alles auswählen
#include <cstring>
import Test;
auto old = std::strlen("foo");
auto nuw = strlen_wrapper("foo");
error C2668: 'std::strlen': ambiguous call to overloaded function
Okaaaay. Also vertausche ich das #include mit dem import und
error: 'std::strlen' has already been defined
Das Problem scheint zu sein, dass ich zwei Mal #include <cstring> habe – einmal im Modul und einmal in der Übersetzungseinheit, die das Modul benutzt. Dadurch ist die Funktion doppelt deklariert(!).
Ich bin baff weil ich dachte, aus einem Modul würden nur Symbole exportiert werden, die export deklariert sind?! Der Compiler schlägt mir die Definition doppelt als Kandidat vor, und sagt nicht, worin sie sich die beiden Versionen unterscheiden. Ich kann das auch static, inline oder als template deklarieren – es bleibt doppelt definiert.
Schiebe ich das export module Test hinter das #include, kompiliert nichts mehr, weil die Module Declaration am Anfang der Datei stehen muss.
Ich bin perplex, denn letztes Jahr ging all das noch.
Entweder ist Visual Studio hier Schrott, oder Modules sind im finalen Standard nochmal deutlich schwieriger nutzbar geworden.
HOLY SHIT ich hab’s
Aus einem Module wird alles exportiert, was static oder inline ist. Ein anonymes Namespace (namespace { size_t strlen(); }) ist das einzige, was den Export verhindert. static exportiert, inline exportiert, beide lösen doppelt definierte Symbole aus. Nur namespace nicht.
Das kann doch nicht richtig sein?!
Nachtrag 2: Mit anonymen Namespaces statt static klappt die Übersetzung, aber der Linker findet nicht eine einzige Funktion aus den Modulen. Ich geh pennen
- xq
- Establishment
- Beiträge: 1590
- Registriert: 07.10.2012, 14:56
- Alter Benutzername: MasterQ32
- Echter Name: Felix Queißner
- Wohnort: Stuttgart & Region
- Kontaktdaten:
Re: C++ Modules
Doch, das ist komplett bekloppt. Die haben versucht, Module so nah an Headern zu halten wie möglich. Und damit exportieren Header natürlich alle static und inline-Funktionen *facepalm*Das kann doch nicht richtig sein?!
Ich hatte mit den TS mal durchgelesen und mir einfach die Hand auf die Stirn geklatscht. Man hätte so viel besser machen können. Und was is? Jetzt haben wir alle Probleme aus Headern UND die Probleme mit Modulen. GEIL.
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…
Programmiert viel in Zig und nervt Leute damit.
Programmiert viel in Zig und nervt Leute damit.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Jein. Ich bin endlich auf das gekommen, was weder die Microsoft Docs noch die meisten Tutorials erwähnen:
module; // Muss am Anfang der Datei stehen
// Alles, was hier steht – also auch Inhalt von #includes – wird nicht exportiert
export module Test; // Jetzt wird’s ernst
// Ab hier landet alles im Module Purview
// Das kann also mit anderen Dateien kollidieren, auch wenn es nicht explizit export markiert ist
Module mit einem nicht-exportierten Teil zu beginnen und mit einem exportierten Teil zu beenden ist ja an sich nicht schlecht (eben auch wegen #includes). ABER DAS MUSS MAN ERSTMAL WISSEN
Nachtrag: Zumindest vector of bool hat es: https://vector-of-bool.github.io/2019/1 ... e-fragment
module; // Muss am Anfang der Datei stehen
// Alles, was hier steht – also auch Inhalt von #includes – wird nicht exportiert
export module Test; // Jetzt wird’s ernst
// Ab hier landet alles im Module Purview
// Das kann also mit anderen Dateien kollidieren, auch wenn es nicht explizit export markiert ist
Module mit einem nicht-exportierten Teil zu beginnen und mit einem exportierten Teil zu beenden ist ja an sich nicht schlecht (eben auch wegen #includes). ABER DAS MUSS MAN ERSTMAL WISSEN
Nachtrag: Zumindest vector of bool hat es: https://vector-of-bool.github.io/2019/1 ... e-fragment
Und nein, ES FUNKTIONIERT IMMER NOCH NICHTCongratulations on making it thus far!
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Ich komme besser klar, aber …
… Module funktionieren nicht mit __restrict. Heißt: VC++ versemmelt die Signatur und die Funktion wird nirgends gefunden.
oh no
Und #pragma darf in Modulen nicht vorkommen (haben sie wohl in der neuen Syntax vergessen).
Edit-and-Continue geht nicht, weil Modules kein /INCREMENTAL unterstützen.
… Module funktionieren nicht mit __restrict. Heißt: VC++ versemmelt die Signatur und die Funktion wird nirgends gefunden.
oh no
Und #pragma darf in Modulen nicht vorkommen (haben sie wohl in der neuen Syntax vergessen).
Edit-and-Continue geht nicht, weil Modules kein /INCREMENTAL unterstützen.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Okay, das ist alles ganz ganz große Scheiße und *tatsächlich* Dead on Arrival.
Vor zwei Jahren haben Microsoft ihren Modules-Vorschlag in Visual C++ umgesetzt. Ich habe ein mittelgroßes Projekt auf diesen Vorschlag portiert. Der Support des Build-Systems war quasi nicht existent, deshalb musste ich das Projekt immer *zwei Mal* kompilieren, bis es klappte.
Aber ich hatte an einem Tag alles fertiggekriegt.
Ich schrieb module Text; in meine Parser-cpp, schrieb export vor jede Funktion, die ich außen verwenden wollte, löschte den Header, ersetzte #include "Text.hpp" durch import Text; und alles funktionierte.
Heute ist die Situation anders. Bevor ihr Modules benutzen könnt, müsst ihr erstmal lernen, was ein Fragment ist und das globale und private Fragment und der Unterschied zwischen Visibility und Reachability. Und was Module Linkage und ein Module Perview ist.
Dazu kommt, dass ihr die Syntax auswendig lernen müsst. Pro Modul müsst ihr module; oder export module foo; oder module :private; oder export import :bar einsetzen. Jedes davon bringt eine eigene Syntax mit („Ab jetzt sind nur Präprozessoranweisungen erlaubt“) und die Reihenfolge ist wichtig.
Ich habe nach zwei Tagen noch immer nicht richtig kapiert, wozu man das export-Schlüsselwort nun eigentlich braucht.
Dann kommt ihr in die unangenehme Situation, dass Module keine Header #includen dürfen, die auch irgendwo im Rest des Projektes benutzt werden(!!!). Ein Modul darf also nicht <Windows.h> oder <SDL.h> einbinden, sonst sind die nur noch exklusiv für das eine Modul verfügbar und nicht für den Rest des Projekts(!!!).
Das könnt ihr teilweise umschiffen, indem ihr Module in Interfaces und Implementations aufteilt. Dann habt ihr aber wieder ganz genau die gleiche Situation wie mit Headern und Cpp-Dateien! Ihr schreibt wieder alles doppelt hin, genau wie früher. Und erwartet nicht, dass es dann funktioniert – damit Linker das Merging von Module Fragments unterstützen, müssen sie beim Name Mangling die Symbole prefixen, und aus einer Funktion inline foo() im Header wird dann ein inline module::foo(), auf das sich der Rest des Projekts beruft, es aber nicht findet, weil es private ist. Aber auch nicht immer, dnn ob das stattfindet, hängt vom Two-Phase-Lookup ab. Herrgott, ich musste extern "C++" einsetzen, um einen Linkerfehler stumm zu kriegen?! WHAT THE FUCK
Ich weiß wirklich nicht, was in den letzten zwei Jahren mit dem Vorschlag passiert ist. Vor zwei Jahren konnte ich ein komplettes Projekt an einem Tag auf Modules umstellen; heute kapituliere ich nach drei Tagen.
Mein Hauptkritikpunkt an C++ ist, dass niemand versteht, wie es funktioniert. Chandler Carruth und John Carmack fassen es hier besser zusammen als ich: https://youtu.be/LJh5QCV4wDg?t=2337
… und diese Komplexität ist durch Module radikal gewachsen.
Nachtrag: Mir fällt gerade auf, dass die Modulsysteme von Java und C# locker auf einer Din-A4-Seite erklärbar sind (für 99 % der Use Cases sogar in einem Satz).
Was das C++-Modulsystem angeht, kommt die Tutorialserie von vector-of-bool auf 47 Din-A4-Seiten(!) und ich krieg’s trotzdem nicht produktiv eingesetzt. Obwohl das wirklich from Scratch entworfen wurde und null Legacy drinsteckt. Das kann man sich nicht ausdenken.
Vor zwei Jahren haben Microsoft ihren Modules-Vorschlag in Visual C++ umgesetzt. Ich habe ein mittelgroßes Projekt auf diesen Vorschlag portiert. Der Support des Build-Systems war quasi nicht existent, deshalb musste ich das Projekt immer *zwei Mal* kompilieren, bis es klappte.
Aber ich hatte an einem Tag alles fertiggekriegt.
Ich schrieb module Text; in meine Parser-cpp, schrieb export vor jede Funktion, die ich außen verwenden wollte, löschte den Header, ersetzte #include "Text.hpp" durch import Text; und alles funktionierte.
Heute ist die Situation anders. Bevor ihr Modules benutzen könnt, müsst ihr erstmal lernen, was ein Fragment ist und das globale und private Fragment und der Unterschied zwischen Visibility und Reachability. Und was Module Linkage und ein Module Perview ist.
Dazu kommt, dass ihr die Syntax auswendig lernen müsst. Pro Modul müsst ihr module; oder export module foo; oder module :private; oder export import :bar einsetzen. Jedes davon bringt eine eigene Syntax mit („Ab jetzt sind nur Präprozessoranweisungen erlaubt“) und die Reihenfolge ist wichtig.
Ich habe nach zwei Tagen noch immer nicht richtig kapiert, wozu man das export-Schlüsselwort nun eigentlich braucht.
Dann kommt ihr in die unangenehme Situation, dass Module keine Header #includen dürfen, die auch irgendwo im Rest des Projektes benutzt werden(!!!). Ein Modul darf also nicht <Windows.h> oder <SDL.h> einbinden, sonst sind die nur noch exklusiv für das eine Modul verfügbar und nicht für den Rest des Projekts(!!!).
Das könnt ihr teilweise umschiffen, indem ihr Module in Interfaces und Implementations aufteilt. Dann habt ihr aber wieder ganz genau die gleiche Situation wie mit Headern und Cpp-Dateien! Ihr schreibt wieder alles doppelt hin, genau wie früher. Und erwartet nicht, dass es dann funktioniert – damit Linker das Merging von Module Fragments unterstützen, müssen sie beim Name Mangling die Symbole prefixen, und aus einer Funktion inline foo() im Header wird dann ein inline module::foo(), auf das sich der Rest des Projekts beruft, es aber nicht findet, weil es private ist. Aber auch nicht immer, dnn ob das stattfindet, hängt vom Two-Phase-Lookup ab. Herrgott, ich musste extern "C++" einsetzen, um einen Linkerfehler stumm zu kriegen?! WHAT THE FUCK
Ich weiß wirklich nicht, was in den letzten zwei Jahren mit dem Vorschlag passiert ist. Vor zwei Jahren konnte ich ein komplettes Projekt an einem Tag auf Modules umstellen; heute kapituliere ich nach drei Tagen.
Mein Hauptkritikpunkt an C++ ist, dass niemand versteht, wie es funktioniert. Chandler Carruth und John Carmack fassen es hier besser zusammen als ich: https://youtu.be/LJh5QCV4wDg?t=2337
… und diese Komplexität ist durch Module radikal gewachsen.
Nachtrag: Mir fällt gerade auf, dass die Modulsysteme von Java und C# locker auf einer Din-A4-Seite erklärbar sind (für 99 % der Use Cases sogar in einem Satz).
Was das C++-Modulsystem angeht, kommt die Tutorialserie von vector-of-bool auf 47 Din-A4-Seiten(!) und ich krieg’s trotzdem nicht produktiv eingesetzt. Obwohl das wirklich from Scratch entworfen wurde und null Legacy drinsteckt. Das kann man sich nicht ausdenken.
-
- Moderator
- Beiträge: 2138
- Registriert: 25.02.2009, 13:37
Re: C++ Modules
Ich denke das liegt auch daran, dass "Modul" mindestens "Übersetzungseinheit", "Gliederung des Programms für den Programmierer" (vulgo: Datei) und "In sich abgeschlossene funktionale Einheit" bedeuten kann.
Die "Datei"-Dimension ist die am leichtesten zu verstehende und mindestens für Java und Python die einzige, die man wirklich verstehen muss um es produktiv zu benutzen.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
In den puren Wahnsinn abgeglitten ist es bei den impliziten Abhängigkeiten. Man nehme an:
export module foo;
struct Internal { int var; }; // nicht exportiert
export Internal makeInternal() { return { 42 }; }
Ein Benutzer des Moduls kann nun makeInternal() aufrufen. Aber dann bekommt er eine Rückgabe vom Typ Internal, und dieser Typ wird nicht vom Modul exportiert!
C#:
Fehler C50050. Das ist nicht erlaubt. Was auch immer man da machen will – es gibt sicher einen Weg, das deutlicher auszudrücken.
Java:
Es ist erlaubt, aber Benutzer werden statt Internal ausschließlich den Basistyp Object erhalten können, weil das alles ist, womit sie was anfangen können, ohne das private zu verletzen. Sie können das Object bei Bedarf ins Modul zurückfüttern, wo es wieder zu Internal gecastet werden kann, falls das nötig ist.
C++:
Also, wir benutzen ein Konzept, das es in C++ schon gibt und keiner benutzen will: Wir unterscheiden zwischen Visibility und Reachability. Der Typ Internal ist für Benutzer des Moduls nicht sichtbar, ich kann also nicht schreiben Internal i = makeInternal();. Was ich aber sehr wohl schreiben kann, ist auto i = makeInternal(); und sogar int lolfu = makeInternal().var;, denn er ist sehr wohl erreichbar! Nun müssen wir dummerweise dem Linker [einem 50 Jahre alten Konzept, das niemand mehr haben will] beibringen, zwischen Reachability und Visibility zu unterscheiden. Führen wir also neben den öffentlichen und privaten Symbolen einen neuen Symbolraum ein, der nicht-öffentliche nicht-private Symbole enthält! Dann müssen wir zwar auch spezifizieren, wie der Linker damit umgeht, wenn Namen kollidieren – aber C++-Programmierer werden’s lieben! Kollisionen zwischen Symbolen finden, die gar nicht exportiert sind, und dann Paragraphen im C++-Standard wälzen um zu erfahren, ob der Fehler im Compiler liegt oder im Code, und aus kryptischen Linker-Fehlern zurückermitteln, wo der Fehler im Quelltext liegt – das lieben die! Und wir müssen’s natürlich auch für enum und namespace spezifizieren, damit jeder sieht, wie viele Gedanken wir uns gemacht haben! Und wir benutzen Jura-Begriffe wie Purview, die zwar außerhalb der Facebook-AGB noch nie ein Schwein gehört hat, aber weil der C++-Standard aus Paragraphen besteht, ist das lustig!
export module foo;
struct Internal { int var; }; // nicht exportiert
export Internal makeInternal() { return { 42 }; }
Ein Benutzer des Moduls kann nun makeInternal() aufrufen. Aber dann bekommt er eine Rückgabe vom Typ Internal, und dieser Typ wird nicht vom Modul exportiert!
C#:
Fehler C50050. Das ist nicht erlaubt. Was auch immer man da machen will – es gibt sicher einen Weg, das deutlicher auszudrücken.
Java:
Es ist erlaubt, aber Benutzer werden statt Internal ausschließlich den Basistyp Object erhalten können, weil das alles ist, womit sie was anfangen können, ohne das private zu verletzen. Sie können das Object bei Bedarf ins Modul zurückfüttern, wo es wieder zu Internal gecastet werden kann, falls das nötig ist.
C++:
Also, wir benutzen ein Konzept, das es in C++ schon gibt und keiner benutzen will: Wir unterscheiden zwischen Visibility und Reachability. Der Typ Internal ist für Benutzer des Moduls nicht sichtbar, ich kann also nicht schreiben Internal i = makeInternal();. Was ich aber sehr wohl schreiben kann, ist auto i = makeInternal(); und sogar int lolfu = makeInternal().var;, denn er ist sehr wohl erreichbar! Nun müssen wir dummerweise dem Linker [einem 50 Jahre alten Konzept, das niemand mehr haben will] beibringen, zwischen Reachability und Visibility zu unterscheiden. Führen wir also neben den öffentlichen und privaten Symbolen einen neuen Symbolraum ein, der nicht-öffentliche nicht-private Symbole enthält! Dann müssen wir zwar auch spezifizieren, wie der Linker damit umgeht, wenn Namen kollidieren – aber C++-Programmierer werden’s lieben! Kollisionen zwischen Symbolen finden, die gar nicht exportiert sind, und dann Paragraphen im C++-Standard wälzen um zu erfahren, ob der Fehler im Compiler liegt oder im Code, und aus kryptischen Linker-Fehlern zurückermitteln, wo der Fehler im Quelltext liegt – das lieben die! Und wir müssen’s natürlich auch für enum und namespace spezifizieren, damit jeder sieht, wie viele Gedanken wir uns gemacht haben! Und wir benutzen Jura-Begriffe wie Purview, die zwar außerhalb der Facebook-AGB noch nie ein Schwein gehört hat, aber weil der C++-Standard aus Paragraphen besteht, ist das lustig!
Re: C++ Modules
Alle Jahre wieder: Sind C++ Module schon an dem Punkt angekommen, wo man sie produktiv benutzen will?
Ich bastel gerade an meinem Projekt rum und es kompiliert jetzt schon lange und jedes mal wenn ich 'include' schreibe läuft es mir kalt den Rücken runter. Und seitem ich mir neulich den Includebaum von einer einzelnen Datei angeschaut habe um herauszufinden woher diese dämlichen windows.h includes kommen (und dieser Baum hatte ~1000 Einträge) fände ich funktionierende Module echt mal nice...
Ich bastel gerade an meinem Projekt rum und es kompiliert jetzt schon lange und jedes mal wenn ich 'include' schreibe läuft es mir kalt den Rücken runter. Und seitem ich mir neulich den Includebaum von einer einzelnen Datei angeschaut habe um herauszufinden woher diese dämlichen windows.h includes kommen (und dieser Baum hatte ~1000 Einträge) fände ich funktionierende Module echt mal nice...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Siehe oben: Du kannst sie in Visual Studio produktiv benutzen. Ich finde sie aber nach meinen Tests schlimmer als #include (und das will was heißen). Habe alle Experimente damit abgebrochen.
Ist vielleicht nur mein Geschmack; ich lasse mich gern von dir überraschen :) Viel Spaß mit Visibility und Reachability!
Ist vielleicht nur mein Geschmack; ich lasse mich gern von dir überraschen :) Viel Spaß mit Visibility und Reachability!
Re: C++ Modules
Ja, den Beitrag hatte ich vorhin noch gelesen. Dachte, es hätte sich vielleicht etwas getan.
Klingt jedenfalls alles nicht sehr toll...
Ist das immer noch so? Soll das so sein? Ich meine, das macht das komplette System doch irgendwie sinnlos? Was ist mit Headern aus der Standardbibliothek? Oder heißt das, dass dann einfach jeder das entsprechende Modul importieren muss und niemand die Datei mehr inkludieren darf?
Klingt jedenfalls alles nicht sehr toll...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Die Header aus der Standardbibliothek stellt Visual Studio als Module zur Verfügung … vielleicht verwendet man dann die. Kann das nicht recht beantworten (nutze selber keine Standardbibliothek) :(
Re: C++ Modules
Naja, ist aber auch innerhalb von C++ ähnlich oder?
Was ähnliches hatte ich hier schonmal beschrieben:
viewtopic.php?p=60486#p60486
Hat also mMn nicht unbedingt was mit Modulen zu tun. Darum heißen sie ja auch "Voldemort"-Types, weil man sie nicht beim Namen nennen darf :-P
Du kannst aber mal mit decltype versuchen, also so etwa:
Hab ich aber noch nicht probiert mit Modulen.
Ist aber ein gängiges Konzept (naja jedenfalls in D, aber die haben auch seit einigen Jahrzehnten brauchbare modules) und auch eigentlich ganz brauchbar für Libraries, wo der Nutzer quasi ein Handle bekommt, aber es nur über die Lib erzeugen soll.
Was ähnliches hatte ich hier schonmal beschrieben:
viewtopic.php?p=60486#p60486
Code: Alles auswählen
auto myfunc(int i) {
struct returntype {
int result;
bool success = true;
};
return returntype{ i * 2 }; //geht, weil return type "auto" :-)
}
int main()
{
auto test1 = myfunc(10); //normal
if(test1.success)
{
auto x = test1.result; //benutzen
}
auto [result, success] = myfunc(20); //de-struct-uring
return result;
}
Du kannst aber mal mit decltype versuchen, also so etwa:
Code: Alles auswählen
decltype(makeInternal()) myVar;
using ExportedInternal = decltype(makeInternal()); //hihihi
Ist aber ein gängiges Konzept (naja jedenfalls in D, aber die haben auch seit einigen Jahrzehnten brauchbare modules) und auch eigentlich ganz brauchbar für Libraries, wo der Nutzer quasi ein Handle bekommt, aber es nur über die Lib erzeugen soll.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: C++ Modules
Das war ja auch nicht das Problem. Das Problem war eher:
Es gibt eine Erklärung dafür, und eine Lösung. Ich habe beides verdrängt, weil ich es ehrlich gesagt nur für Verschwendung von Hirnmasse halte. Wenn jemand auf meinen Code schaut, dann muss er die C-Konzepte Deklaration, Definition, #include verstehen. Wenn ich meinen Code auf Module umstelle, muss er die Konzepte Deklaration, Definition, Visibility, Reachability, Fragment, Purview, Global Module Fragment und Private Module Fragment verstehen, und noch mehr, was ich wieder vergessen habe. Ich sehe keinen Grund, warum ich das wählen sollte.Krishty hat geschrieben: ↑17.09.2020, 23:37 error: 'std::strlen' has already been defined
Das Problem scheint zu sein, dass ich zwei Mal #include <cstring> habe – einmal im Modul und einmal in der Übersetzungseinheit, die das Modul benutzt. Dadurch ist die Funktion doppelt deklariert(!).
Ich bin baff weil ich dachte, aus einem Modul würden nur Symbole exportiert werden, die export deklariert sind?! Der Compiler schlägt mir die Definition doppelt als Kandidat vor, und sagt nicht, worin sie sich die beiden Versionen unterscheiden. Ich kann das auch static, inline oder als template deklarieren – es bleibt doppelt definiert.
Wie gesagt: Ich würde mich freuen, wenn jemand ein vollständiges Projekt auf Module umstellt und dann hier berichtet, wie’s lief. Vielleicht bin ich ja nur senil und alles ist ganz einfach. Wenn’s gut läuft, ist das Projekt sauberer. Wenn nicht, haben wir alle was gelernt.
Und ja, D hat das besser gemacht. Und C#. Und sogar Java. Nur C++ hat es IMO extrem verkackt, und jetzt klebt es wie Scheiße unter dem Schuh der Sprache, obwohl es uns alle hätte retten können.
-
- Establishment
- Beiträge: 135
- Registriert: 29.08.2003, 14:22
- Kontaktdaten:
Re: C++ Modules
Scheint mittlerweile nicht mehr so zu sein. Habs gerade mal ausprobiert:Jonathan hat geschrieben: ↑28.01.2021, 16:11 Ja, den Beitrag hatte ich vorhin noch gelesen. Dachte, es hätte sich vielleicht etwas getan.
Ist das immer noch so? Soll das so sein? Ich meine, das macht das komplette System doch irgendwie sinnlos? Was ist mit Headern aus der Standardbibliothek? Oder heißt das, dass dann einfach jeder das entsprechende Modul importieren muss und niemand die Datei mehr inkludieren darf?
Klingt jedenfalls alles nicht sehr toll...
ModulesSample.cpp
Code: Alles auswählen
import MyFirstModule;
#include <iostream>
int main()
{
std::cout << "This is the module sample" << std::endl;
M1::hello();
}
Code: Alles auswählen
export module MyFirstModule;
namespace M1
{
void internalFunction();
export void hello();
}
Code: Alles auswählen
module;
#include <iostream>
module MyFirstModule;
namespace M1
{
void internalFunction()
{
std::cout << "Start!" << std::endl;
}
void hello()
{
internalFunction();
std::cout << "Hello World" << std::endl;
}
}
Ganz gut gefällt mir die Aufteilung zwischen Module-Interface und Module-Implementierung und dass es auch möglich ist, die Implementierung auf mehrere CPP-Dateien aufzuteilen.
Hier übrigens nochmal schön beschrieben:
https://docs.microsoft.com/de-de/cpp/cp ... w=msvc-160
Ob es komplexere Probleme gibt, kann ich nicht sagen. Das war quasi mein erster Gehversuch mit Modulen :)
Hier nochmal ein etwas erweitertes Beispiel inkl. Klassen:
>>> http://www.bug-soft.net <<<
-
- Establishment
- Beiträge: 135
- Registriert: 29.08.2003, 14:22
- Kontaktdaten:
Re: C++ Modules
Hat schon jemand herausgefunden, wie man in Visual Studio Modulinterface-Dateien ins Projekt integriert, die nicht im Projektverzeichnis, liegen?
>>> http://www.bug-soft.net <<<
-
- Establishment
- Beiträge: 135
- Registriert: 29.08.2003, 14:22
- Kontaktdaten:
Re: C++ Modules
Ich habe nochmal etwas recherchiert und festgestellt, dass man zwar externe Module in seinem Projekt einbinden kann, allerdings müssen diese schon kompiliert sein. Siehe hier (Achtung, mittlerweile heißt die CompilerOption nur noch "/reference" und nicht mehr "/module:reference":
https://docs.microsoft.com/de-de/cpp/bu ... w=msvc-160
Die Option findet sich unter den Projekteigenschaften => C/C++ => Allgemein => Zusätzliche Modulabhängigkeiten
Das funktioniert also leider etwas anders als z.B. die zusätzlichen include-Verzeichnisse.
Eine analoge Option für Module (aka zusätzliche Modulverzeichnisse) scheint es leider nicht zu geben.
Möchte man nicht kompilierte Module (ixx, cpp) im Projekt nutzen, müssen diese Dateien dem Projekt also auf herkömmliche Weise einfach hinzugefügt werden.
https://docs.microsoft.com/de-de/cpp/bu ... w=msvc-160
Die Option findet sich unter den Projekteigenschaften => C/C++ => Allgemein => Zusätzliche Modulabhängigkeiten
Das funktioniert also leider etwas anders als z.B. die zusätzlichen include-Verzeichnisse.
Eine analoge Option für Module (aka zusätzliche Modulverzeichnisse) scheint es leider nicht zu geben.
Möchte man nicht kompilierte Module (ixx, cpp) im Projekt nutzen, müssen diese Dateien dem Projekt also auf herkömmliche Weise einfach hinzugefügt werden.
>>> http://www.bug-soft.net <<<