Win32 auf Linux kompilieren

Dank dem Windows Subsystem für Linux (WSL) können wir also unter Windows 10 native Linux Binaries kompilieren.
Aber wie sieht es anders herum aus?

Dank dem guten alten MinGW können wir auch unter Linux native Windows Binärprogramme erstellen lassen.

Heißt also konkret: Der nächste GATE Build für Windows wird am Raspberry PI laufen …


MinGW installieren

Für Debian und Ubuntu könnte es einfacher nicht sein:

1sudo apt install gcc-mingw-w64 -y
2sudo apt install g++-mingw-w64 -y

Die Installation liefert alles, was notwendig ist, also Compiler und alle nötigen WinAPI Header für die meisten Anwendungsfälle.

Und mit x86_64-w64-mingw32-g++ --version sieht man ob die Installation erfolgreich war. Jetzt könnte man schon manuell kompilieren … aber wie sieht es mit CMake aus?

CMake Toolchain anpassen

CMake nutzt für gewöhnlich den Standard GCC eines Systems, wenn man keine weiteren Parameter setzt.
Um dieses Tool mit MinGW anzufreunden, nutzen viele OpenSource Projekte eine Toolchain-Datei, die nötige Parameter setzt.

Die könnte mingw-w64-x86_64.cmake heißen und sieht dann etwa so aus:

 1set(CMAKE_SYSTEM_NAME Windows)
 2set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
 3
 4set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
 5set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
 6set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
 7set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
 8
 9set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
10
11set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
12set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
13set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Nun startet man CMake mit dem Parameter CMAKE_TOOLCHAIN_FILE mit dem Pfad zur Datei und schon bereitet CMake alles vor. Per ccmake kann man letzte Flags im Cache bequem einstellen, oder man übergibt diese als Parameter direkt an das cmake Kommando. Am Ende kann dann ein reguläres make den Build anstoßen.

1cd build-dir
2cmake -DCMAKE_TOOLCHAIN_FILE=path/to/mingw-w64-x86_64.cmake path/to/sources
3ccmake path/to/sources
4make

Und wenn man kein 64-bit Build, sondern nur 32-bit möchte,
ersetzt man set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
durch set(TOOLCHAIN_PREFIX i686-w64-mingw32).

WinAPI Header Verweise anpassen

Sourcen aus dem MSDN oder diversen Codebeispielen nutzen gerne Headerverweise mit Großbuchstaben. Das funktioniert dann unter Linux nicht, denn MinGW stellt alle WinAPI-Header nur mit Kleinbuchstaben zur Verfügung.

Hat man also Einträge wie z.B.:

1#include "Winsock2.h"
2#include "Windows.h"

müssen diese auf "winsock2.h", "windows.h" und so weiter angepasst werden.

Das war auch im GATE Projekt schon längst notwendig.

Fazit

Ähm … hätte mir mal vor 15 Jahren jemand gesagt, dass es so leicht sei, Windows Programme unter Linux und umgekehrt zu kompilieren, hätte ich überheblich gelacht und gemeint:

Na dann viel Spaß beim manuellen Schreiben der Konfiguration!

Aber mit CMake und MinGW ist das echt komfortabel geworden.
Und das bedeutet, dass man sich nicht mehr ewig lange mit dem Setup von Windows und der MSVC Toolchain abmühen muss, denn nun läuft der Windows Build einfach auf einer Linux VM mit, und diese sind in vielen Cloud-Lösungen wesentlich günstiger zu bekommen als entsprechende Windows-Umgebungen.

Und das GATE Framework lässt sich nun tatsächlich vollständig auf dem Raspberry PI für Windows bauen.

… also eine “echt geniale Sache”!