C++ & GUI & Windows
Welcher C++ Entwickler kennt nicht das Problem: Wie erzeuge ich unter Windows GUI Anwendungen ohne dabei ein Vermögen für eine Entwicklungsumgebung wie MS Visual Studio, Qt oder Embarcadero C++ Builder auszugeben?
(Fast) Ganz einfach: mit Code::Blocks, MinGW und wxWidgets.
Leider ist die erste Einrichtung der Entwicklungsumgebung mit relativ viel Handarbeit verbunden, weswegen ich hier einmal eine Anleitung zusammenstelle.
C::B & wxWidgets – die Installation
Ziel der folgende Schritte ist es diese Pakete zu installieren:
- Code::Blocks in seiner aktuellsten Binärversion (derzeit 17.12)
- MinGW: Eine Version >= 5.3, (ältere Versionen haben mir diverse Probleme bereitet)
- wxWidgets: die letztaktuelle stabile Version (3.0.4).
Let’s go!
Code::Blocks
Hier werde ich erst mal folgende Version herunterladen und installieren:
http://www.codeblocks.org/downloads/26
Ich habe mich für die Version codeblocks-17.12-setup.exe entschieden, da ich MinGW separat installieren möchte und da ich dennoch nicht auf den Installer verzichten möchte.
MinGW
http://www.mingw.org/category/wiki/download
Der Installer hat mich relativ schnell überzeugt, die Version 6.3.0 zu installieren. Grund: er hat mir keine andere angeboten. Jetzt bleibt nur noch zu hoffen, dass diese Version mit wxWidgets und mit Code::Blocks konform geht.
Entgegen meiner ursprüglichen Planung habe ich MinGW nun doch in den Pfad c:\MinGW installiert. Eigentlich wollte ich MinGW in einem Unterverzeichnis von Code::Blocks führen, doch dann habe ich an die zahlreichen Pfadangaben gedacht, die in dieses Verzeichnis zeigen sollten. Kürzer ist da wohl besser.
Apropos Pfad: Der erste zu setzende Pfad ist hier natürlich c:\mingw\bin im Windows System Pfad. Unter Windows 10 sollte der dann auch gleich ganz nach oben geschoben werden, sonst haben wir wieder einmal ein komisches Verhalten.
wxWidgets
https://www.wxwidgets.org/downloads/
Hier verhalte ich mich ausgesprochen feige, denn ich lade tatsächlich die „stable“ version herunter. Derzeit 3.0.4
Der Installer entpackt lediglich die Dateien in ein Verzeichnis meiner Wahl. Mein Wahl lautet: C:\wxWidgets\wxWidgets-3.0.4
Dadurch kann ich später vielleicht einmal mehrere Version parallel installieren.
Los gehts mit der Installation von wxWidgets, denn das will noch kompiliert werden und zwar auf die richtige Weise.
Hier ist besonders zu berücksichtigen, dass die Compiler-Flags gleich sein sollten, wie sie dann später im Code::Blocks projekt Verwendung finden sollen.
Die Kompilierung erfolgt im wx-Widgets-Verzeichnis build/msw, denn dort finden sich auch die Makefiles. Mich interessiert hier nur makefile.gcc.
Zuerst aber einmal ein Test, ob die Pfade auch richtig gesetzt wurden:
C:\wxWidgets\wxWidgets-3.0.4\build\msw>mingw32-make -v GNU Make 3.82.90 Built for i686-pc-mingw32 Copyright (C) 1988-2012 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. C:\wxWidgets\wxWidgets-3.0.4\build\msw>gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe Target: mingw32 Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nls Thread model: win32 gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) C:\wxWidgets\wxWidgets-3.0.4\build\msw>
Prächtig!
C::B & MinGW 6.x.x
Da ich gcc 6.3.0 verwende muss ich zuerst eine Zeile in c:\mingw\include\stdio.h auskommentieren: Die Zeile 345
// extern int __mingw_stdio_redirect__(snprintf)(char*, size_t, const char*, ...);
Warum das so ist? Nähere Informationen hierzu weiter unten!
wxWidgets & Multicore Kompilierung
Da es eine halbe Ewigkeit dauert wxWidgets zu kompilieren, meine Workstation aber mit 32 Kernen ausreichend Power hat, wäre es vernünfigt den Multicore-Parameter „-jN“ zu verwenden: Also „mingw32-make -j16 -f makefile.gcc …“
Leider verbirgt sich in makefile.gcc ein Bug, sodass das Ziel für setup_h separat kompiliert werden muss (vgl. diese Quelle). Im Klartext heisst dies, die Kompilierung muss in zwei (eigentlich drei) einzelnen Schritten vorgenommen werden:
- mingw32-make … clean
- mingw32-make … setup_h
- mingw32-make …
mingw32-make -j16 -f makefile.gcc CXXFLAGS="-fno-keep-inline-dllexport" BUILD=debug UNICODE=1 SHARED=1 MONOLITHIC=1 clean mingw32-make -j16 -f makefile.gcc CXXFLAGS="-fno-keep-inline-dllexport" BUILD=debug UNICODE=1 SHARED=1 MONOLITHIC=1 setup_h mingw32-make -j16 -f makefile.gcc CXXFLAGS="-fno-keep-inline-dllexport" BUILD=debug UNICODE=1 SHARED=1 MONOLITHIC=1
Das Flag „-j16“ ist die Anzahl der Prozessorkerne, die GCC verwenden soll. Das muss freilich angepasst werden.
Das Ganze muss natürlich für die Release-Variante mit BUILD=release noch einmal wiederholt werden.
wxWidgets & c++14
Mit den entsprechenden CXXFLAGS unternahm ich den Versuch wxWidgets mit c++14 zu kompilieren.
CXXFLAGS="-fno-keep-inline-dllexport -std=c++14"
Dieser Versuch war allerdings alles andere als erfolgreich:
g++ -c -o gcc_mswuddll\monodll_arcfind.o -g -O0 -mthreads -DHAVE_W32API_H -D__WXMSW__ -D_UNICODE -I..\..\lib\gcc_dll\mswud -I..\..\include -W -Wall -DWXBUILDING -I..\..\src\tiff\libtiff -I..\..\src\jpeg -I..\..\src\png -I..\..\src\zlib -I..\..\src\regex -I..\..\src\expat\lib -I..\..\src\stc\scintilla\include -I..\..\src\stc\scintilla\lexlib -I..\..\src\stc\scintilla\src -D__WX__ -DSCI_LEXER -DLINK_LEXERS -DwxUSE_BASE=1 -DWXMAKINGDLL -Wno-ctor-dtor-privacy -fno-keep-inline-dllexport -std=c++14 -MTgcc_mswuddll\monodll_arcfind.o -MFgcc_mswuddll\monodll_arcfind.o.d -MD -MP ../../src/common/arcfind.cpp In file included from ..\..\include/wx/stream.h:21:0, from ..\..\include/wx/archive.h:16, from ..\..\include/wx/zipstrm.h:16, from ../../src/common/arcall.cpp:19: ..\..\include/wx/filefn.h: In function 'int wxAccess(const wxString&, mode_t)': ..\..\include/wx/Ifn fililee incflnu.dhed :f5r2om ..8\:..4\6i: error: '_waccess' was not declared in this scope { return wxCRT_Access(path.fn_str(), mode); } nclude/wx/stream.h:21:0, from ..\..\include/wx/archive.h:16, from ../../src/common/arcfind.cpp:18: ..\..\include/wx/filefn.h: In function 'int wxAccess(const wxString&, mode_t)': ..\..\include/wx/filefn.h:528:46: error: '_waccess' was not declared in this scope { return wxCRT_Access(path.fn_str(), mode); } ^
wxWidgets mit c++14 werde ich daher auf später verschieben und die bekanntermaßen funktionierenden CXXFLAGS verwenden:
CXXFLAGS="-fno-keep-inline-dllexport -std=gnu++11"
Starten von Code::Blocks und ein neues Projekt
Nach dem Klick auf Close kam dann die Fehlermeldung „Please select a valid location“. OK, hab ich vielleicht nicht richtig verstanden, daher werde ich einfach mal den richtigen Pfad noch einmal eingeben.
Am Ende kommen noch immer die seltsamen Warnungen vom Anfang, aber ich werde sie einfach mal ignorieren.
Sollte der erste Kompilierungsversuch scheitern – Keine Panik! Es hat mit höchster Wahrscheinlichkeit mit fehlenden oder falschen Pfadangaben zu tun. Und zu diesen Fragen gibt es im Rest dieses Beitrags mit ziemlicher Sicherheit die richtige Antwort.
Die klassischen Fehlerfälle
Nachdem ich in der Vergangenheit etliche Installationen von wxWidgets vorgenommen habe, kann ich inzwischen mit einer ganzen Liste an Fallstricken und deren Lösungen aufwarten und bin auch gerne bereit, diese mit meinen Mitmenschen aus der C++ommunity zu teilen.
Teil 1: Bei der Installation von wxWidgets
extern int __mingw_stdio_redirect__(snprintf)(char*, size_t, const char*, …);
Man möchte wxWidgets mit einem neueren GCC kompilieren, doch leider schlägt das schon nach wenigen Zeilen fehl:
gcc -c -o gcc_mswuddll\wxtiff_tif_win32.o -g -O0 -mthreads -DHAVE_W32API_H -DNDEBUG -I..\..\src\zlib -I..\..\src\jpeg -I..\..\src\tiff\libtiff -MTgcc_mswuddll\wxtiff_tif_win32.o -MFgcc_mswuddll\wxtiff_tif_win32.o.d -MD -MP ../../src/tiff/libtiff/tif_win32.c In file included from ../../src/tiff/libtiff/tiffio.h:257:0, from ../../src/tiff/libtiff/tiffiop.h:59, from ../../src/tiff/libtiff/tif_win32.c:30: c:\mingw\include\stdio.h:345:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before '__mingw__snprintf' extern int __mingw_stdio_redirect__(snprintf)(char*, size_t, const char*, ...); ^ makefile.gcc:5942: recipe for target 'gcc_mswuddll\wxtiff_tif_win32.o' failed mingw32-make: *** [gcc_mswuddll\wxtiff_tif_win32.o] Error 1
An anderer Stelle habe ich allerdings gelesen, dass wir die Stelle einfach auskommentieren können, damit wxWidgets sich auch mit MinGW 6.3 kompilieren lässt.
Also weg mit der Zeile aus c:\mingw\include\stdio.h:
extern int __mingw_stdio_redirect__(fprintf)(FILE*, const char*, ...); extern int __mingw_stdio_redirect__(printf)(const char*, ...); extern int __mingw_stdio_redirect__(sprintf)(char*, const char*, ...); // extern int __mingw_stdio_redirect__(snprintf)(char*, size_t, const char*, ...); extern int __mingw_stdio_redirect__(vfprintf)(FILE*, const char*, __VALIST); extern int __mingw_stdio_redirect__(vprintf)(const char*, __VALIST); extern int __mingw_stdio_redirect__(vsprintf)(char*, const char*, __VALIST); extern int __mingw_stdio_redirect__(vsnprintf)(char*, size_t, const char*, __VALIST);
…weiter gehts.
Teil 2: Beim ersten Programm
Nachdem nun wxWidgets erfolgreich kompiliert und installiert wurde, gehen wir mit voller Enthusiasmus und Elan an unser erstes Projekt… und scheitern!
Das liegt zumeist an fehlerhaften oder gar fehlenden Einstellungen innerhalb vom Projekt selbst. Daher: hier die Top-Favoriten solcher Fehler.
_waccess was not declared in this scope
Kaum will man das erste „Hello World“ kompilieren, rasseln schon die ersten Fehler daher. Wir starten meist mit dem selben:
=== Build: Debug in ChatClient (compiler: GNU GCC Compiler) === In function 'int wxAccess(const wxString&, mode_t)' error: '_waccess' was not declared in this scope In function 'int wxChmod(const wxString&, mode_t)' error: '_wchmod' was not declared in this scope In function 'int wxOpen(const wxString&, int, mode_t)' error: '_wopen' was not declared in this scope In function 'int wxStat(const wxString&, _stati64*)' error: '_wstati64' was not declared in this scope In function 'int wxLstat(const wxString&, _stati64*)' error: '_wstati64' was not declared in this scope In function 'int wxAccess(const wxString&, mode_t)' error: '_waccess' was not declared in this scope In function 'int wxChmod(const wxString&, mode_t)' error: '_wchmod' was not declared in this scope In function 'int wxOpen(const wxString&, int, mode_t)' error: '_wopen' was not declared in this scope In function 'int wxStat(const wxString&, _stati64*)' error: '_wstati64' was not declared in this scope In function 'int wxLstat(const wxString&, _stati64*)' error: '_wstati64' was not declared in this scope === Build failed: 10 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===
Bildlich gesprochen:
Glücklicherweise ist diese Problem sehr schnell behoben, in dem wir die korrkten CXXFLAGS angeben:
-std=gnu++11
Das Projekt will mit den gleichen CXXFLAGS kompiliert werden, mit denen auch wxWidgets kompiliert wurde. Daher gilt für uns:
wx/setup.h: No such file or directory
Der Klassiker, wenn wir ein neu angelegtes wxWidgets-Projekt erstmalig kompilieren wollen: Der Header setup.h wird nicht gefunden.
Im Verzeichnis include/wx befinden sich die Dateien setup_inc.h und setup_redirect.h und in manchen Foren wird beschrieben, wie diese denn anzupassen seien, damit der Fehler verschwindet. Das ist jedoch keine gute Idee.
Ursache und Lösung
wxWidgets benötigt für die Lauffähigkeit unter MS Windows eine separate setup.h und diese befindet sich in einem Unterverzeichnis, das wir dem Compiler bekannt machen müssen.
Unter Menü / Project / Build Options… müssen daher folgende Pfade ergänzt werden:
Für die Release Version: <wxWidgets>\lib\gcc_dll\mswu
Für die Debug Version: <wxWidgets>\lib\gcc_dll\mswud
cannot find -lwxmsw30ud
Im selben Kontext von „wx/setup.h“ vermisst auch der Linker seine Dateien. Dies ist der Fall, wenn folgender Pfade nicht angeben wurde:
Menü / Project / Build Options… / Search directories / Linker
<wxWidgets>lib\gcc_dll
Nachdem dieser Pfad richtig eingeben wurde, werden auch gleich die „Link libraries“ gefunden und auch richtig zugeordnet:
Release
Debug
Anschließend sollte sich das Programm problemlos kompilieren lassen.
Diverse Links
http://wiki.codeblocks.org/index.php?title=Compiling_wxWidgets_3.0.0_to_develop_Code%3a%3aBlocks_(MSW)
https://forums.wxwidgets.org/viewtopic.php?t=43501
c++14
https://forums.wxwidgets.org/viewtopic.php?t=43085
Hallo Herwig, vielen Dank für diese Anleitung.
Wenn ich Code::Blocks unter Ubuntu aus den Repositories installiere dann dauert das ca. 30 Sekunden und anschließend kann ich sofort meine erste Gnome-GUI-Demo kompilieren. Das nenne ich ein Erfolgserlebnis.
Warum ist unter Windows schon die reine Installation ein Tagesprojekt?
Ich kann das nicht verstehen. Kannst Du es uns allen mal kurz erklären.
Gruß..