Deploying Qt 5 Applications on Ubuntu 12.04


The fun is over, you’ve written your Qt 5.x application, compiled it for Ubuntu and it is time to deploy your software to a vanilla box (a PC without any Qt libraries on it), how do you go about it?

I spent quite some time struggling with this problem so now that I have finally got it working (for XML Mill at least), I decided to share my experience.

With regards to my setup, although I build Qt from source myself, I don’t believe what follows will differ much if you installed Qt from a binary package.  Of further importance is that I do not build Qt statically due to the LGPL licensing restrictions (which is why I have to go through the library distribution process in the first place) and, finally, my current Ubuntu platform is 12.04.3.

Since most of what you will need to know is already discussed at length in the two reference articles at the bottom of this post I won’t go into the details of how to determine which dependencies your application has, etc, but will rather tell you how I did it.  After copying all relevant dependencies and platform plugins to their respective folders, I ended up with a directory structure that looked like this:

dirstructureI will get to the “fonts” directory in a bit since that is not addressed in the referenced articles, but the “platforms” directory is discussed and the “sqldrivers” directory is included due to the fact that this application makes use of the Qt SQLite plugin.  I also prefer not having all my dependencies in the same directory as the application as I personally find this neater, hence the inclusion of the “libs” directory.

With the run script set up (once again see the first link below for the necessary concepts), I fired it up and ran into the following error:

This application failed to start because it could not find or load the Qt platform plugin “xcb”.Available platform plugins are: xcb.Reinstalling the application may fix this problem.
Aborted (core dumped)

This surprised me as I was sure I had set up the directory structure correctly and the “libqxcb.so” platform library was definitely there.  After some investigation, I realised that the dependencies for this library was missing, resulting in the same error as if the library itself wasn’t there at all.  In order to fix this, a user will obviously need root access, but running this script from within the platforms directory (where “libqxcb.so” lives) will resolve all the outstanding dependencies for you (the script will also create another script to uninstall all dependencies installed in this manner in case you wish to undo what you have done).

After I resolved the libqxcb dependencies, I once again tried to run my application on the vanilla box and ran into yet another error:

QFontDatabase: Cannot find font directory /home/william/qtsource/qt5/qtbase/lib/fonts – is Qt installed correctly?
Aborted (core dumped)

This did not make any sense to me at all since the directory path referenced only existed on my development box…how did this happen and, more importantly, how do I fix it?

It turns out that the reason is that Qt contains hard-coded paths that are set at build time and it was one of these (non-existent on the vanilla box) paths that was being queried by the application and (obviously) found missing, resulting in the error above.

Since the font engine uses QLibraryInfo to find the paths it is apparently possible to prevent this issue by setting the paths from within your application itself (I did not try this as I wasn’t too keen on hard-coding paths within my application myself).  Alternatively, one could also use a qt.conf file to override these paths, but there is also a third option which is to set and export a QT_QPA_FONTDIR environment variable in the run script.  This was the route I decided to take.

I created the “fonts” directory at the same level of my executable (see the directory structure image above) and copied all the fonts from the directory referenced in the error message across.  A quick edit to my run script resulted in the following (I kept it very simple as you can see):

#!/bin/sh
export LD_LIBRARY_PATH=`pwd`/libs
export QT_QPA_FONTDIR=`pwd`/fonts
./XMLMill

And that was it…finally it worked!

In Closing

I have written a bash script to do all of the above for me (specifically for XML Mill).  This script:

  1. Creates the “libs”, “platforms”, “sqldrivers” and “fonts” directories.
  2. Determines which libraries the application depends on and copies these dependencies to the “libs” directory (it may not be necessary to ship all of the dependencies found, but it will be up to you to determine which ones can be excluded after the fact).
  3. Copies the “libqxcb.so” library to “platforms” (the path to this library is set in the script itself).
  4. Creates the “fixdep.sh” script (the script mentioned above to resolve “libqxcb.so” dependencies) and copies it to the “platforms” directory.
  5. Copies the “libsqlite.so” library to “sqldrivers” (this is a specific plugin dependency for XML Mill).
  6. Copies all fonts (the path is specified in the script itself) to the “fonts” directory.
  7. Creates the run script in the form “run<appname>.sh”
  8. Creates a tar ball of all of the above.

The script lives here but please note that you will have to edit the script to suit your needs.

If you need any assistance with this script, feel free to contact me.

Reference:

  1. Deploying an Application on X11 Platforms

  2. Deploying Qt Applications on Linux and Windows

Advertisements

19 Replies to “Deploying Qt 5 Applications on Ubuntu 12.04”

  1. Thanks for the fantastic article, which solved most of problems, but am still stuck at the error “This application failed to start because it could not find or load the Qt platform plugin “xcb”.
    Reinstalling the application may fix this problem.
    Aborted (core dumped)”.

    Steps I followed:
    1) Run the main script, with path changes as appropriate. Which generated a tar file containing libs and platform directories. Libs contained all the library dependencies and platform has only libqxcb.so (as my app requires only this plugin). If I run the application, it runs like a champ. But hold on, read further points..
    2) Now I do not want to use the tar ball itself to ship the application, reason being, I want to use Qt installer framework. So what I did is just took the libs and platforms directory (and its contents) and try to package using Qt installer framework. But when I run like this, I get the error “could not load xcb”.
    3) I made sure that my LD_LIBRARY_PATH (inside my run script) is pointing to the libs directory.
    4) When I run ldd on my application, I do not see “not found” mappings.
    5) When I run ldd on libqxcb.so (in the platforms directory), I do not see “not found” mappings. This means that all dependencies of libqxcb.so are all met.

    They why do I still get the annoying error “could not find or load xcb”?
    My application is deployed using the below hierarchy

    /opt/mycompanyname/myapp/runscript (this invokes appbinary)
    /opt/mycompanyname/myapp/bin/appbinary
    /opt/mycompanyname/myapp/lib
    /opt/mycompanyname/myapp/platforms
    /usr/bin/myapp (a symbolic link to /opt/mycompanyname/myapp/runscript)
    Regarding the logos and images my application uses, I point the Qt Installer Framework to install in standard location as defined by freedesktop,org standards.

    The only difference in the tar ball approach and Qt Installer framework is that, in Qt IF, there are prdefined apis to install fonts/logos/images etc and it is a UI driven tool. I still need to deploy my libs, which I actually use from the tar ball. I even ran the fixdep.sh on my machine, but it does nothing. (Probably because there are no “not found” mappings).

    Please let me know if you need more information from my side. Your inputs would be of great value to solve this.

    1. Hi Sandeep,

      I have never used Qt IF, but from the directory structure you provided, my best guess is that the problem is due to your app binary residing in your /bin directory relative to the /myapp and /platforms directories.

      The executable and the /platforms directory must have the same root directory, i.e., I suggest you try the following structure(s):

      /opt/mycompanyname/myapp/bin/appbinary
      /opt/mycompanyname/myapp/bin/platforms

      or

      /opt/mycompanyname/myapp/appbinary
      /opt/mycompanyname/myapp/platforms

      I hope this helps!

      (PS. Please let me know if this solved your problem, I’d be very interested to know 🙂 )

      1. This issue is killing me, turning my hair grey to bald 😦

        No luck till now. I took some time to do multiple things one by one, but in vain.
        Used various hierarchical permutations and combinations:
        1) /opt/mycompanyname/myapp/bin/appbinary, /opt/mycompanyname/myapp/bin/platforms, /opt/mycompanyname/myapp/bin/lib
        2) /opt/mycompanyname/myapp/bin/appbinary, /opt/mycompanyname/myapp/bin/plugins/platforms, /opt/mycompanyname/myapp/bin/lib
        3) /opt/mycompanyname/myapp/bin/appbinary, /opt/mycompanyname/myapp/bin/plugins/platforms, /opt/mycompanyname/myapp/bin(libraries under bin directly, instead of a separate lib directory)
        And many more combinations to see no results..

        I even tried having a qt.conf file under bin, and tried pointing the plugins and libraries with hard coded paths. Still no progress. I doubt if my qt.conf file is even picked up (parsed) when I run the application. Btw, I placed the qt.conf file on the target machine (assuming it will pick it dynamically), not during the binary generation (compile time) on the development machine. Hope I am doing right..

        I tried printing the output of libraryPaths() (on my development machine) and it prints “/home/sandeep/Downloads/qtinstallations/Qt5.2.1/5.2.1/gcc_64/plugins/”.
        Does this give any idea about what hierarchical structure I need to maintain on my target machine?
        Or let me ask this way, Is there a way to do something on my development machine (call some similar functions like libraryPaths or print some QT environment variables) which will tell me what hierarchy I need to maintain on the target machine? Sad part is, when I tried searching the web, over 100s of people have already faced this problem and each one solved with a different approach and none works for me.
        So looks like there is no single, predefined, standard approach.

      2. This excessive struggling is exactly why I wrote this article in the first place. It took me hours and hours and hours of searching and swearing just to get my tar ball approach figured out and working. I am going to send you an email to see if we can take this further and solve it between the two of us.

  2. I also had another question: when I create a directory named “platforms” and placed the libqxcb.so, how does my application know that there is a directory named “platforms” and it has a .so file? I understand that for libs, we use export LD_LIBRARY_PATH, but how are we communicating the app to go and look for some plugins in the platforms directory. Am I missing something here? (Your post also does not mention anything specific about this)

  3. Sorry for multiple replies, but I found people suggesting using the path “plugins”, “plugins/platforms”, “platforms”, “/plugins/platform”, “platform” to place libqxcb.so. Not sure, why Qt dynamic linking is not so standardized. (I am saying this assuming I am not missing any basic step or doing something silly).

    1. Sticking it under /platforms has always worked for me (the tar ball approach)…we just need to figure out what the link is between the “run script and directory” way and the Qt IF one. I sent you an email 🙂

  4. Sorry again (now this has become a habit). The whole issue was happening because 1 of the Qt libraries (my application referring to) was a different version from what libqxcb.so was referring. I am only guilty that I wasted your time, but not guilty of the mistake as such because I was expecting a smooth linking procedure from Qt. It is an added burden for a developer to treat liking core libraries and plugins differently. According to me, if it is a library (either core or plugin) the location to look for it should have been same, which might have made me to figure out the issue much earlier. Now I have progressed to :

    qrc:/main.qml:2:1: module “QtQuick.Layouts” is not installed
    qrc:/main.qml:1:1: module “QtQuick” is not installed
    qrc:/main.qml:2:1: module “QtQuick.Layouts” is not installed
    qrc:/main.qml:1:1: module “QtQuick” is not installed

    this might be due to the application not able to locate the icons or resources I guess. I will figure out and update you. Thanks for all the support till now.

    1. Hi Indio,

      I have absolutely no idea what GLib is, but if I have to hazard a guess, I’d start by compiling my app on 12.04 and THEN deploying to a 12.04 machine (I am guessing you are compiling on 14.04 and trying to deploy the same binaries to a 12.04 box).

      That is where I would start 🙂

      1. Hi
        I just figured out that the app starts if i run it with sudo. Can be something related to rpath i used as linker flags in qt creator?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s