The most easiest way how to deploy Qt linux Application

I found solution also for the problem with executing application form in-app directory!!, Look to text bellow.
Warning: This solution has one big disadvantage ;-(. It’s necessary to execute application only from app-dir. In other cases system doesn’t find required libraries.
The solution could be run patchelf on the client computer with final installation path

Today I start working on deploying my http://www.orm-designer.com/ Qt application on linux platform.

I read a lot of articles about deploying applications but all of the suggested methods was impractical, too complex or unusable. Here is a list of them:

  • Using qt.conf in Qt resource or application dir. Usefull for Qt libraries, but not third party libraries
  • Installing Qt and third-party libraries in one of the system library path. This method need root permission for app users
  • Using startup script for setting correct LD_LIBRARY_PATH. Really? It’s too complicated for maintenance and users
  • Using -rpath to specify predetermined path. This method requires the users have this directory and have the full access to this directory

Another solution, the simplest one

I’m not sure why this solution isn’t mentioned in Qt forums or anywhere else. Maybe this solution isn’t so clean and perfect for Linux gurus, but it’s perfect for me.

The solution is in simply changing the search path in already compiled application to “.” (current directory) current application location by using $ORIGIN variable, so application will search all libraries in application directory first. It’s simple, it’s clean. All libraries distributed with application will be isolated in application directory and app-loader will not load any other library by mistake.

Updated: The keyword $ORIGIN do the trick, that you can run application from anywhere on your computer. $ORIGIN is absolute path to your executable.

And how to do this change? As first, you need to download small utility called PatchELF. With this application you can change -rpath in app to anything you need.

patchelf --set-rpath '$ORIGIN' ./ApplicationExecutable

And it is. Now you can copy all required libraries to directory with your application and everything will works correctly.

Installation

Download Ubuntu 32/64bit package from site http://hydra.nixos.org/release/patchelf/patchelf-0.6

Note

Maybe there is a way how to set rpath directly in the linking proces by using -rpath linker param. But I didn’t manage it to work.

If you want to display list of shared libraries used by your application, use this command:

ldd ./ApplicationExecutable

External links

Qt application crash when compiled for 64-bit VS2010

Callstack

>	QtGui4.dll!00000000652f071f()
 	[Frames below may be incorrect and/or missing, no symbols loaded for QtGui4.dll]
 	QtGui4.dll!00000000652f07ae()
 	QtGui4.dll!0000000065326821()
 	QtGui4.dll!0000000065327f30()
 	QtGui4.dll!00000000653284ba()
 	QtGui4.dll!000000006532a5f5()
 	QtGui4.dll!00000000652f4792()
 	QtGui4.dll!000000006532f701()
 	QtGui4.dll!000000006535be71()
 	QtCore4.dll!0000000059a0ab9f()
 	QtGui4.dll!0000000065306eb9()
 	QtCore4.dll!00000000599f7903()
 	QtGui4.dll!0000000064eaffa2()
 	QtGui4.dll!0000000064eb2e56()
 	QtCore4.dll!00000000599f7792()
 	QtGui4.dll!0000000064eec2a3()
 	QtGui4.dll!0000000064eee85e()
 	QtGui4.dll!0000000064eec265()
 	QtGui4.dll!0000000064eee85e()
 	QtGui4.dll!0000000064eec265()
 	QtGui4.dll!0000000064eee85e()
 	QtGui4.dll!0000000064efa870()
 	QtGui4.dll!0000000065208727()
 	QtGui4.dll!000000006527a082()
 	QtGui4.dll!0000000064eaffb6()
 	QtGui4.dll!0000000064eb2e56()
 	QtCore4.dll!00000000599f7792()
 	QtGui4.dll!0000000064ef264c()
 	QtGui4.dll!0000000064ef26c7()
 	QtGui4.dll!0000000064ef26c7()
 	QtGui4.dll!0000000064ef26c7()
 	QtGui4.dll!0000000064efe30c()
 	OrmDesigner2.exe!000000013f95a2cf()
 	OrmDesigner2.exe!000000013f95dce2()
 	kernel32.dll!000000007794652d()
 	ntdll.dll!0000000077c8c521()

The bug is probably caused by wrong alignment or incorrect VS2010 compiler optimalization.

Found resources:
https://bugreports.qt.nokia.com//browse/QTBUG-11445
https://connect.microsoft.com/VisualStudio/feedback/details/573262/incorrect-alignment-with-x64-optimizer-and-movaps
http://support.microsoft.com/kb/2280741
https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=31433

Workarounds:

First way – Update VS2010 mkspec for Qt

go to $QTDIR/mkspecs/win32-msvc2010/qmake.conf and replace -02 with -01 (ie. reducing the optimzation level).Also /Ob0 could be used.

Microsoft hotfix for VS

http://archive.msdn.microsoft.com/KB2280741
File patch name VS10-KB2268081-x86.exe

Install Visual Studio 2010 SP1

Service pack could also contains required fix.
http://www.microsoft.com/download/en/details.aspx?id=23691

Problem with Qt compilation under Windows 64-bit

This short post will show you how to resolve following error during Qt compilation on 64-bit windows:

Creating library ..\..\..\..\lib\QtWebKitd4.lib and object ..\..\..\..\lib\Qt
WebKitd4.exp
PluginViewWin.obj : error LNK2019: unresolved external symbol _HBeginPaint refer
enced in function "private: static struct HDC__ * __cdecl WebCore::PluginView::h
ookedBeginPaint(struct HWND__ *,struct tagPAINTSTRUCT *)" (?hookedBeginPaint@Plu
ginView@WebCore@@CAPEAUHDC__@@PEAUHWND__@@PEAUtagP AINTSTRUCT@@@Z)
PluginViewWin.obj : error LNK2019: unresolved external symbol _HEndPaint referen
ced in function "private: static int __cdecl WebCore::PluginView::hookedEndPaint
(struct HWND__ *,struct tagPAINTSTRUCT const *)" (?hookedEndPaint@PluginView@Web
Core@@CAHPEAUHWND__@@PEBUtagPAINTSTRUCT@@@Z)
..\..\..\..\lib\QtWebKitd4.dll : fatal error LNK1120: 2 unresolved externals
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 9.0\
VC\BIN\x86_amd64\link.EXE"' : return code '0x460'
Stop.
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio 9.0\
VC\BIN\nmake.exe"' : return code '0x2'

This error is caused by bug in QMAKE_HOST variable used in WebCore.pro file. This variable is tested to determine destination platform (x86 or x64).
This variable contains x86 value also on 64-bit builds instead of x86_64 value. This value is tested on the following line in a WebCore.pro file:

win32:!win32-g++*:contains(QMAKE_HOST.arch, x86_64):{

If you want to fix this error, simply replace QMAKE_HOST by QMAKE_TARGET variable. Updated line should look like this:

win32:!win32-g++*:contains(QMAKE_TARGET.arch, x86_64):{

After this update all required asm defines are correctly included and build of WebKit will be successful.

Update for this error

In newer versions of Qt there is already applied fix the error with QMAKE_HOST / QMAKE_TARGET, but also there is a new problem ;-(.

The Problem is in the following “if” definition:

   if(win32-msvc2005|win32-msvc2008):equals(TEMPLATE_PREFIX, "vc") {
        SOURCES += \
            plugins/win/PaintHooks.asm
    }

When you compile your project for MSVC 2010, .asm file isn’t included. It’s necessary to add win32-msvc2010 to this definition. So updated WebCore.pro for Qt 4.8 will look like this:

 if(win32-msvc2005|win32-msvc2008|win32-msvc2010):equals(TEMPLATE_PREFIX, "vc") {
        SOURCES += \
            plugins/win/PaintHooks.asm
    }

Next problem solution

Next problem which I found during compilation is wrongly set QMAKE_TARGET.arg. For unspecified reason, when I compile 64bit library in 64bit system in 64bit VS command line, this variable has value x86 instead of x86_64.
The problem is in the qmake project.cpp file. QMAKE trying to determine 64/32 bit version based on the %PATH% configuration. Qmake search for VS-PATH\bin\amd64 of \bin\x86_amd64 string. Unfortunately there is a bug in concating searched string. This is how looks original project.cpp file at line 3177:

QString vcBin64 = qgetenv("VCINSTALLDIR").append("\\bin\\amd64");
QString vcBinX86_64 = qgetenv("VCINSTALLDIR").append("\\bin\\x86_amd64");

The problem is, that VCINSTALLDIR contains \ at the end of the string, and then we append \ again. So, result is:

QString vcBin64 = qgetenv("VCINSTALLDIR");
if ( vcBin64.at( vcBin64.size()-1 ) != '\\' )
  vcBin64.append("\\");
vcBin64.append("bin\\amd64");

QString vcBinX86_64 = qgetenv("VCINSTALLDIR");
if ( vcBinX86_64.at( vcBinX86_64.size()-1 ) != '\\' )
  vcBinX86_64.append("\\");
vcBinX86_64.append("bin\\x86_amd64");

Now, QMake correctly determine 32/64 bit compilation and then correctly include PaintHooks.asm and your Qt WebCore will be sucesfully compiled.

How to deploy Qt application on MacOs

Missing dylib libraries

If your application using some externals dynamic libraries (called .dylib in MacOs system), you have to provide all these libraries. The simplest way is to provide these libraries into the Application.app directory.

Find out which libraries are used

Qt provide really useful tool called “otool” which serves to lots of purpose. One of them is to detect which shared libraries are required by our application. For this purpose otool has parameter -L. The usage is following:

otool -L ./Test1.app/Contents/MacOS/Test1

Output could looks like this:

./Test1:
        libboost_iostreams.dylib (compatibility version 0.0.0, current version 0.0.0)
        libboost_filesystem.dylib (compatibility version 0.0.0, current version 0.0.0)
        libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)
        libboost_thread.dylib (compatibility version 0.0.0, current version 0.0.0)
        libboost_date_time.dylib (compatibility version 0.0.0, current version 0.0.0)
        libboost_regex.dylib (compatibility version 0.0.0, current version 0.0.0)
        /Users/dev/dev/SharedLibraries/libiconv/lib/libiconv.2.dylib (compatibility version 8.0.0, current version 8.0.0)
        /Users/dev/dev/ExternalLibraries/../SharedLibraries/libxml/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.8.0)
        /Users/dev/dev/ExternalLibraries/../SharedLibraries/libxslt/lib/libxslt.1.dylib (compatibility version 3.0.0, current version 3.26.0)
        /Users/dev/dev/ExternalLibraries/../SharedLibraries/libxslt/lib/libexslt.0.dylib (compatibility version 9.0.0, current version 9.15.0)
        /Users/dev/dev/ExternalLibraries/yaml-cpp-0.2.5/build/libyaml-cpp.0.2.dylib (compatibility version 0.2.0, current version 0.2.5)
        QtGui.framework/Versions/4/QtGui (compatibility version 4.7.0, current version 4.7.0)
        QtCore.framework/Versions/4/QtCore (compatibility version 4.7.0, current version 4.7.0)
        /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
        /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 625.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)

Output from “otool” is simmilar to linux tool “ldd”.

The Mac Deployment Tool

Because manual copying and configuring all shared libraries to our application could be difficult, Qt have deployment tool which do all work for us. Tool is called “macdeployqt” and can be found in /Developer/Tools/Qt/macdeployqt.

 /Developer/Tools/Qt/macdeployqt ./GeneratedFilesMacOs/Debug/Test1.app

Note: Every time when you call macdeployqt tool, project have to be build from scratch. But is sufficient when whole result directory is removed and linked again:

rm -rf ./GeneratedFilesMacOs/Debug/Test1.app/
make

g++ template method problem

Quick post about problem which I already solved, but think that could be handy for someone else.

I have following code:

template<class T>
struct Test
{
	T val;
	template <class T2>
	void DoSomething( T2 &obj )
	{
		obj.FindByType<int>();
	}
};

When compiling under Visual studio, everything is ok. But when try the same code snippet under g++, have following error:

test.cpp: In member function ‘void Test<T>::DoSomething(T2&)’:
test.cpp:48: error: expected primary-expression before ‘int’
test.cpp:48: error: expected ‘;’ before ‘int’

This is because compiler doesn’t known FindByType method, because T2 is templated argument. The solution which I found is in adding keyword template before FindByType method name. So updated source code will look like this:

template<class T>
struct Test
{
	T val;
	template <class T2>
	void DoSomething( T2 &obj )
	{
		obj.template FindByType<int>();
	}
};

After this update, code will be compiled correctly under both compilers.

List of known issues and tips

This is list of all known issues and problems which we had to solve during our first Qt installation on Linux, Windows and Mac.

Known errors

Error: undefined interface

What to do when compilation of QT crash with message “Error: undefined interface”.
http://www.qtforum.org/article/31561/error-when-building-libraries.html
http://www.qtcentre.org/threads/26245-Qt-4.6-api/qscriptextensionplugin.h(43)-Error-Undefined-interface

make: g++: Command not found

it’s necessary to instal g++ support (sudo apt-get install g+)

Basic XLib functionality test failed!

it’s necessary to instal xlib(xorg??) support (sudo apt-get install xorg-dev)

*** [sub-corelib-make_default-ordered] Error 2

Probably mishmash on 32bit / 64bit  system and QT versions.

undefined reference to `QEventDispatcherGlib::versionSupported()’

Probably missing libglib2.0-dev on your system. (sudo apt-get install libglib2.0-dev).

Undefined reference to QSslSocket::*

Missing OpenSSL library on your system. (sudo apt-get install libssl-dev)

gtk/gtk.h: No such file or directory

Missing gtk package. (sudo apt-get install libgtk2.0-dev ). After that its necessary to update db (sudo updatedb).

if system can’t find file gtk/gtk.h because gtk is stored in gtk-2.0 directory, add -I (capitalised i) param to configure with gtk path:

./configure -opensource -I /usr/include/gtk-2.0

cups/cups.h: No such file or directory

install libcups2. (sudo apt-get install libcups2-dev)

gst/gst.h: No such file or directory

install gstreamer 0.10. (sudo apt-get install libgstreamer0.10-dev)

Missing Include/glibconfig.h

it’s because this file isn’t in /usr/include/glib-2.0, but in /usr/lib/glib-2.0. So you have to include also this /usr/lib path or copy file to include/glib-2.0

Hints and tips

How to create symbolic link to directory

create symbolic link using ln -nsf /usr/include/gtk-2.0/gtk /usr/include/gtk

Minimal required libraries

List of libraries required by Qt:

  • libfontconfig1-dev
  • libfreetype6-dev
  • libx11-dev
  • libxcursor-dev
  • libxext-dev
  • libxfixes-dev
  • libxft-dev
  • libxi-dev
  • libxrandr-dev
  • libxrender-dev

And other which are required by some modules of Qt:

To install all required on Linux, use following commands

sudo apt-get install libfontconfig1-dev libfreetype6-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxcups/cups.h: No such file or directory ft-dev libxi-dev libxrandr-dev libxrender-dev

sudo apt-get install bison flex libqt4-dev libqt4-opengl-dev libphonon-dev libicu-dev libsqlite3-dev libxext-dev libxrender-dev gperf libfontconfig1-dev libphonon-dev

If error doesn’t disappear after installing correct library

Sometimes it’s necessary to reconfigure Qt using make confclean

How to find where is missing header file located on disk

Use find /path -iname xxx.h command

How to find package which contains missing header file

use apt-file application with following syntax:

apt-file search gdk/gdk.h

Useful links about instalation Qt on linux

List of links about installation:
Building Qt on Linux

Qt configuration for succesfull build

This is currently my latest configure command to compile Qt on my Ubuntu 10.10.

Compilation fixes

This is necessary when search path for following libraries isn’t entered to configure.

sudo ln -nsf /usr/include/gstreamer-0.10/gst /usr/include/gst

Todo

Figure out how works pkg-config (pkg-config –cflags gstreamer-0.10)

Qt installation and configuration

This is our company step-by-step guide to install and configure Qt on our developer machines.

How to install Qt

Link to Qt download site: http://qt.nokia.com/downloads

Windows (VS2005)

Download VS 2008 distribution from download site. When 2008 distribution is downloaded, it’s necessary to reconfigure and rebuild it for VS 2005 using next steps.

Linux

Download linux/x11 distro from Qt page. Download 32/64bit distro package. Setup downloaded files as executables:

chmod +x qt-sdk-linux-x86-opensource-2009.01.bin
chmod +x qt-creator-linux-x86-opensource-1.0.0.bin

Install Qt sdk to default directory and begin with configuration.

MacOS

Download latest Qt SDK distribution and latest XCode developer pack from apple site. Then install both.

How to configure Qt

Qt configuration is done via Configure script/executable on all platforms.

Windows

Run “Start menu->Visual studio->Tools-> Visual studio command prompt”
Then go to “c:\Qt\Qt_Version\Qt” and run “configure” with additional params.

Our current configuration:

configure -debug-and-release -opensource -shared -platform win32-msvc2005 -incredibuild-xge -openssl

Clean configurations

run nmake confclean and nmake distclean to remove all previous version of QT compilations.

SSL support

For SSL Support add -openssl switch to configure.

Note!

: configure param HAVE TO be executed from Visual studio command prompt!

Linux

Enter Qt directory and enter following configure param:

./configure -opensource -I /usr/include/gtk-2.0 -L /usr/lib/gt-2.0 -I  /usr/include/gstreamer-0.10 -L /usr/lib/gstreamer-0.10 -I /usr/include/glib-2.0 -L /usr/lib/glib-2.0 -I /usr/include/libxml2 -fast

Clean configurations

run make confclean and then configure.

MacOS

How to compile Qt

Windows

Compile Qt using command prompt:

  • Run Visual studio command prompt.
  • And run nmake to build a whole library

Second option is open projects.sln located in p:/Qt/4.7.1/ using Visual Studio IDE  and compile it.

Linux

  • As first thing, use configure to setup Qt settings.
  • As next, run make to build a whole library
  • After a while when everything is compiled, use make install. This will install library to /usr/local/Trolltech/Qt-4.7.0

MacOS

Currently not tested, using default compilation.

How to compile application

When we have prepared Qt library, it’s time to compile our application.

MacOS

When using  qmake without additional params, qmake generate xcode project from .pro instad makefile for g++. To generate makefile, use following params:

qmake -spec macx-g++
make

Deploying application

Windows

Not testes.

External link: http://doc.trolltech.com/4.5/deployment-windows.html

Linux

Not testes.

MacOS

Not testes.