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.

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:

I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.

You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days.

![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: main.qml files/example.png source.zip 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 . 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.