Code::Blocks und wxWidgets

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:

  1. mingw32-make … clean
  2. mingw32-make … setup_h
  3. 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

Comment on this post

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.