GCC 16.1.0 und Modules
-
@john-0
-freflectionwar übrigens auch bei meinem Test da oben aktiv. Das sollte also grundsätzlich funktionieren. Auch wenn mein Compiler hier noch ein Commit aus dem Entwicklungs-Branch von vor ein paar Monaten ist. Wenn es also nicht an der#include/import-Reihenfolge liegt, solltest du vielleicht mal versuchen das mit einem Minimalbeispiel zu reproduzieren. Vielleicht fällt dir bei dem Versuch ja auch eine ganz banale Ursache auf (vielleicht irgendein#includenoch irgendwo weiter unten im Code?).Es ist aber auch nicht ausgeschlossen, dass es da noch einen ernsthaften Compiler-Bug gibt. Ich habe da auch schon einen gemeldet, der nur mit der
-fmodules/-freflection-Kombination auftrat. Da gibt es intern wohl eine ganze Menge Zahnrädchen, die sich verhaken können. Ein Grund mehr, die Sache leicht reproduzierbar zu machen - sofern du die Muße dafür hast. Auf die nächste Version warten ist natürlich auch eine Option
Ansonsten werd ich demnächst wohl auch wieder einiges mit der
-fmodules/-freflection-Kombination machen und den Compiler auf 16.1 oder neuer aktualisieren. Vielleicht bekomme ich ja ähnliche Probleme. Falls ja, und ich es eingrenzen kann, werd ich das sicher melden.
-
@john-0 Interessanterweise hatte ich gerade beim Bauen von GCC 16.1.0 exakt dasselbe Problem (Konflikt mit
__mbstate_t). Die Ursache bei mir war allerdings, dass ich noch ein#include <meta>in einer meiner Quellcode-Dateien hatte aus einer Zeit, wostd::metanoch nicht in dasstd-Modul integriert war. Dabei war es übrigens egal, dass es vor demimport std;stand. in der alten Entwicklungsversion hat das noch so funktioniert, mit GCC 16.1.0 allerdings nicht mehr.Stell auf jeden Fall sicher, dass du keine Header der Standardbibliothek mit
#includeeinbindest, wenn duimport std;verwendest. Ich habe auch in irgendwelchen Bug-Reports gelesen, dass das zu kombinieren nicht funktioniert. Da gibt's auf jeden Fall noch einiges, das im argen liegt beimstd-Modul. Ich hab grad auch noch einen Bug gemeldet, der allerdings nicht direkt mit diesem Problem zu tun hat.Mein Eindruck ist, dass das Modul nur wirklich gut mit der GCC-Standardkonfiguration funktioniert. Wenn man da irgendwas spezielles konfiguriert, läuft da noch eine Menge vor die Wand
... aber das ist bei dir denke ich schon eher "Standard", während ich an einer Runtime für DOS-Retroprogrammierung mit modernem C++ bastele. Da stoße ich doch recht häufig auf Dinge, die nicht so recht wollen. Runtime-Startup-Code, der vor der main()läuft und der in C++26 mit Reflection und Modulen programmiert wurde, ist wahrscheinlich auch ein etwas weniger "ausgetretener Pfad"
Kleine spaßige Anekdote am Rande: Meine Runtime ist grad in einem Zustand, wo ich einiges umgebaut habe und die
main()noch gar nicht aufrufe. Das hat dazu geführt, dass beim Bauen der neuen GCC 16.1.0-Toolchain alle "Link-Tests" durchgegangen sind. Buildsysteme wie Autotools oder CMake testen ob Bibliotheksfunktionen existieren, indem sie ein Programm kompilieren, dass die entsprechende Funktion benutzt und schließen dann aus einem Linker-Fehler, dass die Funktion nicht existiert. Nun habe ich allerdings die Toolchain so konfiguriert, dass Compiler und Linker aggressiv allen Code eliminieren, der nicht aufgerufen wird (für möglichst kleine Binaries). So auch diemain()-Funktion, wo der eigentliche Test der Funktion stattfindet. Resultat: Buildsysteme glauben, dass ALLE getesteten Funktionen existieren, was dann natürlich später gnadenlos vor die Wand läuft
... habe mainnun im Linker-Skript explizit so angegeben, dass sie nicht "garbage-collected" wird, damit sowas nicht mehr vorkommt während ich da an Innereien herumbastele.
-
@Finnegan sagte in GCC 16.1.0 und Modules:
@john-0 Interessanterweise hatte ich gerade beim Bauen von GCC 16.1.0 exakt dasselbe Problem (Konflikt mit
__mbstate_t). Die Ursache bei mir war allerdings, dass ich noch ein#include <meta>in einer meiner Quellcode-Dateien hatte aus einer Zeit, wostd::metanoch nicht in dasstd-Modul integriert war. Dabei war es übrigens egal, dass es vor demimport std;stand. in der alten Entwicklungsversion hat das noch so funktioniert, mit GCC 16.1.0 allerdings nicht mehr.Wie ich bereits schrieb, ich inkludiere nur C Header, da ich Dinge mit ncurses bzw. der Wide Version davon mache, und ohne C Header geht da nichts. Sicherlich wird die C++ Standard Bibliothek einiges davon auch inkludieren, aber diese Header hatten schon immer Include Guards. Dazu empfinde ich es als besonders verwirrend, wenn man das std Module importiert, und es zu Kollisionen kommt. Im Vergleich zu den klassischen C++ Headern wird nun im Modul
stdalles in::stddefiniert. Eigentlich sollte es daher gerade nicht mehr zu Problemen kommen. Erst seit GCC 16 gibt es nun das Modulestd.compat.Stell auf jeden Fall sicher, dass du keine Header der Standardbibliothek mit
#includeeinbindest, wenn duimport std;verwendest. Ich habe auch in irgendwelchen Bug-Reports gelesen, dass das zu kombinieren nicht funktioniert. Da gibt's auf jeden Fall noch einiges, das im argen liegt beimstd-Modul. Ich hab grad auch noch einen Bug gemeldet, der allerdings nicht direkt mit diesem Problem zu tun hat.Seit GCC 14 hatte ich keine Probleme mit dem GCC Modul Support, aber es gab bisher auch kein Support für Reflection. Sobald ich Reflection aktiviere fliegt mir der Code um die Ohren.

Fazit, ich lasse bis auf weiteres die Finger von Reflection.
-
Es gibt seit ein paar Tagen GCC 16.2.0 und mit diesem Release scheinen nun die Probleme in Bezug auf std::meta behoben zu sein. Es lässt sich nun auch mit import std; übersetzten, linken und ausführen. Mal sehen, ob es bei größeren Dingen noch Probleme gibt.
-
@john-0 Wie sieht das bei GCC aus, wenn man
import std;nutzen will, aber über Abängigkeiten von Drittbibliotheken noch "alte" includes von std Headern hat?Ich habe letztens versucht ein größeres Projekt umzustellen, was sowohl unter Windows mit MSVC als auch unter Ubuntu mit Clang kompiliert werden muss und ich hab irgendwann aufgegeben. Visual Studio kann man sagen, dass die includes durch imports ersetzt werden sollen, aber unter Clang mit Cmake habe ich das nicht ans laufen bekommen.
-
@john-0 sagte in GCC 16.1.0 und Modules:
Es gibt seit ein paar Tagen GCC 16.2.0 und mit diesem Release scheinen nun die Probleme in Bezug auf std::meta behoben zu sein. Es lässt sich nun auch mit import std; übersetzten, linken und ausführen. Mal sehen, ob es bei größeren Dingen noch Probleme gibt.
Oh, das hört sich gut an. Werde mal auf die Version aktualisieren. Habe da nämlich auch noch so ein berüchtigtes
/toolchains/dlo-toolchain-x86_64-linux-musl/i386-dlo-elf/include/sys/_types.h:219:3: error: conflicting imported declaration 'typedef struct _mbstate_t _mbstate_t' [build] 219 | } _mbstate_t;bei einem
#include <sys/types.h>, das ich fürpid_teinbinden will. Habe erstmal einfachintverwendet, weil es der Typ für die Plattform ist, aber das ist keine saubere Lösung. Ich frage mich echt was da schief gelaufen ist, da das bei mir ein völlig anderes System ist. Der mag scheinbar einfach die Art und den Kontext nicht, wie der Typ deklariert wird.
-
Diese Kombination habe ich bisher noch nicht probiert. Vorausgesetzt es wird der gleiche Compiler für alles in C++ Projekt genutzt, gehe ich davon aus, dass das mit GCC funktioniert, wenn man einige Punkte beachtet.
- Das Standard Module sollte so übersetzt werden, dass es zu restlichen Code passt.
- Man sollte immer das gleiche Standard Module importieren, d.h. nicht zwischen std und std.compat wechseln sondern sich für eine der Varianten entscheiden.
- Du bindest std.o bzw. std.compat.o zum fertigen Programm.
- Die Variante mit den Module für jeden Standard Header gibt es zwar auch noch. Aber sie ist mittlerweile veraltet. Wenn möglich sollte man sie nicht nutzen unter anderem, weil es erheblich mehr Aufwand ist die Header bei GCC selbst zu modularisieren, da sie in der Standard Installation eben nicht übersetzt werden.
-
@Schlangenmensch sagte in GCC 16.1.0 und Modules:
@john-0 Wie sieht das bei GCC aus, wenn man
import std;nutzen will, aber über Abängigkeiten von Drittbibliotheken noch "alte" includes von std Headern hat?Ich habe letztens versucht ein größeres Projekt umzustellen, was sowohl unter Windows mit MSVC als auch unter Ubuntu mit Clang kompiliert werden muss und ich hab irgendwann aufgegeben. Visual Studio kann man sagen, dass die includes durch imports ersetzt werden sollen, aber unter Clang mit Cmake habe ich das nicht ans laufen bekommen.
Zu Clang und MSVC kann ich leider nicht viel sagen aber ganz generell kann man externe Bibliotheken natürlich auch noch über Header einbinden, sofern man ein paar Dinge beachtet:
- handelt es such um ein C++-Modul, müssen die
#include-Direktiven im Global Module Fragment stehen. Das gilt für Module Interface Units (die neuen "Header" - aber psst! Lass das nicht das Standardisierungskomitee hören
):
//! @file mymodule.ixx module; // Global Module Fragment beginnt hier #include <library.h> // Global Module Fragment endet hier export module mymodule;wie auch für Module Implementation Units:
//! @file mymodule.cpp module; #include <library.h> module mymodule;-
Makros und Präprozessor-Definitionen sind isoliert, d.h. die von
library.hsind also z.B. im obigen Fall nicht in dem Programm verfügbar, das "mymodule" viaimport mymodule;konsumiert. Wenn die Bibliothek es mit Präprozessor-Magie allzu wild treibt, kann das ein Problem werden, wennlibrary.hauch von dem Programm eingebunden wird, welches das Modul konsumiert. Im Allgemeinen verhalten sich Includes wie oben aber wie solche in separaten Übersetzungseinheiten (.cppFiles), und sollten daher keine Probleme machen. Auch werden diese eingebundenen header nicht exportiert. Konsumenten des Moduls müssen dielibrary.hselbst nochmal einbinden, wenn sie diese benötigen. -
Das bringt uns auch zu Konsumenten von Modulen, die selbst keine Module sind: Prinzipiell kann hier eigentlich
importund#includewild gemischt werden, allerdings gibt es meines Wissens eine Regel im Standard bezüglich Auflösung von Symbolen, die sowohl im Header, als auch im Modul definiert werden. Mehrfache Definitionen sind möglich, wenn ein Modul eine solche exportiert, die vorher über einen Header hereingeholt wurde. Umgekehrt gilt das jedoch nicht, daher sollten#includes stets vor denimport-Anweisungen kommen:
//! @file main.cpp #include <mylibrary.h> #include <string> import std; ...Eine solche doppelte Definition wäre in diesem Beispiel z.B.
std::string, die auch vomstd-Modul exportiert wird. In dieser Reihenfolge sollte das funktionieren, umgekehrt sollte es jedoch krachen. Das ist wohl auch der Mechanismus der beim ursprünglichen Problem von @john-0 eine Rolle spielt, und der offenbar in GCC 16.1 nicht so ganz klappte, egal in welcher Reihenfolge (vermutlich in Kombination mit C++26 Reflection).Ich fahre mit diesen
#include/import-Regeln bisher ganz gut, verwende aber auch noch nicht so viele Bibliotheken mit klassischen Headern (derzeit nurlibc). Ich hoffe das hilft weiter, so sollte es zumindest funktionieren. Allerdings muss man damit rechnen, dass da der eine oder andere Compiler noch ein paar Probleme bereitet, wie bei @john-0 und mir mit dem_mbstate_tbzw.__mbstate_t.
- handelt es such um ein C++-Modul, müssen die
-
@john-0 sagte in GCC 16.1.0 und Modules:
- Das Standard Module sollte so übersetzt werden, dass es zu restlichen Code passt.
Das ist auch ein wichtiger Punkt. Die kompilierten Binary Module Interfaces (
.gcm-Dateien bei GCC, bei anderen Compilern heißen die anders - ein bisschen mit Objektdateien/Bibliotheken vergleichbar) sind sehr spezifisch für die aktuellen Compiler-Flags und haben diese teilweise auch eingebettet. D.h. der Compiler wird z.B. meckern, wenn man ein solches BMI, das z.B. mit-fexceptionskompiliert wurde für ein Programm verwendet, dass man mit-fno-exceptionskompiliert. Ich glaube bei GCC gehören u.a. auch noch RTTI- und Sprachstandard-Flags dazu.Letztendlich bedeutet das, dass BMIs aus den Module interface Unit-Quellcodes (oft
.ixxoder.cppm) für nahezu jedes Projekt individuell neu kompiliert werden müssen. Daher habe ich die weiter oben "die neuen Header" genannt, da man die ähnlich den Headern im Quellcode mit ausliefern muss, wenn man ein Modul veröffentlicht. Auch müsseninline-Funktionen und Templates ähnlich wie bei Headern in diesen Interface Units definiert werden, wenn z.B. Nutzer des Moduls diese templates für eigene Typen instantiieren wollen.Das erfordert natürlich auch, dass das Build-System Module unterstützt und die BMIs aus den Interface Units als Teil des eigenen Projekts baut - auch für die Standardbibliothek (da ist das Interface Unit glaube ich
std.ccirgendwo im GCC-Verzeichnisbaum). Ein aktuelles CMake kann das, es ist jedoch dort ein experimentelles Feature, das explizit aktiviert werden muss.
-
@Finnegan sagte in GCC 16.1.0 und Modules:
Das erfordert natürlich auch, dass das Build-System Module unterstützt und die BMIs aus den Interface Units als Teil des eigenen Projekts baut - auch für die Standardbibliothek (da ist das Interface Unit glaube ich
std.ccirgendwo im GCC-Verzeichnisbaum). Ein aktuelles CMake kann das, es ist jedoch dort ein experimentelles Feature, das explizit aktiviert werden muss.Sehr gut in Deinen beiden Postings zusammen gefasst.
Noch eine Anmerkung dazu. Ich nutze direkt GNU make und schreibe die Regeln selbst, weil das schon deutlich früher ging, und man so die Flexibilität hat, alles unter Kontrolle zu haben. Mit CMake kann ich mich nicht anfreunden, und wahrscheinlich sollte ich mal meson o.ä. anschauen. b2 wird wohl außerhalb von boost kaum genutzt.