Qt-Programme für 32-Bit Systeme auf einem 64-Bit System kompilieren (Linux)

Oftmals soll ein Programm für noch weit verbreitete 32-Bit Systeme erstellt werden, wenn aber nur ein 64-Bit System zur Entwicklung zur Verfügung steht. Da 32-Bit Systeme keine 64-Bit Bibliotheken verwenden können, dürfen ausführbare Dateien nicht einfach von einem 64-Bit System auf ein 32-Bit System kopiert werden. Dieses Problem ist momentan nicht einfach zu lösen, es gibt jedoch einen Weg Qt-Programme entsprechend zu kompilieren.

:!: Diese Anleitung bezieht sich ausschließlich auf Linux-Systeme, genauer gesagt Ubuntu. Vorausgesetzt wird eine funktionierende 64-Bit Installation des Qt-SDKs.

Entwicklungssystem vorbereiten

Bibliotheken installieren

Zu allererst muss die 32-Bit Version von Qt installiert werden. Das kannst über den Paketmanager der Distribution oder über Konsolenbefehle geschehen. Diese Pakete haben eine “:i386“-Endung, also zum Beispiel „libqtgui4:i386“. Es sollten zumindest die Qt-Module „Core“ und „Gui“ installieren, der Rest je nach Bedarf. Außerdem wird noch das Paket „libc6-dev-i386“ benötigt.

Links zu den Bibliotheken erstellen

Nun sollte sich alles am Rechner befinden, das zum Erstellen einer 32-Bit ELF benötigt wird. Bei der Installation der 32-Bit Bibliotheken wird aber ein entscheidender Fehler gemacht. Es werden nämlich keine Links erstellt, um die Bibliotheken mit ihrem richtigen Namen zu verwenden. Das kann relativ leicht mit Links korrigiert werden:

$ cd /usr/lib32
$ sudo ln -s libstdc++.so.6 libstdc++.so
$ cd /usr/lib/i386-linux-gnu
$ sudo ln -s libQtCore.so.4 libQtCore.so
$ sudo ln -s libQtGui.so.4 libQtGui.so

Konfigurationsdateien kopieren

Bei der 32-Bit Installation fehlen außerdem noch ein paar Konfigurationsdateien. Es können entweder jene der 64-Bit Version verwendet werden oder entsprechende Kopien der Dateien im richtigen Verzeichnis.

$ cd /usr/lib/x86_64-linux-gnu
$ sudo cp *.prl ../i386-linux-gnu/

Projekt erstellen

Das Qt-Projekt kann ganz normal mit den üblichen Befehlen erstellt werden.

$ qmake -project
$ qmake

Makefile korrigieren

Am Makefile müssen noch einige Parameter und Pfade korrigiert werden. Die zu ändernden Teile sind ziemlich offensichtlich. Das “-m64“ muss weg und durch “-m32“ ersetzt werden. Außerdem sind die Verzeichnisse für den Linker “/usr/lib/i386-linux-gnu/“ und “/usr/lib32/“. Noch ein paar Kleinigkeiten, die im diff sicher leicht zu erkennen sind:

--- Makefile    2012-07-14 17:25:57.937851716 +0200
+++ Makefile2   2012-07-14 17:24:37.733855068 +0200
@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building: test
-# Generated by qmake (2.01a) (Qt 4.8.1) on: Sat Jul 14 17:25:57 2012
+# Generated by qmake (2.01a) (Qt 4.8.1) on: Tue Jul 10 17:42:04 2012
 # Project:  test.pro
 # Template: app
 # Command: /usr/bin/qmake -o Makefile test.pro
@@ -11,12 +11,12 @@
 CC            = gcc
 CXX           = g++
 DEFINES       = -DQT_WEBKIT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
-CFLAGS        = -m64 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
-CXXFLAGS      = -m64 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
-INCPATH       = -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I.
+CFLAGS        =  -m32 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+CXXFLAGS      =  -m32 -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES)
+INCPATH       = -I/usr/share/qt4/mkspecs/linux-g++-32 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I.
 LINK          = g++
-LFLAGS        = -m64 -Wl,-O1
-LIBS          = $(SUBLIBS)  -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtCore -lpthread 
+LFLAGS        = -m32 -Wl,-O1
+LIBS          = $(SUBLIBS)  -L/usr/lib/i386-linux-gnu/ -L/usr/lib32/ -lQtGui -lQtCore -lpthread
 AR            = ar cqs
 RANLIB        = 
 QMAKE         = /usr/bin/qmake
@@ -102,7 +102,7 @@
 $(TARGET):  $(OBJECTS)  
        $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
 
-Makefile: test.pro  /usr/share/qt4/mkspecs/linux-g++-64/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \
+Makefile: test.pro  /usr/share/qt4/mkspecs/linux-g++-32/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \
                /usr/share/qt4/mkspecs/common/linux.conf \
                /usr/share/qt4/mkspecs/common/gcc-base.conf \
                /usr/share/qt4/mkspecs/common/gcc-base-unix.conf \
@@ -127,8 +127,8 @@
                /usr/share/qt4/mkspecs/features/yacc.prf \
                /usr/share/qt4/mkspecs/features/lex.prf \
                /usr/share/qt4/mkspecs/features/include_source_dir.prf \
-               /usr/lib/x86_64-linux-gnu/libQtGui.prl \
-               /usr/lib/x86_64-linux-gnu/libQtCore.prl
+               /usr/lib/i386-linux-gnu/libQtGui.prl \
+               /usr/lib/i386-linux-gnu/libQtCore.prl
        $(QMAKE) -o Makefile test.pro
 /usr/share/qt4/mkspecs/common/unix.conf:
 /usr/share/qt4/mkspecs/common/linux.conf:
@@ -155,8 +155,8 @@
 /usr/share/qt4/mkspecs/features/yacc.prf:
 /usr/share/qt4/mkspecs/features/lex.prf:
 /usr/share/qt4/mkspecs/features/include_source_dir.prf:
-/usr/lib/x86_64-linux-gnu/libQtGui.prl:
-/usr/lib/x86_64-linux-gnu/libQtCore.prl:
+/usr/lib/i386-linux-gnu/libQtGui.prl:
+/usr/lib/i386-linux-gnu/libQtCore.prl:
 qmake:  FORCE
        @$(QMAKE) -o Makefile test.pro

Programm kompilieren

Schlussendlich kann das Programm ganz normal kompiliert werden.

$ make
g++ -c -pipe -m32 -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED 
-I/usr/share/qt4/mkspecs/linux-g++-32 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 
-I. -I. -o main.o main.cpp
g++ -m32 -Wl,-O1  -o test main.o    -L/usr/lib/i386-linux-gnu/ -L/usr/lib32/ -lQtGui -lQtCore -lpthread

Dadurch wird folgende Datei erstellt:

$ file test
test: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for 
GNU/Linux 2.6.24, BuildID[sha1]=0x82e53f9a66cafeaca2494ff0a6fa3c62885ca2c5, not stripped

Das ganze natürlich auf einem 64-Bit System:

$ uname -a
Linux xps 3.2.0-26-generic #41-Ubuntu SMP Thu Jun 14 17:49:24 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

Programm ausführen

Nun kann die ausführbare Datei einfach auf ein 32-Bit System kopiert werden. Dieses System muss aber die entsprechenden Laufzeit-Bibliotheken (in diesem Fall natürlich 32-Bit) installiert haben.