SDL2 Cross Compilieren



  • Diese Minibeispiel lässt sich problemlos unter Linux compilieren.

    $ gcc main.c -o main -lSDL2
    
    #include <SDL2/SDL.h>
    #include <stdio.h>
    
    int main(int argc, char* argv[]) {
        SDL_Init(SDL_INIT_VIDEO);   
        SDL_Window *window = SDL_CreateWindow("An SDL2 window", 0, 0, 640, 480, SDL_WINDOW_OPENGL);
        SDL_Delay(3000);  
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 0;
    }
    

    Jetzt wollte ich eine Win64 Version compilieren.
    Also habe ich folgendes probiert.

    $ 86_64-w64-mingw32-gcc main.c -o main -lSDL2
    

    Nur spuckt mir der Compiler folgende Fehlermeldung aus:

    main.c:1:10: fatal error: SDL2/SDL.h: Datei oder Verzeichnis nicht gefunden
        1 | #include <SDL2/SDL.h>
          |          ^~~~~~~~~~~~
    compilation terminated.
    

    Einer eine Idee, wie ich das umgehen kann ?



  • Hat du überhaupt eine mingw kompatible version von SDL installiert?
    Und unter windows gibt es auch kein default verzeichniss in denen headers installiert werden wie unter linux (z.b. wenn die diese vom package manager installiert werden)
    DU musst dann hier schon den Pfad zu den header dateien dem kompiler mitteilen.
    Und das gleiche gilt auch für den pfad zu den libraries die gelinkt werden sollen



  • @firefly sagte in SDL2 Cross Compilieren:

    Hat du überhaupt eine mingw kompatible version von SDL installiert?

    Ich habe nur die Linux-Version. Aber ich dachte, der Cross-Compiler verwendet die gleichen Includes.
    Eine SDL2.DLL habe ich auch.



  • Ein kleiner Schritt bin ich weiter gekommen, nun findet er das SDL2 Zeugs.

    $ x86_64-w64-mingw32-gcc main.c -o main -lSDL2 -I/usr/include -I/usr/include/x86_64-linux-gnu
    

    Dafür hat er jetzt mit den Integer-Typen ein Durcheinander.

    x86_64-w64-mingw32-gcc main.c -o main -lSDL2 -I/usr/include -I/usr/include/x86_64-linux-gnu
    In file included from /usr/share/mingw-w64/include/crtdefs.h:10,
                     from /usr/share/mingw-w64/include/stddef.h:7,
                     from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/stddef.h:1,
                     from /usr/include/x86_64-linux-gnu/sys/types.h:144,
                     from /usr/include/SDL2/SDL_stdinc.h:40,
                     from /usr/include/SDL2/SDL_main.h:25,
                     from /usr/include/SDL2/SDL.h:32,
                     from main.c:1:
    /usr/share/mingw-w64/include/corecrt.h:50:35: error: conflicting types for ‘ssize_t’
       50 | __MINGW_EXTENSION typedef __int64 ssize_t;
          |                                   ^~~~~~~
    In file included from /usr/include/SDL2/SDL_stdinc.h:40,
                     from /usr/include/SDL2/SDL_main.h:25,
                     from /usr/include/SDL2/SDL.h:32,
                     from main.c:1:
    /usr/include/x86_64-linux-gnu/sys/types.h:108:19: note: previous declaration of ‘ssize_t’ was here
      108 | typedef __ssize_t ssize_t;
          |                   ^~~~~~~
    In file included from /usr/share/mingw-w64/include/crtdefs.h:10,
                     from /usr/share/mingw-w64/include/stddef.h:7,
                     from /usr/lib/gcc/x86_64-w64-mingw32/10-win32/include/stddef.h:1,
                     from /usr/include/x86_64-linux-gnu/sys/types.h:144,
                     from /usr/include/SDL2/SDL_stdinc.h:40,
                     from /usr/include/SDL2/SDL_main.h:25,
                     from /usr/include/SDL2/SDL.h:32,
                     from main.c:1:
    /usr/share/mingw-w64/include/corecrt.h:143:20: error: conflicting types for ‘time_t’
      143 | typedef __time64_t time_t;
    
    

    Hat du überhaupt eine mingw kompatible version von SDL installiert?

    So wie es scheint muss ich SDL2 noch irgendwie nach /usr/share/mingw-w64/include/c zaubern.



  • Wieso motzt er noch ?
    Er hat ja die DLL vor seiner Nase.

    $ x86_64-w64-mingw32-gcc main.c -o main -lSDL2 -I/usr/share/mingw-w64/include
    /usr/bin/x86_64-w64-mingw32-ld: -lSDL2 kann nicht gefunden werden: Datei oder Verzeichnis nicht gefunden
    collect2: error: ld returned 1 exit status
    
    $ ls
    main  main.c  SDL2.dll
    
    


  • Ein Include Verzeichnis ist kein Verzeichnis für den Linker. Mit der Option -L kann man Pfade für den Linker setzen.



  • @john-0 sagte in SDL2 Cross Compilieren:

    Ein Include Verzeichnis ist kein Verzeichnis für den Linker. Mit der Option -L kann man Pfade für den Linker setzen.

    Die habe ich jetzt gemacht und bekomme folgenden Fehler:

    $ x86_64-w64-mingw32-gcc main.c -o main.exe -lSDL2 -I/usr/share/mingw-w64/include -L.
    /usr/bin/x86_64-w64-mingw32-ld: /usr/lib/gcc/x86_64-w64-mingw32/10-win32/../../../../x86_64-w64-mingw32/lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): in function `main':
    ./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt/./mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain'
    collect2: error: ld returned 1 exit status
    

    Die konnte ich jetzt auch umgehen, in dem ich main durch WinMain ersetzte.

    int WinMain(int argc, char* argv[]) {
     ...
    }
    

    Jetzt läuft das Programm wie es sein soll. Nur jetzt die Frage, wieso braucht der WinMain ?



  • Setze mal das Makro SDL_MAIN_HANDLED direkt vor dem Einbinden des SDL-Headers, s.a. undefined reference to WinMain@16 C++, SDL-2 sowie die offizielle Doku SDL_SetMainReady.



  • Wobei das ganze komplett falsch ist.
    WinMain ist anders definiert unter windows. Daher wird dein Programm dort nicht laufen.
    https://learn.microsoft.com/en-us/windows/win32/learnwin32/winmain--the-application-entry-point

    Der Windows build von SDL bietet eine eigene winmain implementierung an, welche dann die standard c main methode aufruft.
    Diese gibt es als separate library siehe auch https://github.com/msys2/MINGW-packages/issues/6379

    @Mathuas du solltest dich aber vorher generell mal mit dem thema cross compiling linux->Windows beschäftigen. Bzw. Mit der Entwicklung von SDL programmen unter windows
    Das die ganzen Probleme/Fragen ergeben sich nur aus deinem Unwissen über die entsprechenden Themen.

    Da stellt sich mir dir Frage wieso überhaupt du das ganze überhaupt via crosscompiling lösen möchtest.
    Da wäre es doch einfacher das Programm unter windows zu bauen (das geht dann auch mit mingw)



  • @firefly sagte in SDL2 Cross Compilieren:

    @Mathuas du solltest dich aber vorher generell mal mit dem thema cross compiling linux->Windows beschäftigen. Bzw. Mit der Entwicklung von SDL programmen unter windows
    Das die ganzen Probleme/Fragen ergeben sich nur aus deinem Unwissen über die entsprechenden Themen.

    In der Pascal/Lazarus Welt mache ich dies schon sehr lange. Etwas in Linux entwickeln und wen alles läuft das ganze über den Cross-Compiler laufen lassen und schon hat man eine Windows-Version.
    Daher wollte ich es auch mit C versuchen. So wie es schien, habe ich unter Linux alle Werkzeuge zur Verfügung.

    Da stellt sich mir dir Frage wieso überhaupt du das ganze überhaupt via crosscompiling lösen möchtest.

    Da ich mich schon fast komplett von Windows gelöst habe, ich habe es nur noch in einer VB am laufen.

    Da wäre es doch einfacher das Programm unter windows zu bauen (das geht dann auch mit mingw)

    An das habe ich auch schon gedacht, so wie ich es am Rande mitbekommen habe, sollte dies auch mit wine laufen. Wen ich mich nicht täusche, ist mingw der klein Bruder von cygwin ?



  • @Mathuas sagte in SDL2 Cross Compilieren:

    Jetzt läuft das Programm wie es sein soll. Nur jetzt die Frage, wieso braucht der WinMain ?

    Meines Wissens gibt es unter Windows zwei "Subsytsem"-Typen, wobei der für das Programm verwendete vom Linker im Header der PE-.exe hinterlegt wird ("Subsystem"-Feld) - einmal "Konsolen-Programm" und einmal "Windows-Programm".

    Windows-Programme (GCC/Clang: -mwindows / MSVC: -subsystem:windows, könnte bei dir evtl. "Default" sein) öffnen bei der Ausführung kein Konsolenfenster und erwarten eine WinMain-Funktion.

    Konsolen-Programme (GCC/Clang: -mconsole / MSVC: -subsystem:console) machen beim Ausführen ein Konsolenfenster auf (sofern sie nicht bereits aus einem heraus aufgerufen wurden) und benötigen lediglich eine klassische main-Funktion.

    Während der Entwicklung ist -mconsole ganz nett, da es unkomplizierte Textusgaben mit printf, std::cout oder write(fileno(stdout), ...) ermöglicht und das nicht bedeutet, dass man damit keine Windows- oder SDL-Fenster erstellen kann. Man hat halt lediglich immer noch ein zusätzliches Konsolenfenster, wo sich z.B. Statusmeldungen loggen lassen. Wenn du also keine WinMain möchtest und dich das Konsolenfenster nicht stört, wäre dem Compiler -mconsole mitzugeben eventuell eine Option. Du solltest aber recherchieren (oder einfach ausprobieren), ob SDL dabei eventuell eine etwas andere Initialisierung benötigt, da kenne ich mich nicht genau aus.



  • @Mathuas sagte in SDL2 Cross Compilieren:

    @firefly sagte in SDL2 Cross Compilieren:

    Da stellt sich mir dir Frage wieso überhaupt du das ganze überhaupt via crosscompiling lösen möchtest.

    Da ich mich schon fast komplett von Windows gelöst habe, ich habe es nur noch in einer VB am laufen.

    Da wäre es doch einfacher das Programm unter windows zu bauen (das geht dann auch mit mingw)

    An das habe ich auch schon gedacht, so wie ich es am Rande mitbekommen habe, sollte dies auch mit wine laufen. Wen ich mich nicht täusche, ist mingw der klein Bruder von cygwin ?

    Ich finde den Crosscompiling-Ansatz eigentlich ganz gut, sofern dein Primäres OS ohnehin ein anderes ist. Das ermöglicht dir, das Projekt in einem einzigen Build-Prozess für alle unterstützten Zielplattformen zu bauen, ohne dabei umständlich das OS wechseln zu müssen. Aber es stimmt schon, dass Crosscompiling oft etwas komplizierter ist, besonders wenn die Projekte nicht darauf ausgelegt sind (und z.B. Tools und Tests, die während des Build-Prozesses ausgeführt werden sollen, einfach für die Zielplattform kompilieren anstatt für die "Build"-Plattform und dann vor die Wand laufen). Dabei kann man allerdings eine Menge lernen 😁

    Auch braucht man für eventuelle eigene, plattformspezifische Tests einen Mechanismus, mit dem man die ausführen kann - z.B. indem eine VM gestartet wird, mit Wine, oder eben "manuell" auf dem jeweiligen Zielsystem.

    Von Linux zu Windows ist meiner Erfahrung nach auch etwas leichter als umgekehrt, besonders was Projekte angeht, die primär für Linux entwickelt wurden (Build-Skripte, die ein vollwertiges Linux-System erwarten, Symbolische Links die nicht richtig erstellt werden oder auch Dateinamen, die erfordern, dass das Dateisystem zwischen Groß/Kleinschreibung unterscheidet - die Linux-Header haben z.B. ein paar solcher Dateien). Um z.B. einen GCC-Compiler für Windows zu bauen bin ich daher irgendwann auf einen Linux-Container umgestiegen, der eine GCC/MinGW-Version für Windows auf einem Linux-System cross-kompiliert, anstatt direkt unter Windows zu bauen. Das ist wesentlich einfacher, obwohl es in dem Fall ein (noch komplizierteres) sog. "Canadian Cross" war, auf Linux einen Compiler für Windows bauen, mit dem man Linux-Programme kompilieren kann (die Konstellation gibts aber nur, wenn man Compiler baut).

    Zu deiner Cygwin/MinGW-Frage: Ich glaube die haben einen gemeinsamen Ursprung, aber MinGW ist im Gegensatz zu Cygwin keine POSIX-Kompatibilitätsschicht, sondern eine GCC-kompatible C-Standardbibliothek (libc) für Windows und eine Implementierung der Windows-API-Header (und auch solche Sachen wie DirectX). Ziel ist es, Windows-Programme mit GCC (oder auch Clang im GCC-Modus) kompilieren zu können. Die Linux-Kompatibilität spielt dabei nur am Rande eine Rolle, z.B. wenn es um zentrale Funktionen der libc geht, für die es unter Windows keine direkte Entsprechung gibt, die aber von vielen Programmen/Bibliotheken verwendet werden. Wie das "Min" im Namen schon sagt, fokussiert sich MinGW auf das "Minimum", um für Linux entwickelte Programme und Bibliotheken lauffähig zu machen, während Cygwin eher versucht möglichst vollständig POSIX-kompatibel zu sein. Daher muss man für MinGW-Kompatibität Windows auch meist aktiv im Programmcode unterstützen (Compiler-Switches, plattformspezifische #ifdefs und sowas), während man mit Cygwin eventuell damit durchkommt, bei der Entwickung ausschließlich Linux zu berücksichtigen.



  • @Finnegan sagte in SDL2 Cross Compilieren:

    Von Linux zu Windows ist meiner Erfahrung nach auch etwas leichter als umgekehrt, besonders was
    Projekte angeht, die primär für Linux entwickelt wurden

    Die ist bei FPC/Lazarus das Gleiche. Linux ist die besser Basis. Auch wen man für den Raspi etwas entwickelt hat dies Vorteile. Ich habe Windows sowieso nur noch, um etwas auszuprobieren. ZB. um zu gucken ob das Cross compilierte Programm läuft.

    Zu deiner Cygwin/MinGW-Frage: Ich glaube die haben einen gemeinsamen Ursprung, aber MinGW...

    Wen ich mal Zeit und Lust habe werde ich das mal genauer angucken. Ich hatte mal vor vielen Jahren,, etwa 15-20 Jahren, als ich noch primär Windows verwendete, Cygwin installiert. Es war dazumal schon spannend.
    Ich denke da ist unterdessen sicher auch noch einiges gegangen. Auch Linux hat sich in dieser Zeit recht entwickelt.



  • @Finnegan sagte in SDL2 Cross Compilieren:

    Windows-Programme (GCC/Clang: -mwindows / MSVC: -subsystem:windows, könnte bei dir evtl. "Default" sein) öffnen bei der Ausführung kein Konsolenfenster und erwarten eine WinMain-Funktion.
    Konsolen-Programme (GCC/Clang: -mconsole / MSVC: -subsystem:console) machen beim Ausführen ein Konsolenfenster auf (sofern sie nicht bereits aus einem heraus aufgerufen wurden) und benötigen lediglich eine klassische main-Funktion.

    Bringt leider nichts, das WinMain Problem besteht immer noch.

    Einzig was momentan hilft ist dies:

    int WinMain(int argc, char* argv[]) {
      main(argc, argv);
    }
    

    Übrigens mit SDL3 besteht das Problem nicht, da geht ganz normal main().



  • @Mathuas sagte in SDL2 Cross Compilieren:

    Bringt leider nichts, das WinMain Problem besteht immer noch.

    Gut möglich. Ich habe den main/WinMain-Zusammenhang auch nur generisch beschrieben, SDL kenne ich kaum. Natürlich gibt es auch wenn der Compiler mit -mconsole keinen WinMain-Einstiegspunkt mehr erwartet die Möglichkeit, dass SDL diese Funktion irgendwo explizit referenziert. Das würde dann ebenfalls zu diesem Fehler führen.



  • @Mathuas sagte in SDL2 Cross Compilieren:

    Nochwas: Ich denke, diese WinMain-Signatur ist nicht korrekt und kann wegen der zu wenigen Parameter zu subtilen Fehlern führen (abgesehen davon, dass die ersten ohnehin nicht die richtigen argc und argv sind):

    int WinMain(int argc, char* argv[]) {
      main(argc, argv);
    }
    

    Ich denke das hier ist wahrscheinlich besser als "schnelle Lösung" (siehe hier):

    #include <windows.h>
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
    {
        char* argv[1] = { 0 };
        main(0, argv);
    }
    

    Die Kommandozeile wird der WinMain soweit ich weiß als zusammenhängender String in pCmdLine übergeben. Um argc und argv korrekt zu initialisieren, müsste man daher die Kommandozeile wahrscheinlich erstmal selbst parsen - daher nur diese Quick&Dirty-Lösung.



  • @Mathuas Du solltest dir Unbedingt die Doku von SDL2 mal genauer durchlesen.
    Besonders den Part wie das ganze unter Windows funktioniert.

    Aktuell bist du nur blind am rumstochern



  • @Mathuas Was lange währt, wird endlich gut. 😉 Lass dich von firefly nicht ins Bockshorn jagen.


Anmelden zum Antworten