Development is not an only part of product delivering – deployment and maintenance are both equally important parts of the product lifecycle. That is why Qt lend us a hand by providing Installer Framework. It is a set of tools that allows not only to create good-looking and functional installers but also update the app, provide tools for maintaining it, and much more. In this tutorial, you will learn the basics of Qt Installer Framework and find out how to generate your first offline installer for Windows. Let’s go!
Qt Installer framework can be easily installed via Qt Maintenance tool or downloaded from Qt repository. When using a maintenance tool, it can be found in the Developer and Designer Tools section:
After download it should be stored in [QtDirectory]/Tools/QtInstallerFramework
Before generating an installer, you have to prepare your app for deployment. The first step is to create a deployment folder where all necessary files for app execution and installer generation will be stored. Inside it, you should create two directories: „config” and „packages”.
As the name suggests, the first directory will contain configuration files for your installer – in this case a single XML file. What should this file contain?
The configuration file consists of some general information about the app: installation directory, name of the installer, etc. You can make some interesting things by modifying this file – for example, add a „run after installation” checkbox, modify installer UI or even add remote repositories for fetching app updates. You can learn about all the available tags in the Qt Installer documentation.
Let’s create such a file. The basic one should look like this:
<?xml version="1.0" encoding="UTF-8"?> <Installer> <Name>APP NAME</Name> <Version>1.0.0</Version> <Title>INSTALLER WINDOW TITLE</Title> <Publisher>Scythe Studio</Publisher> <StartMenuDir>START_MENU_DIR</StartMenuDir> <TargetDir>@HomeDir@/APP_DIR</TargetDir> </Installer>
Although it is minimalistic, for now, this would be enough.
Before you go any further, you should learn what the package actually is. The package is a module that contains a certain version or some parts of the app. If you include many packages, the installation can be customized – users can select what they want to install. Qt itself is a great example of such approach. Let’s take a look at the tree structure in the Qt installer:
As you see, the framework is divided into several packages containing kits for different platforms and modules with optionals functionality like a web engine.
According to the documentation, the packages directory should have following structure:
-packages - com.vendor.root - data - meta - com.vendor.root.component1 - data - meta - com.vendor.root.component1.subcomponent1 - data - meta - com.vendor.root.component2 - data - meta
With this knowledge, you can now start creating the first packages for our app. To make things clear and simple, for now, we’ll roll on with only two packages: a 64-bit app version and a 32-bit one.
Begin by creating proper directories for the packages. We will stick to the „com.developername.shortpackagename” naming pattern:
What about packages content? Let’s begin populating them!
Each package should contain two main directories inside: „data” and „meta”. First will contain executables, libraries, and other files necessary for running the app, while second hold information about the package. The „Meta” folder will contain only two files, in this case, so start with it.
Metadata should consist of „license.txt” and „package.xml” files. The text file is obvious – it provides the installer with license content. It doesn’t have any required format, but HTML tags are supported if you need some styling.
Now let’s talk about „package.xml” – this one is more interesting. This file contains information about the package, which will be presented in the installer window. By putting additional tags you can add custom installer pages, translations, dependencies between other packages and many more. We will talk about this file again, in another part of the tutorial, which will be published in the future. The „package.xml” content should look like this for now:
<?xml version="1.0" encoding="UTF-8"?> <Package> <DisplayName>PACKAGE NAME</DisplayName> <Description>This is going to install APP NAME on your machine</Description> <Version>1.0.0</Version> <ReleaseDate>2020-06-17</ReleaseDate> <Licenses> <License name="LICENSE TITLE" file="license.txt" /> </Licenses> <Default>true</Default> </Package>
Most of the tags are self-explanatory. If you want to learn more about other tags see documentation.
When you add necessary files to the „meta” directory, move one to the „data” folder. This directory contains all the app files that the package holds. When installing the package, its contents will be unpacked to the target directory. In order to keep the installation folder clear, we suggest creating an additional subfolder in the data directory.
As there is already a large number of folders we talked about, we’ll call this one „package files directory”. With that keeping track would be simpler.
Now the crucial part of deployment preparation begins. Inside the package files directory, you need to add a substantial amount of files needed to run an app outside the Qt Creator IDE: all the executables, Qt and external libraries, dll files, etc. Fortunately, the Qt Framework will help us achieve this by providing a set of tools for deployment.
Now add the executable file to the package files directory. Simply copy it from the build folder. Now open the command line terminal in the package files directory. It is needed to run „windeployqt.exe” – a tool created for automatic loading of all the Qt dll files needed for running the app. To run this tool use this command:
[QtFolder]\[QtVersionThatYouUse]\[SelectedKitDirectory]\bin\windeployqt.exe APPNAME.exe --qmldir [DirectoryContainingProjectQMLSourcecode] --compiler-runtime
This command adds (almost) all necessary binaries and files that you need to launch a QML based app. The -qmldir flag is used to scan your QML code and add all the needed runtime libraries from the Qt Quick module. After this flag put your project directory – don’t worry it will be scanned recursively. If your app is not QML based, you can skip this flag.
In the tutorial case the full command should look like this:
C:\Qt\5.15.0\mingw81_64\bin\windeployqt.exe QtInstallerTutorial.exe --qmldir C:\Projects\QtInstallerTutorial --compiler-runtime
When the tool finishes its work you can see that now the package files directory is getting crowded.
Currently, windeployqt tool tends to ship a lot of unnecessary files here, but even now there is no every file you need. Not yet…
If you try to run the application now you’ll get an error pop-up showing info about missing files. Depending on the configuration, compiler-specific and some other libraries must be redistributed along with your application. According to the documentation, the basic ones are:
VC++ 14.0 (2015)
VCCORLIB140.DLL, VCRUNTIME140D.DLL – The C runtime
MSVCP140.DLL – The C++ runtime
However, to make sure that you didn’t miss anything, following Qt docs advice, we suggest using the Dependency Walker tool. After running it you can easily see what dependencies are missing.
In this case, the LIBGCC_S_SEH-1.DLL and LIBSTDC++-6.DLL are missing. You can find them in the Qt folder, inside the kit directory: