This is a text-only version of the following page on https://raymii.org:
---
Title       :   Embed the source code directly in your Qt app with qmake and qrc, for GPL compliance
Author      :   Remy van Elst
Date        :   12-02-2022
URL         :   https://raymii.org/s/articles/Embed_the_source_code_directly_in_your_Qt_app.html
Format      :   Markdown/HTML
---



In my earlier [post on selling GPL software](/s/blog/Selling_GPL_Software_part_1_lots_of_hurdles.html) I outlined a few points that make it hard to sell GPL software. One of them is the availability of the source code. You could put it online but then everyone has access without paying. Other options like putting it behind a login or sending a link after purchase require extra systems and saving more user information, lots of extra hassle for me and the users.
One of my ideas for 'solving' this issue is by shipping the actual source code directly inside the application. This article shows you how to do that, by creating an archive of the current source code on every build with `qmake` and embedding that inside the application using `qrc`, including a button to save the archive locally to disk. It works on the desktop as well as Android, including the required permissions.



<p class="ad"> <b>Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called  Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p>



![screenshot][9]

> Screenshot of the demo application


The example program has 2 buttons, one to save the zip archive we dynamically
create on every build and one to save the example image. The example image is a
random screenshot I found in an old folder from one of my previous jobs, that
system is no longer in use.

This solves another hurdle, the mobile app source aspect. On a desktop
I can provide a zip file with the installer and source code, but in the
app stores I cannot do that, just an `.apk` file or `.aab` bundle.

By embedding the code inside the application, on Android the users can
save the code from within the app to their system, no need to download
a source archive.

This guide works for Qt5 and assumes you're familiar with the Qt framework
and Qml. The demo program can be found [on github][2]. The first part of
the guide covers dynamically creating the source archive on every build
and the second part covers embedding it in a Qt application.


This is part 2 in my series on selling GPL software. You can find
the other parts here:

- [Part 1: Selling my own GPL software, part 1: a lot of hurdles](https://raymii.org/s/blog/Selling_GPL_Software_part_1_lots_of_hurdles.html)
- [Part 2: Embed the source code directly in your Qt app with qmake and qrc, for GPL compliance](https://raymii.org/s/articles/Embed_the_source_code_directly_in_your_Qt_app.html)
- [Part 3: Existing GPL software for sale](https://raymii.org/s/blog/Existing_GPL_software_for_sale.html)




### Source code availability

If you haven't read the [previous article][1], I recomend you do, as this
explains why I'm struggling with this part, source code availability. I do
want the source to be available, but only to actual customers. Whatever they
then do with the source code is their right, as long as it's compliant with
the GPL. So I'm not against publishing the code, but I also don't want to end
up with the software being available everywhere. In the end, if a customer does
buy the program and publishes the source, it's their right to do so and I'm fine
with that.

The [GPL FAQ][10] has three Q&A items regarding charging and source distribution
which answer all the questions you might have:

**Does the GPL allow me to sell copies of the program for money?**

> Yes, the GPL allows everyone to do this. The right to sell copies is part of
 the definition of free software. Except in one special situation, there is
 no limit on what price you can charge. (The one exception is the required
 written offer to provide source code that must accompany binary-only
 release.)


**Does the GPL allow me to charge a fee for downloading the program from my
 distribution site?**

> Yes. You can charge any fee you wish for distributing a copy of the program.
 Under GPLv2, if you distribute binaries by download, you must
 provide "equivalent access" to download the source--therefore, the fee to
 download source may not be greater than the fee to download the binary. If
 the binaries being distributed are licensed under the GPLv3, then you must
 offer equivalent access to the source code in the same way through the same
 place at no further charge.

**If I distribute GPLed software for a fee, am I required to also make it
 available to the public without a charge?**

> No. However, if someone pays your fee and gets a copy, the GPL gives them
 the freedom to release it to the public, with or without a fee. For
 example, someone could pay your fee, and then put her copy on a web site
 for the general public.



The last line of the second item, `you must offer equivalent access to the
source code in the same way through the same place at no further charge`,
seems to be covered as far as I can tell when I provide the source together
with the download and inside the application (whenever a download is not
possible such as on app-stores).

One of the effects of this way of publishing the source code is that you do
need to be able to run the application before you can extract the source
code. Newer versions also require a new purchase, since the app only ships
with that version's source code. On desktop platforms I do plan to ship an
archive of the source in the download after purchase, so you're not required
to run the application to get the source, but on Android in the app store
that is not possible. So, in that case, this is best effort, if it even gets
through app-store review.


### qmake a source code archive

You can find the example project [here on github][2]. This section
of the article covers how the source code archive is made, later on we'll
cover the `qrc` section to extract the archive on disk.

I'm shipping a simple `.zip` archive with the source code and relevant
project files. The file is created with the following command:

   zip -r source.zip ./ -i '*.cpp' '*.h' '*.qml' '*.qrc' '*.pro' '*.png' 'README.md' 'LICENSE'

This command produces a zip file relative to the current working directory
in which the folder structure is preserved. It includes all files on
the wildcard extensions list and the `README.md` file.

This file, `source.zip`, is referenced in the `DISTFILES` section of the `.pro`
file as well as in the `qrc` file (to be embedded in the application), so
it must be available before building the program.

At first I tried to add an extra compiler to the `qmake` project file,
as is [documented here][3], but that was a bit of a hassle. Either I
had to add all input files, otherwise changes would not be detected,
or there would be a lot of variable trickery. Also, when the command
runs wasn't entirely predictable, and I need to run the command **before**
the actual build. This is because we reference the `source.zip` file in
our `qrc` file, it must be there before we build.


In the end I used a simple `system()` command, which is guaranteed to run
before the actual build:

   system(cd $$PWD; rm source.zip; zip -r source.zip ./ -i \'*.cpp\' \'*.h\' \'*.qml\' \'*.qrc\' \'*.pro\' \'*.png\' \'android/*\' 'README.md' 'LICENSE')


This is not cross-platform and only works with this specific zip version's
commandline flags, but for now that's fine enough. I can always encapsulate
a different command later on in a block like below:

   win32 {
       system(windows command)
   } else {
       system(linux command)
   }


The output when building via Qt Creator or running `qmake` looks like this:

   19:48:23: Running steps for project qrcToDisk...
   19:48:23: Starting: "/bin/qmake" /src/QtExamples/qrcToDisk/qrcToDisk.pro -spec linux-g++ CONFIG+=debug CONFIG+=qml_debug
     adding: src/QtExamples/qrcToDisk/files/example.png (deflated 14%)
     adding: src/QtExamples/qrcToDisk/SaveToDisk.cpp (deflated 56%)
     adding: src/QtExamples/qrcToDisk/qml.qrc (deflated 36%)
     adding: src/QtExamples/qrcToDisk/main.qml (deflated 64%)
     adding: src/QtExamples/qrcToDisk/main.cpp (deflated 50%)
     adding: src/QtExamples/qrcToDisk/qrcToDisk.pro (deflated 41%)
     adding: src/QtExamples/qrcToDisk/SaveToDisk.h (deflated 33%)
   19:48:23: The process "/bin/qmake" exited normally.


If you omit the `rm` command, any already existing files will be overwritten and new files
are added. Old files are not removed.

The zip archive opens just fine and the contents are as expected:

![zipfile][8]


### Save a Qt qrc embedded file to disk

A `qrc` file is part of the [Qt resource system][5]. The Qt resource system is
a platform-independent mechanism for storing binary files in the
application's executable. Most often `qmake` generates `make` rules to
generate the file `qrc_application.cpp` which is linked into your
application. This file contains all the data for the images and other
resources as static C++ arrays of compressed binary data.

You can also configure `qrc` to create an external binary resource file which
is later registered with the resource system. This is useful if you have, for
example, two sets of images for the same codebase.


Below you'll find the example contents of my `qml.qrc` file:

   <RCC>
       <qresource prefix="/">
           <file>main.qml</file>
           <file>files/example.png</file>
           <file>source.zip</file>
       </qresource>
   </RCC>


Copying a file out of `qrc` to the filesystem is as simple as calling
`QFile::copy`. `QFile` supports the Qt resource system and if your file's
path starts with a colon (`:`), it knows to look in the resource system
for the filename. An example:


   QFile::copy(":/files/example.png", "/tmp/example.png");

With the above `qrc` file, the file `example.png` that is embedded in the
application will be copied to the `/tmp` folder.


The demo program I wrote to test this does a bit more, like sanitizing the
filename, checking for non-existing folders and overwriting, but the one
`QFile::copy` like is the gist of it.

One problem I had was that at first I used a [QML FileDialog][4] to let the
user select the folder to save the files into. The returned path however, on
linux, started with `file://`, instead of just the path(`/home/user/...`). On
Android, the path returned, no matter what the user choose, was
`/data/user/0/org.qtproject.example.qrcToDisk`, which is not a folder the
user can browse to. At first I tried to work around those issues, but that
proved not to work reliably, so I opted to just use
`QStandardPaths::DocumentsLocation`, which should always return something,
create the folder if needed.

One other thing to keep in mind is that by default the permissions of files
in the `qrc` file are read-only (since you can't write back to it) and
`QFile` copies those permissions. In the example project I set the file
permission of the new file to be writable.


Same thing goes for the case where the destination file already exists,
`QFile::copy` will fail unless you manually remove that file.

In this example I overwrite any existing files, it's up to any users of this
example to implement a user question to overwrite.


There is a bit of boilerplate code to request permissions dynamically on
Android, those permissions are already in the `AndroidManifest.xml` file,
but newer versions of Android also require you to ask for them before
using them, so we do. If it all works, it looks like below:

![android save][6]

Once saved, the files are in the `Documents` folder:

![source Android][7]

[1]: /s/blog/Selling_GPL_Software_part_1_lots_of_hurdles.html
[2]: https://github.com/RaymiiOrg/QtQrcSourceCodeToDisk
[3]: http://web.archive.org/web/20211007231100/https://doc.qt.io/qt-5/qmake-advanced-usage.html#adding-compilers
[4]: http://web.archive.org/web/20210507002851/https://doc.qt.io/qt-5/qml-qtquick-dialogs-filedialog.html
[5]: http://web.archive.org/web/20220211112006/https://doc.qt.io/qt-5/resources.html
[6]: /s/inc/img/savetodisk2.jpg
[7]: /s/inc/img/savetodisk3.jpg
[8]: /s/inc/img/savetodisk1.png
[9]: /s/inc/img/savetodisk4.png
[10]: https://www.gnu.org/licenses/gpl-faq.html#DoesTheGPLAllowDownloadFee



---

License:
All the text on this website is free as in freedom unless stated otherwise.
This means you can use it in any way you want, you can copy it, change it
the way you like and republish it, as long as you release the (modified)
content under the same license to give others the same freedoms you've got
and place my name and a link to this site with the article as source.

This site uses Google Analytics for statistics and Google Adwords for
advertisements. You are tracked and Google knows everything about you.
Use an adblocker like ublock-origin if you don't want it.

All the code on this website is licensed under the GNU GPL v3 license
unless already licensed under a license which does not allows this form
of licensing or if another license is stated on that page / in that software:

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

Just to be clear, the information on this website is for meant for educational
purposes and you use it at your own risk. I do not take responsibility if you
screw something up. Use common sense, do not 'rm -rf /' as root for example.
If you have any questions then do not hesitate to contact me.

See https://raymii.org/s/static/About.html for details.