|
|
| 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 /> <<<span class="caps">CTRL</span>>><br /> Package: mflqta<br /> Version: 1.0.0<br /> Section: utils<br /> Maintainer: lexasss <lexasss@domain.com><br /> Homepage: [Project Website]<br /> Priority: optional<br /> Architecture: i386<br /> Depends: libc6<br /> Description: My first testing Qt app on Linux. Just testing
| |
|
| |
| <</CTRL>><br /> <<<span class="caps">FILES</span>>><br /> 1<br /> /path/to/mflqta/pkg/mflqta.png -> mflqta.png -> /usr/share/pixmaps<br /> /path/to/mflqta/pkg/mflqta.desktop -> mflqta.desktop -> /usr/share/applications<br /> /path/to/mflqta/pkg/mflqta* -> mflqta -> /usr/bin<br /> /path/to/mflqta/pkg/mflqta.sh -> mflqta.sh -> /usr/bin<br /> /path/to/Qt/lib/libQt5Widgets.so.5* -> libQt5Widgets.so.5 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5Gui.so.5* -> libQt5Gui.so.5 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5Core.so.5* -> libQt5Core.so.5 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libQt5DBus.so.5* -> libQt5DBus.so.5 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicuuc.so.49* -> libicuuc.so.49 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicui18n.so.49* -> libicui18n.so.49 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/lib/libicudata.so.49* -> libicudata.so.49 -> /usr/lib/i386-linux-gnu/qt5<br /> /path/to/Qt/plugins/platforms/libqxcb.so* -> libqxcb.so -> /usr/lib/i386-linux-gnu/qt5/platforms<br /> <</FILES>><br /> <[removed]><br /> <<<span class="caps">PREINST</span>>><br /> 0<br /> <</PREINST>><br /> <<<span class="caps">POSTINST</span>>><br /> 0<br /> <</POSTINST>><br /> <<<span class="caps">PRERM</span>>><br /> 0<br /> <</PRERM>><br /> <<<span class="caps">POSTRM</span>>><br /> 0<br /> <</POSTRM>><br /> <[removed]><br /> <<<span class="caps">CHANGELOG</span>>><br /> <<<span class="caps">DEST</span>>><span class="caps">DEFAULT</span><</DEST>><br /> <</CHANGELOG>><br /> <<<span class="caps">COPYRIGHT</span>>><br /> <</COPYRIGHT>><br /> <<<span class="caps">MENU</span>>><br /> 0<br /> <</MENU>><br /> <<<span class="caps">BUILD</span>>><br /> 0<br /> 1<br /> 1<br /> <</BUILD>>
| |
|
| |
| </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<…>'' 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 > Accessories” menu in Fedora.
| |
|
| |
| ===Categories:===
| |
|
| |
| [[:Category:Deploying-Qt5-Applications|Deploying Qt5 Applications]]
| |