Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.

Deploying a Qt5 Application Linux: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
=Creating installation package of Qt5 application for Linux/X11: Personal Experience=


======[please help to format this article properly]======
I’m quite new in Linux, but recently got a special interest in building apps for this platform using Qt5, as I had already experience in using this framework in Windows. The first issue I was interesting in while moving my projects onto the Linux platform was how do I distribute my apps to others. By “others” I mean people who are not geeks in Linux: they probably more familiar with Windows than Linux and expect an app to be installed in few clicks and appear in their applications menu. So, I formulated my task as
'''create a simple application for Linux/X11 and package its binaries properly, so that others could download it, easily install and run from the applications menu without any programming/scripting knowledge.'''
I knew that the variety of Linux distribution makes my task a bit challenging, so I decided to start with the simplest case: my app should be installable and runnable at least on the same Linux distro as mine. Mine was Kubuntu 12.10 (with <span class="caps">KDE</span>).
First of all, I have downloaded and installed the recent Qt <span class="caps">SDK</span> version 5.0.1 directly from the qt.io. The installation went successfully, and I launched Qt Creator. Since I was just testing how to deploy my apps rather than what can I develop for Linux, I created a simple <span class="caps">GUI</span> application with QMainWindow, a menu and a toolbar. And then I was quite surprised to found out that Qt Creator cannot find any compiler to build the project – Qt Create was complaining that gcc is not found, so I had to install it manually via Kubuntu’s package manager. Now the Qt Creator was able to detect the compiler automatically, and I finally built the app. My app’s name was ''mflqta'' (My First Linux Qt App <span class="smiley">:)</span> ), and the output folder was ''~/projects/mflqta/pkg/''.
==Creating a <span class="caps">DEB</span> package==
Next, I googled how can I create an installation package for my app. I quickly found that I have to create a <span class="caps">DEB</span> package, and there are <span class="caps">DEB</span> package creators with <span class="caps">GUI</span>, so I downloaded and installed '''Debreate''' (the first item in the search results list I got from Google). It contained a link (page Information) to the YouTube video of using this app. The video helped me a lot, and I got an idea what I have to write into the Debreate’s fields. Debreate can create a shortcut for the desktop menu (''.desktop'' file) automatically (page ''Menu''), but I preferred to create it manually, since I wished to be in control of how to name this file, and add the value '''''GenericName''''': Debreate does not add it if you use its wizard, but then Kubuntu does not show the application’s description in its menu.
Then I started to search how to find the dependencies of my app. I found that I have to use the '''''ldd''''' tool. It lists all the libs loaded by an app. My application depended on many libs. However, in the Debreate’s tutorial the author was building a package for his Qt4 application and he included only a few dependencies. I wished to include all, but in further tests I learned that I cannot simply list names of libs: these should be package name, not lib’s. So I left only ''libc6'', skipping many libs (packages related to <span class="caps">MESA</span>, X11, and others). Of course, I wished to include the Qt5 package, but there was no such thing as qt5 in the Kubuntu repository! Only qt4, but this one does not suit, as I learned from building Qt5 apps in Windows. So I listed the following libs form ''/path/to/Qt/libs/'' in the “Files” section: ''libQt5Core.so.5, libQt5Gui.so.5, libQt5Widgets.so.5, libicuuc.so.49, libicui18n.so.49, libicudata.so.49'' (exactly this way, as I found in my tests: not ''.so'', nor ''.so.5.'', but ''.so.5''). Later I spent many hours finding out why my installed app cannot start: I had to include the folder platforms and the file ''libqxcb.so'' from the ''/path/to/Qt/plugins/'' into the <span class="caps">DEB</span> package. And in addition I had to install the library ''libQt5DBus.so.5'', since ''libqxcb.so'' requires it.
Next I spent many hours finding where to place the libs and how to point to my app where they are. Finally, I found the way: I installed the ''libQt5*, libicu*'' and ''platforms'' into the ''/usr/lib/i386-linux-gnu/qt5'' folder (or maybe ''/usr/lib/i386-linux-gnu/mflqta'' is a better choice?), compiled my app with the following line going first in the ''main()'' function in ''main.cpp'':<br />
and created the ''mflqta.sh'' file:<br />
(I adapted the code found on http://doc.qt.io/qt-5.0/qtdoc/deployment-x11.html ''[qt.io]'') to be launched from the ''mflqta.desktop'', which is the following:<br />
I left empty the pages Scripts, Changelog and Copyright in Debreate and saved my Debreate project into a ''mflqta.dbp'' file. Here its content:
<code>
[DEBREATE-0.7.7]<br /> &lt;&lt;<span class="caps">CTRL</span>&gt;&gt;<br /> Package: mflqta<br /> Version: 1.0.0<br /> Section: utils<br /> Maintainer: lexasss &lt;lexasss@domain.com&gt;<br /> Homepage: [Project Website]<br /> Priority: optional<br /> Architecture: i386<br /> Depends: libc6<br /> Description: My first testing Qt app on Linux. Just testing
&lt;&lt;/CTRL&gt;&gt;<br /> &lt;&lt;<span class="caps">FILES</span>&gt;&gt;<br /> 1<br /> /path/to/mflqta/pkg/mflqta.png -&gt; mflqta.png -&gt; /usr/share/pixmaps<br /> /path/to/mflqta/pkg/mflqta.desktop -&gt; mflqta.desktop -&gt; /usr/share/applications<br /> /path/to/mflqta/pkg/mflqta* -&gt; mflqta -&gt; /usr/bin<br /> /path/to/mflqta/pkg/mflqta.sh -&gt; mflqta.sh -&gt; /usr/bin<br /> /path/to/Qt/lib/libQt5Widgets.so.5* -&gt; libQt5Widgets.so.5 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5Gui.so.5* -&gt; libQt5Gui.so.5 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5Core.so.5* -&gt; libQt5Core.so.5 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5DBus.so.5* -&gt; libQt5DBus.so.5 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicuuc.so.49* -&gt; libicuuc.so.49 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicui18n.so.49* -&gt; libicui18n.so.49 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicudata.so.49* -&gt; libicudata.so.49 -&gt; /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/plugins/platforms/libqxcb.so* -&gt; libqxcb.so -&gt; /usr/lib/i386-linux-gnu/qt5/platforms<br /> &lt;&lt;/FILES&gt;&gt;<br /> &lt;[removed]&gt;<br /> &lt;&lt;<span class="caps">PREINST</span>&gt;&gt;<br /> 0<br /> &lt;&lt;/PREINST&gt;&gt;<br /> &lt;&lt;<span class="caps">POSTINST</span>&gt;&gt;<br /> 0<br /> &lt;&lt;/POSTINST&gt;&gt;<br /> &lt;&lt;<span class="caps">PRERM</span>&gt;&gt;<br /> 0<br /> &lt;&lt;/PRERM&gt;&gt;<br /> &lt;&lt;<span class="caps">POSTRM</span>&gt;&gt;<br /> 0<br /> &lt;&lt;/POSTRM&gt;&gt;<br /> &lt;[removed]&gt;<br /> &lt;&lt;<span class="caps">CHANGELOG</span>&gt;&gt;<br /> &lt;&lt;<span class="caps">DEST</span>&gt;&gt;<span class="caps">DEFAULT</span>&lt;&lt;/DEST&gt;&gt;<br /> &lt;&lt;/CHANGELOG&gt;&gt;<br /> &lt;&lt;<span class="caps">COPYRIGHT</span>&gt;&gt;<br /> &lt;&lt;/COPYRIGHT&gt;&gt;<br /> &lt;&lt;<span class="caps">MENU</span>&gt;&gt;<br /> 0<br /> &lt;&lt;/MENU&gt;&gt;<br /> &lt;&lt;<span class="caps">BUILD</span>&gt;&gt;<br /> 0<br /> 1<br /> 1<br /> &lt;&lt;/BUILD&gt;&gt;
</code>
After building the package with Debreate I got the file ''mflqta-1.0.0-1.i386.deb'' (named it manually: Debreate suggested the name ''mflqta_1.0.0_i386.deb''), installed it and found my application in the Kubuntu’s menu ''Utilities''.
==Creating <span class="caps">RPM</span> package==
Well, I got the <span class="caps">DEB</span> package, but this one seems to be usable in Debian-based Linux distros only. Most of other relatively known distros use <span class="caps">RPM</span> packages. So my next goal was packaging the <span class="caps">RPM</span>. I thought this task will be easier, since I knew what libs must be distributes, but it was not truly so. First of all, I searched for some <span class="caps">GUI</span> app that does same as the Decreate, but with ''.rpm'' file as the output. I found few, but could not install it into my Kubuntu: they all were packaged as <span class="caps">RPM</span>s. So I had to go to another distro. I selected Fedora 18 with Xfce.
I installed several tools with <span class="caps">GUI</span>, like Easy <span class="caps">RPM</span> Builder, but did find how to fill the necessary fields. It seemed that packaging <span class="caps">RPM</span>s is quite different task than packaging <span class="caps">DEB</span>. I decided to stay with a non-<span class="caps">GUI</span> tool called '''rpmbuild'''. Thanks to some web resources, I learned the steps I have to complete while building my <span class="caps">RPM</span> package. So, first I had to run these two commands in the terminal:
You would need to place [user] with your account name. Also, you are free defining any path instead of ‘rpm’ that I used in my case. Also note, that all manuals recommend building <span class="caps">RPM</span>s under non-root account.
Interestingly, the ''rpmbuild _requires 5 folders to have in its working folder (which is _~/rpm'' in my example). The folder ''<span class="caps">SOURCES</span>'' must contain the distributed files (in all example these files were in a ''tar.gz'' archive), the folder ''<span class="caps">SPECS</span>'' must contain the file ''.spec'', which is similar to the Debreate’s ''.dbp'' file I used to create my <span class="caps">DEB</span> package. The folder ''<span class="caps">BUILD</span>'' is used to extract the files from the archive located in ''<span class="caps">SOURCES</span>''. Folders ''<span class="caps">SRPMS</span>'' and ''<span class="caps">RPMS</span>'' are used to place the <span class="caps">RPM</span>s with sources and binaries accordingly. The ''rpmbuild'' also creates one more folder, ''<span class="caps">BUILDROOT</span>'', and places there the files from_ <span class="caps">BUILD</span>_ according to the rules you specify in ''.spec'', thus simulating the structure of the files and folders to be installed.
So first I had to transfer my distribution files into Fedora. In Kubuntu I created a folder ''mflqta-1.0.0-1'' and copied all the files I used to create the Deb package into it (I did not used any subfolders). I found one peculiarity here: I had to copy all 4 files for ''libQt5{Gui, Core, DBus, Widgets}'', since only the libs with ''.so.5.0.1'' ending were the real files, others were only links to the corresponding libs. I have no idea why using ''.so.5'' files worked fine for <span class="caps">DEB</span> package… So I got 16 ''libQt5*'' files in my archive. I archived the folder itself, not the files inside it. The archive name was ''mflqta-1.0.0-1.tar.gz''.
Now as my ''mflqta-1.0.0-1.tar.gz'' was placed into the ''~/rmp/SOURCES'' in Fedora, I created the file ''mflqta.spec'' and saved it into the ''~/rpm/SPECS''. I used '''gedit''' for editing – it knows how to highlight ''.spec'' file’s content, and this is very convenient (Fedora with Xfce misses gedit, I installed it separately). Here is my ''.spec'' file:
Note that I used macros here where I could. If you wonder what is ''%{_datadir}'', go to http://www.rpm.org/wiki/PackagerDocs/Macros#MacroAnaloguesofAutoconfVariables ''[rpm.org]'' .
Other note: on the very first installation trial the package manager in Fedors (Yum) was complaining about the unresolved dependency for ''libc6'', so I commented the dependency line.
One may see that the beginning of the ''.spec'' file is quite similar to the ''.dbp'' file. Then it defines the source preparation step, described in the ''%prep'' section (I think, it only extract files from ''.tar.gz'' into the ''<span class="caps">BUILD</span>'' folder). The ''%build'' section is empty (no source in my package to build). In the ''%install'' section my files (already extracted into the ''~/rmp/BUILD'') are placed into the correct folders (note that you have to create these folders first) inside of the ''$RPM_BUILD_ROOT (= ~/rpm/BUILDROOT)'' folder. Some tutorials suggest that you better create the proper folder tree in the archive already, then the ''%install'' section would have only a single line:<br />
In the ''%files'' section I did quite similar work: specified what files goes to what locations during installation. Some tutorials recommend using just ''./'' , but I have not testing this. In the section ''%clear'' are the command to clear the working folders, ''~/rpm/BUILD'' and ''~/rpm/BUILDROOT''. The ''%post&lt;…&gt;'' sections is optional and offers to run post-[un]installation scripts (similar to the analogue section in ''.dbp'' file). Finally, the ''%changelog'' section comes – every tutorial recommends filling it in the way that is shown here.
Now everything was ready to build the <span class="caps">RPM</span>. I opened the terminal in the ''~/rpm/SPECS'' folder and typed <br />
I wished to have a ''.rpm'' file with my binaries only, that’s why the parameters is ''–bb''. With the ''–ba'' parameter it also creates ''.src.rpm'' file and places it into the ''<span class="caps">SRPMS</span>'' folder. My ''mflqta-1.0.0-1.i386.rpm'' file has appeared in the ''<span class="caps">RPMS</span>'' folder.
I installed the package and found my app’s icon in the “Application menu &gt; Accessories” menu in Fedora.
===Categories:===
[[:Category:Deploying-Qt5-Applications|Deploying Qt5 Applications]]

Revision as of 08:52, 24 February 2015