Die wxWidgets-Bibliothek bauen

Diese Seite soll einen kleinen Überblick über den Bauprozeß für wxWidgets geben und euch eine Hilfestellung dazu bieten. Selbstverständlich stehen hier keine absoluten Wahrheiten und es wird immer andere (und vielleicht auch bessere) Wege geben das Ziel zu erreichen, ich werde hier den Weg beschreiben den ich gegangen bin.

:!: Achtung Linux-Benutzer! Bevor ihr die Bibliothek von der Webseite herunterladet und selbst zu kompilieren beginnt, überprüft die Paketqellen eurer Distribution nach wxWidgets. Die meisten Linux-Distributionen stellen euch wxWidgets bereits kompiliert und verpackt bereit! Die Pakete heißen:

  • libwxgtk2.8-dev unter Debian, Ubuntu
  • wxGTK-devel unter Fedora und Suse
  • wxgtk2.8 unter Mac OS X (mit Fink)
  • wxgtk unter Arch Linux

:!: Achtung Windows-Benutzer! Das Projekt wxPack stellt bereits kompilierte Distributionen von wxWidgets zur Verfügung: http://wxpack.sourceforge.net/Main/Downloads

wxWidgets 2.8 vs wxWidgets 3.0

FIXME

wxWidgets herunterladen und entpacken

Geht auf die Downloadseite von wxWidgets: http://www.wxwidgets.org/downloads/ und ladet euch euer gewünschtes Release herunter. Um Bandbreite und Festplattenplatz zu sparen empfehle ich, den passenden Port herunterzuladen. Das heißt:

  • wxMSW für Windows. Hier würde ich empfehlen den Installer zu verwenden
  • wxMac für MacOS
  • wxGTK für andere Unixartige Systeme
  • wxX11 für … keine Ahnung eigentlich :-)

Entpackt nun die heruntergeladenen Bibliotheken an einen Ort (beim wxMSW Port müsst ihr den Installer aufrufen). Es werden ungefähr FIXME MB Festplattenspeicher benötigt.

Ein Überblick über die wxWidgets-konfiguration

Komponenten

wxWidgets besteht aus mehreren Komponenten, die eine große Bandbreite von Funktionen abdecken. Darunter fällt Thread-, Netzwerk- und OpenGL-Programmierung, verarbeitung von XML Dateien, darstellung von HTML und RichText-Verarbeitung. Eine vollständige Liste der Komponenten und ihrer Funktionen findet ihr hier:

Bevor ihr mit dem kompilieren loslegt, ist euch sehr empfohlen euch darüber Gedanken zu machen, welche Funktionen und Komponenten ihr tatsächlich braucht! Das spart viel Zeit beim kompilieren und viel Speicherplatz.

Konfiguration

Nun eine kleine Einführung zu den Begriffen, die bei der Konfiguration verwendet werden:

Unicode

Unicode ist ein Standard für eine Einheitliche, Plattformübergreifende Kodierung von Zeichen.

Für wxWidgets 2.8 gab es die Möglichkeit die Möglichkeit die Bibliothek entweder im „ANSI“-Modus, oder im Unicode-Modus zu bauen:

  • ANSI: Alle Zeichenketten sind sogenannte „narrow“-Strings, die einzelnen Zeichen also vom Datentyp char.
  • Unicode: Alle Zeichenketten sind „wide“-Strings, die einzelnen Zeichen also vom Datentyp wchar_t.

Dementsprechend erwarten auch alle Funktionen und Methoden von wxWidgets die mit Strings arbeiten entweder char-Strings oder wchar_t Strings.

:!: Achtung! Ab wxWidgets 2.9 wird nur mehr die Unicode-Variante unterstützt und empfohlen!

Sofern euer System (wie jedes halbwegs Moderne System) und euer Compiler Unicode unterstützt, empfehle ich die Unicode-Variante zu bauen.

Debug/Release

Die übliche Option:

  • Debug: Mit Debugging-Symbolen, damit ihr euer Programm besser Debuggen könnt
  • Release: Ohne Debugging-Symbolen, für eine kleinere Programmgröße

Dies ist Geschmackssache. Für das tägliche Programmieren würde ich Debug-empfehlen, das könnte euch beim Debuggen helfen. Release braucht ihr eigentlich nur für - wie der Name schon sagt - eine Veröffentlichung eures Programms 1).

Monolithic/Multilib

Wie bereits erwähnt besteht wxWidgets aus vielen komponenten. Diese könnt ihr entweder alle in eine Library zusammenlinken (das bedeutet Monolithic), oder als einzelne Libraries behalten (Multilib). Ich persönlich bevorzuge die Multilib-konfiguration, da ich nur dort genau bestimmen kann, welche Komponenten zu meiner Anwendung gelinkt werden. Außerdem hat die „Monolithic“-Bibliothek eine durchaus beachtliche Größe von ungefähr 50 MB (in der Release-konfiguration!! Mit Debug-Symbolen noch mehr!), und diese Datei ist mir persönlich als .lib/.a, aber vor allem als .dll/.so/.dynlib nicht mehr geheuer!

Static/Shared

Ebenfalls eine übliche Option:

  • Static: Als statisches Archiv bauen (.a/.lib)
  • Shared: Als dynamische Bibliothek bauen (.so/.dll/.dylib)

Baut ihr die Bibliothek als statisches Archiv, werden beim Linken eures Programmes alle Symbole (also Funktionen, statische Variablen, Konstanten) aus wxWidgets fest in die ausführbare Datei mit einkompiliert. Ein Nachteil ist, dass die Bibliothek jetzt „fest“ eingebettet ist, also nicht mehr ausgetauscht werden kann. Ein anderer ist, dass wenn ihr mehrere ausführbare Dateien habt, die Funktionen in jeder Executable vorhanden sind, und das führt zu vergrößertem Speicherplatzverbrauch.

Baut ihr die Bibliothek als dynamische Bibliothek, vermeidet ihr dass der Code mehrfach vorkommt und spart Speicherplatz 2). Außerdem könntet ihr theoretisch die bibliothek austauschen und durch eine neuere Version erstetzen. Dies könnte eventuell bei „Sicherheitsaktualisierungen“ von Vorteil sein, die Notwendig wird wenn in wxWidgets eine Sicherheitskritische Lücke auftaucht.

Was sollt ihr nun tatsächlich verwenden? Anfängern (und mäßig Fortgeschrittenen ;-) ) würde ich das Statische linken empfehlen. Das spart einige Probleme, vor allem beim Linken und Auffinden der dynamischen Bibliotheken. Ein kleiner Test: Wisst ihr, was der dynamische Linker ist? Wisst ihr, auf welchen Pfaden er nach Bibliotheken sucht? Wisst ihr was eine SOVERSION ist und was ABI-Kompatibilität bedeutet? Wenn nicht, solltet ihr eher auf die statischen Bibliotheken zürückgreifen.

Runtime-Bibliotheken

Die sogenannten „Runtime“-Bibliotheken sind diejenigen Bibliotheken, die die Funktionen der Standardbibliothek von C und von C++ enthalten. Das sind Beispielsweise C Funktionen wie „fopen()“ oder die Implementierungen der IOStreams-Klasse. Für Visual Studio auf Windows heißen diese zum Beispiel „msvcrt*.dll“ oder für GCC unter Linux „libc.so“.

Hier habt ihr die Wahl zwischen shared und static:

  • shared: Die Standardbibliothek wird dynamisch hinzugelinkt (also als .dll/.so/.dylib)
  • static: Die Standardbibliothek wird statisch hinzugelinkt (als .a/.lib)

Bitte belasst diese Einstellung bei der Standardeinstellung! Diese ist „shared“. Ihr solltet es nur umstellen wenn ihr genau wisst was ihr tut, ansonsten kann es zu sehr seltsamen und schwer zu behebenden Fehlern beim Linken eures Programms kommen.

wxWidgets Bauen

Dazu benötigt ihr einen der Unterstützten Compiler. Eine vollständige Liste findet ihr hier: http://wiki.wxwidgets.org/Supported_Platforms , allerdings würde ich euch empfehlen es schlicht und einfach mit eurem bereits installierten Compiler zu versuchen.

wxWidgets benutzt „Bakefile“, das ist ein Programm zur Erstellung von plattformübergreifenden Bau-files, die von einer Reihe von Bauwerkzeugen benutzt werden können. Darunter fallen Automake/Autoconf, Makefiles für verschiedenste Werkzeuge, und sogar Visual Studio Projektdateien. Ihr könnt eine der Möglichkeiten auswählen, ich werde in diesem Artikel nur das Kompilieren mit Makefiles erläutern.

Bauen auf Windows

Achtung Visual Studio 2005 Express Benutzer! Der ausgelieferte Compiler ist noch nicht in der Lage wxWidgets zu kompilieren. Bitte lest euch den Artikel “Visual Studio 2005 Express upgraden“ um einen funktionierenden Compiler zu erhalten.

Im Folgenden werde ich das Verzeichnis, in das ihr wxWidgets entpackt habt als %wxWidgets_ROOT% bezeichnen.

Konfigurieren

Zunächst geht es daran, euren Build zu konfigurieren. Das könnt ihr, indem ihr die Konfigurationsdatei die zu eurem Compiler passt findet. Sie befindet sich im Verzeichnis “%wxWidgets_ROOT%/build/msw/“ und heißt „config.*“. Die tatsächliche Endung hängt vom Compiler ab:

  • MinGW: .gcc
  • Visual Studio: .vc
  • Borland: .bcc
  • Open Watcom: .wat

… und so weiter. In diesen Dateien findet ihr einige Variable, die ihr nach euren Wünschen setzen könnt. Die wichtigsten sind oben aufgelistet, die nicht erwähnten solltet ihr nur ändern wenn ihr wisst was ihr tut.

Bauvorgang starten

Öffnet zunächst eine Eingabeaufforderung so, dass euer Compiler und die Build-Tools auf dem Pfad sind. Das impliziert entweder dass euer Compiler bereits auf dem Pfad ist (für MinGW siehe hier) oder dass ihr eine Spezielle Eingabeaufforderung öffnet (wie z.B. bei der Visual Studio-Reihe der „Visual Studio 20XX Command Prompt“, der im Startmenü zu finden ist).

Wechselt nun mit „cd“ in das selbe Verzeichnis in dem sich auch die config.* und makefile.* Dateien befinden. Dies ist das Verzeichnis “%wxWidgets_ROOT%/build/msw/“.

Ihr könnten den Bauvorgang nun starten, indem ihr das Build-Tool eures Compilers mit der richtigen Makefile-Datei aufruft.
Hier ein Beispiel für Visual Studio:

  nmake -f makefile.vc

und hier ein Beispiel für MinGW:

  mingw32-make -f makefile.gcc

Wollt ihr mehrere Konfigurationen bauen, und wollt ihr nicht jedes mal das config.*-File bearbeiten, könnt ihr die dort gesetzten Werte auch auf der Kommandozeile überschreiben, z.B. so:

  mingw32-make -f makefile.gcc BUILD=release SHARED=0

Ein kleiner Tip von mir: besitzt ihr einem Mehrkernprozessor und habt gerade nichts am Rechner zu arbeiten, gebt dem Build-Tool an, dass es die zusätzlichen Kerne benutzt! Das wäre bespielsweise die “-j N“-Option (statt N die maximale Anzahl der gleichzeitig laufenden Prozesse) bei mingw32-make. Damit verkürzt sich die Bauzeit enorm. Beispiel:

  mingw32-make -j3 -f makefile.gcc

Ort der gebauten Dateien

Die resultierenden Bibliotheksdateien findet ihr nun im “%wxWidgets_ROOT%/lib“-Verzeichnis, in einem Unterordner dessen Name von eurer Konfiguration und des verwendeten Compilers abhängig ist. Das Format ist dabei <compilerkürzel>_(„lib“|“dll“).
Habt ihr Beispielsweise mit Visual Studio gebaut (kürzel „vc“) und habt ihr statische Bibliotheken gebaut, findet ihr die Dateien hier: “%wxWidgets_ROOT%/lib/vc_lib“.
Habt ihr allerdings dynamische Bibliotheken mit MinGW gebaut, findet ihr die Dateien hier: “%wxWidgets_ROOT%/lib/gcc_dll“.

Die Benennung der Dateien ist abhängig von der Konfiguration:

Konfiguriert ihr den Build im Debug-modus wird Bibliotheksdateien und dem Konfigurationsverzeichnis der Buchstabe „d“ angehängt.
Baut ihr wxWidgets im Unicode-Modus, wird Bibliotheksdateien und dem Konfigurationsverzeichnis der Buchstabe „u“ angehängt.

Der Dateiname jeder Bibliothek folgt einem Schema. Er besteht aus:

  • Dem Bibliotheksprefix „lib“, wenn ihr mit MinGW statische Bibliotheken baut
  • dem String „wxbase“ (für Grafikunabhängige Komponenten) oder „wxmsw“ für Grafikabhängige Komponenten
  • der Versionsnummer von wxWidgets ohne Punkt (z.B. „28“)
  • den Konfigurationskürzeln (z.B. „ud“)
  • einem Unterstrich und der Komponente (z.B. „net“)

Baut ihr eine Dynamische Bibliothek wird noch folgendes angehängt:

  • ein Unterstrich und das Compilerkürzel, z.B. „vc“
  • ein Unterstrich und der Geschmacksrichtung („Flavour“), die ihr bei der Konfiguration selbst angeben könnt. Standardmäßig ist das „custom“

Und schließlich der Dateiendung (z.B. “.lib“)

Einige Beispiele:

  • wxbase28ud_xml_vc_custom.dll
  • libwxbase28u_net.a

Um euer Programm zu kompilieren benögigt ihr noch die „setup.h“, die die tatsächliche Konfiguration enthält, mit der die Bibliotheken gebaut worden sind. Das Konfigurationsverzeichnis, also jenes, das die „setup.h“-Datei enthält besteht liegt im „lib/<compiler>_(„lib“|“dll“)>/“-Verzeichnis, und besteht aus dem Portnamen (also „msw“ auf Windows mit der WinAPI) und den Konfigurationskürzel.

Einige Beispiel:

  • Kompiliert mit Visual Studio als statische Bibliothek im Debug und im Unicode-Modus: lib/vc_lib/wx/mswud/
  • Kompiliert mit MinGW als dynamische Bibliothek im Release und im Unicode-Modus: lib/gcc_dll/wx/mswu
  • Kompiliert mit Digital Mars als statische Bibliothek im Release und im ANSI-Modus: lib/dmc_lib/wx/msw

Fügt den Pfad dem Include-Pfad eures Compilers hinzu, wenn ihr euer Programm baut. Achtung! Wenn das falsche Include-Verzeichnis beim bauen angibt, wird es höchstwahrscheinlich zu Linker-Fehlern kommen!

Eine Helloworld-Anwendung bauen

Leider ist das bauen von wxWidgets-projekten nicht so einfach auf der Kommandozeile möglich. Das liegt einerseits daran, dass relativ viele Systembibliotheken mitgelinkt und relativ viele zusätzliche Include- und Bibliothekspfade gesetzt werden müssen, vor allem an der großen Anzahl an Präprozessormakros, die beim Bauen gesetzt werden müssen. Es empfiehlt sich, auf IDE's und zusätzliche Bauwerkzeuge wie z.B. CMake zurückzugreifen.

Ich bitte euch nun euch auf dem wxWiki darüber schlau zu machen, wie ein Programm zu bauen ist, da das stark von eurem verwendeten Toolkit abhängig ist.

Hier werde ich nun kurz das Bauen einer kleinen Testanwendung, die ich von hier kopiert habe zu demonstrieren.

Auf Unixartigen Systemen steht ein Tool zur Verfügung, dass die korrekte Konfiguration des Bauvorganges für euch übernimmt, es heißt „wx-config“. Glücklicherweise wurde dieses Tool (inoffiziell) auf Windows portiert. Ihr könnt es hier herunterladen:

http://sites.google.com/site/wxconfig/

Zum Bauen tut bitte folgendes: Ladet euch von der oben genannten Seite das Tool wx-config herunter, und speichert es dort wo ihr es wiederfindet.

Fügt nun eine Umgebungsvariable mit dem Namen „WXWIN“ und dem Installationsverzeichnis von wxWidgets (also “%wxWidgets_ROOT%“) hinzu. Einige Hinweise zum erstellen von Umgebungsvariablen findet ihr auf [windows:faq:envvars|dieser Seite]].

Ruft es nun mit den korrekten optionen auf, und leitet die Standardausgabe in eine Datei um:

  wx-config.exe --wxcfg=gcc_lib\mswu --cflags --libs > 
  

Ersetzt dabei „gcc_lib\mswu“ durch den relativen Pfad zu euren Konfigurationsverzeichnis (siehe oben.

Bauen auf Linux

FIXME

Bauen auf MacOS X

FIXME

1) Es gibt Leute die Meinen, dass man Programme auch wenn man sie veröffentlicht, immer mit Debug-Symbolen kompilieren sollte. Das hilft euch beim Suchen nach Fehlern, vor allem wenn sie nicht auf eurem Rechner entstanden sind
2) Das stimmt so nicht ganz: ihr spart Speicherplatz, wenn ihr mehrere Ausführbare Dateien habt. Habt ihr nur eine, kann der Linker bei einer statischen Bibliothek alle unbenutzten Symbole herausschmeißen. Das kann er bei einer dynamischen Bibliothek nicht!