Cross-compiling, using Qt

On a previous post I described a simple example, of how-to cross compile an Windows application in a Linux environment.
Although this worked fine and raised my motivation, it is not a very useful example since the real world is much more complex. One of the complexities that I want to introduce is the use of Qt libraries, that are used thoroughly in my projects. I will now go in detail, through a slightly more complicated “Hello World”, where I make use of these libraries.

A key thing to understand, when cross compiling with Qt, is that you need to setup the development environment, both in the host and in the target OS (those are in this case: Ubuntu and Windows).

I started by downloading the Qt distribution, compiled for MinGW (of course, you may also decide to download the source codes and compile it yourself, which will add another complexity layer to this task…):

wget http://download.qt-project.org/official_releases/qt/4.8/4.8.5/qt-win-opensource-4.8.5-mingw.exe

Then I ran this with Wine, and followed the installation instructions:

wine qt-win-opensource-4.8.5-mingw.exe

Qt got installed under my “wine drive”, in the $HOME directory:

~/.wine/drive_c/Qt/4.8.5

As I mentioned before, you also need a working Qt environment for Linux. I had Qt 4.8.7 installed in my machine, and I stupidly thought I could use that; it turns out I can not. The Qt versions in Windows and Linux need to match! Since MinGW did not released a 4.8.7 version yet, I decided to download the Linux version of Qt 4.8.5, and installed it along with my current version (let us see what problems this may bring me in the future, if I keep developing in 4.8.7!).
If you did not understand my grump in the last paragraph, the only thing you need to know is that I downloaded Qt 4.8.5 for Linux, and installed it in:

/usr/local/Trolltech/Qt-4.8.5

The next step is to configure the mkspecs for cross-compiling; for that you need to navigate to /usr/local/Trolltech/Qt-4.8.5/mkspecs and create a new directory there. I called it “win32-x-g++”.

/usr/local/Trolltech/Qt-4.8.5/mkspecs/win32-x-g++

Inside this directory, you need to place a version of qmake.conf, with all the necessary information for cross compiling; mainly you need to pay attention to the paths of the Qt installed in Wine, and the minGW paths in Linux. Here is a working version for me; please amend it to reflect your paths.

Then I wrote a very simple Qt “Hello World”:

// Hello World in C++ for the Qt framework
#include 
#include 
int main(int argc, char *argv[])
{ 
	QApplication a(argc, argv); 
	QLabel l("Hello World!", 0); 
	l.setText("Test"); 
	l.setAlignment(Qt::AlignCenter); 
	l.resize(300, 200); 
	l.show();
 return(a.exec());
}

This is just a Window with “Hello World” written, but it is calling the Qt Libraries.
My Qt project file, looks like this (I generated it with qmake, and then added the relevant libraries to the Qt variable):

######################################################################
# Automatically generated by qmake (2.01a) Fri Dec 20 13:18:06 2013
######################################################################

TEMPLATE = app
TARGET = hello
QT += core gui
CONFIG += qt
DEPENDPATH += .
INCLUDEPATH += .

# Input
SOURCES += hello.cpp

I make a small parenthesis here, to note that the qmake version should be the one on:

/usr/local/Trolltech/Qt-4.8.5

If you do have more than one Qt version (like I do!), it is worth to set the $QTDIR variable to this directory, while cross compiling. You can check if this working as expected, by checking the path of qmake:

which qmake

If this points to /usr/local/Trolltech/Qt-4.8.5, then everything is ok; otherwise, please take a moment to export your $QTDIR.

To generate the makefiles, using the created mkspecs file above, you can use the following syntax:

qmake -spec win32-x-g++

Then you can compile the application, using make. If the compilation was successful, you should be able to run the executable “hello.exe”, using wine. When I attempted to do this, I had some errors that related to not finding some libraries. As in my previous example, I copied “mingwm10.dll” to the current directory, but I still had errors related to Wine not finding the Qt libraries.

I edited the QTDIR and PATH variables on Wine(Windows), by calling regedit.

regedit

Unfortunately that still did not do it for me. I thought a quick fix, for forcing the application to pick the libraries would be to copy the required DLL’s to the app path. Unfortunately that also did not worked 😦

err:module:import_dll Library libgcc_s_dw2-1.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\QtCore4.dll") not found
err:module:import_dll Library QtCore4.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\hello.exe") not found
err:module:import_dll Library libgcc_s_dw2-1.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\QtCore4.dll") not found
err:module:import_dll Library QtCore4.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\QtGui4.dll") not found
err:module:import_dll Library libgcc_s_dw2-1.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\QtGui4.dll") not found
err:module:import_dll Library QtGui4.dll (which is needed by L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\hello.exe") not found
err:module:LdrInitializeThunk Main exe initialization for L"Z:\\home\\joana\\projects\\cross-compiling\\hello\\release\\hello.exe" failed, status c0000135

Then I thought, that even if I cannot run the executable with Wine, it does not necessarily mean that I did not generate it correctly (which is ultimately my purpose, with all of this!). So I went to a Windows guest in VirtualBox, and I managed to successfully run the application! 🙂

hello1

This was a nice outcome, however it is still necessary to do this for the entire project, tracking all required Qt dll’s, Boost, and any other needed libraries. It would probably be a good idea to consider static linking, since I would not have to ship the DLL’s, and would also avoid digging into the problem of “why Wine is not finding the shared libraries”. However, from my experience, static linking of the Qt framework is quite an onerous task, and in this case I would have to do it twice (for Linux and for Windows).

Advertisement