GCC 16.1.0 und Modules



  • Es gibt nun eine spezielle Option, um das Standard Module zu übersetzen. Mit

    gcc std=c++26 -fmodules -c --compile-std-module
    

    macht der Compiler das nun selbst, so dass man nicht mehr wissen muss, wo der Compiler installiert wurde. Es wird zusätzlich auch ein std.compat Module übersetzt, dass die Deklarationen auch im globalen Namensraum definiert, so wie das mit den Header der Fall ist. Allerdings musste ich feststellen, dass nicht alle Bestandteile im Standard Module vorhanden sind. Dinge aus meta fehlen.



  • @john-0 sagte in GCC 16.1.0 und Modules:

    Dinge aus meta fehlen.

    Versuchs mal mit zusätzlich -freflection, das muss meines Wissens auch noch extra aktiviert werden wie die Module. Das hat jedenfalls nach einem Bugfix vor nem halben Jahr oder so im Entwicklungs-Branch funktioniert, nachdem sich Module und Reflection lange Zeit gebissen haben.



  • Ah, das war es. Vielen Dank für den Hinweis!



  • Das nächste Problem tritt bei mir auf. Wenn ich das Standard Module mit Reflection Support baue, dann scheitert bei mir das Include von „ncursesw/ncurses.h“ und er spuckt diese Fehlermeldung aus (gekürzt).

    Das Verrückte ist, lässt man die "-freflection" Option weg, übersetzt er das perfekt.

    Hat jemand einen Ansatzpunkt was man machen kann?

    g++-16 --std=c++26 -fmodules -freflection -DCXX_SYSTEM_IMPORT_STD=yes -c --compile-std-module
    mv *.o objs/.
    g++-16 -std=c++26 -O3 -Wpedantic -pedantic-errors -fno-gnu-keywords -Wall -Wextra -Wplacement-new=2 -Waligned-new -Wdouble-promotion -Winit-self -Wnoexcept -Wold-style-cast -fmodules -freflection -DCXX_SYSTEM_IMPORT_STD=yes -c src/ngui_core.cc -o objs/ngui_core.o
    In Datei, eingebunden von /usr/include/x86_64-linux-gnu/bits/types/mbstate_t.h:4,
                     von /usr/include/wchar.h:53,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/cwchar:49,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/bits/postypes.h:42,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/bits/char_traits.h:44,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/string:45,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/bits/stdexcept_throw.h:57,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/bitset:49,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/x86_64-pc-linux-gnu/bits/stdc++.h:52,
    von Modul /opt/gcc-16.1.0/include/c++/16.1.0/x86_64-pc-linux-gnu/bits/stdc++.h, importiert bei /opt/gcc-16.1.0/include/c++/16.1.0/bits/std.cc:26,
    von Modul std, importiert bei src/ngui_core.cc:12:
    /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h:21:3: Fehler: in Konflikt stehende Deklaration »typedef struct __mbstate_t __mbstate_t«
       21 | } __mbstate_t;
          |   ^~~~~~~~~~~
    In Datei, eingebunden von /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h:5,
                     von /usr/include/stdio.h:40,
                     von /usr/include/curses.h:232,
                     von src/ngui_core.cc:7:
    /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h:21:3: Anmerkung: bestehende Deklaration »typedef struct __mbstate_t __mbstate_t«
       21 | } __mbstate_t;
          |   ^~~~~~~~~~~
    In Datei, eingebunden von /usr/include/x86_64-linux-gnu/sys/types.h:227,
                     von /usr/include/stdlib.h:514,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/cstdlib:83,
                     von /opt/gcc-16.1.0/include/c++/16.1.0/x86_64-pc-linux-gnu/bits/stdc++.h:39,
    von Modul /opt/gcc-16.1.0/include/c++/16.1.0/x86_64-pc-linux-gnu/bits/stdc++.h, importiert bei /opt/gcc-16.1.0/include/c++/16.1.0/bits/std.cc:26,
    von Modul std, importiert bei src/ngui_core.cc:12:
    /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:72:3: Fehler: in Konflikt stehende Deklaration »typedef union pthread_mutex_t pthread_mutex_t«
       72 | } pthread_mutex_t;
          |   ^~~~~~~~~~~~~~~
    In Datei, eingebunden von /usr/include/signal.h:375,
                     von src/ngui_core.cc:8:
    /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h:72:3: Anmerkung: bestehende Deklaration »typedef union pthread_mutex_t pthread_mutex_t«
       72 | } pthread_mutex_t;
          |   ^~~~~~~~~~~~~~~
    …
    


  • @john-0 Diese ganzen libc-includes finde ich immer einen absoluten Horror mit den ganzen #ifdef und #include_next von Lowlevel-Header-Fetzen, die teilweise nicht mal Include Guards haben 😱 .

    Nur mal den ersten Konflikt genauer angesehen:

    Auffällig finde ich, dass die "bestehende Deklaration":
    /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h:21:3
    die selbe Stelle ist wie die "in Konflikt stehende Deklaration":
    /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h:21:3

    bei mir (Arch-basiertes Linux, CachyOS) sieht die Datei so aus:

    #ifndef ____mbstate_t_defined
    #define ____mbstate_t_defined 1
    
    /* Integral type unchanged by default argument promotions that can
       hold any value corresponding to members of the extended character
       set, as well as at least one value that does not correspond to any
       member of the extended character set.  */
    #ifndef __WINT_TYPE__
    # define __WINT_TYPE__ unsigned int
    #endif
    
    /* Conversion state information.  */
    typedef struct
    {
      int __count;
      union
      {
        __WINT_TYPE__ __wch;
        char __wchb[4];
      } __value;		/* Value so far.  */
    } __mbstate_t;
    
    #endif
    

    Da ist schon ein Guard namens ____mbstate_t_defined. Aber wer weiss, das da noch alles an #undef-Schwarzmagie zwischendurch veranstaltet wird. Und dann sind auch noch Module im Spiel.

    Ich meine mich allerdings entsinnen zu können, dass die Reihenfolge von import un #include wichtig ist. Auch wenn du kein eigenes Modul baust und diese nur konsumierst:

    Ich glaube die #include müssen auf jeden Fall vor dem import kommen.

    Und in der Tat, wenn ich bei mir das hier mache, knallt es auch gewaltig:

    import std;
    
    #include <stdio.h>
    
    auto main() -> int
    {
    }
    
    /toolchains/dosloader-toolchain-x86_64-linux-musl/i386-dosloader-elf/include/stdio.h:89:8: error: conflicting declaration 'struct __file'
    [build]    89 | struct __file {
    [build]       |        ^~~~~~
    [build] In file included from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/cstdio:47,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/ext/string_conversions.h:47,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/bits/basic_string.h:4500,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/string:58,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/bits/stdexcept_throw.h:57,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/bitset:49,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/i386-dosloader-elf/bits/stdc++.h:52,
    [build]                  from /toolchains/dosloader-toolchain-x86_64-linux-musl/lib/gcc/i386-dosloader-elf/16.0.1/include/c++/bits/std.cc:26,
    [build] of module std, imported at /home/user/Development/dosloader/examples/filesystem.cpp:1:
    [build] /toolchains/dosloader-toolchain-x86_64-linux-musl/i386-dosloader-elf/include/stdio.h:89:8: note: previous declaration as 'struct __file'
    

    Während:

    #include <stdio.h>
    
    import std;
    
    auto main() -> int
    {
    }
    

    wunderbar funktioniert.

    Warum es bei dir allerdings nur mit -freflection knallt, kann ich nicht sagen. Ich hätte erwartet, das würde auch ohne Reflection und nur mit Modulen passieren.

    Edit: Noch ein anderes Detail, wenn du mal eigene Module baust, dann dürfen z.B. solche #includes auch nur im Global Module Fragment stehen:

    module;
    
    #include <stdio.h>
    
    module mymodule;
    
    ...
    

    Das nur so am Rande, da gibt es generell spezielle Regeln, wenn man beide Methoden (Module und #include) mischen will.



  • @Finnegan sagte in GCC 16.1.0 und Modules:

    Warum es bei dir allerdings nur mit -freflection knallt, kann ich nicht sagen. Ich hätte erwartet, das würde auch ohne Reflection und nur mit Modulen passieren.

    Edit: Noch ein anderes Detail, wenn du mal eigene Module baust, dann dürfen z.B. solche #includes auch nur im Global Module Fragment stehen:

    module;
    
    #include <stdio.h>
    
    module mymodule;
    
    ...
    

    Das nur so am Rande, da gibt es generell spezielle Regeln, wenn man beide Methoden (Module und #include) mischen will.

    Ja, die Reihenfolge ist beim Import von Modulen bzw. Headern wichtig. Ich nutze nicht nur Module, sondern erstelle ein eigenes. Was bisher auch gut funktioniert hat, und ohne „-freflection“ es auch weiterhin tut.

    Ich versuche mich seit GCC 13.x.x an Modulen. Seit GCC 14.1.0 funktioniert es soweit, dass man es auch benutzen kann. Am Anfang musste man noch die Header Modulisieren und einzeln importieren z.B.

    #import <stdio>;
    

    Das hat so einiges an Aufwand im Makefile nach sich gezogen, damit man das automatisch bauen konnte. Das Module std ist da ein großer Fortschritt. Mein Modul fängt wie folgt an

    module;
    
    #include <locale.h>
    #include <ncursesw/ncurses.h>
    #include <signal.h>
    
    import std;
    
    export module xxx;
    

    Das funktionierte bisher tadellos. Mit GCC 16.1.0 kam nun das Modul std.compat dazu. In dem wie all die Jahrzehnte zuvor die Deklarationen weiterhin global erfolgen. Z.B. ist size_t im Modul std als ::std::size_t deklariert, und im Modul std.compat weiterhin ( es müsste zusätzlich deklariert sein) als ::size_t, wie man das von den C Headern gewohnt ist.

    Da ich das Modul std verwende (ging ja bisher nicht anders) wundert mich das um so mehr, weshalb es diese Kollision mit dem C Header gibt, denn die Deklarationen sollten gerade nicht mehr im globalen Namensraum erfolgen. Mit dem Modul std.compat gibt es das gleiche Ergebnis. Wahrscheinlich gibt es einfach noch Bugs im Kontext der Reflection Implementation. Was natürlich die Frage aufwirft, wie brauchbar momentan die Implementation ist. Wahrscheinlich muss man auf 16.2.0 warten.

    Danke fürs Anschauen!


Anmelden zum Antworten