Yocto/Qt5: hello-qt part2 - Licensing
Introduction
This work is sponsored by Reliable Embedded Systems. You can find more information about our training/consulting services here.
Objectives
The
goal of this blog post is to show my journey trying to build a hello-qt
application and reasons why I don't like Qt. As far as I can tell this is going to be a multi part blog post. You might want to have a look at part one as well. Disclaimer: I am not a lawyer, so I can not give legal advice.
GPL and LGPL licenses
LGPL v2.x
- Typically libraries are licensed with this license
- You need to provide the source code (including modifications) and instructions on how to build the LGPL v2.1 licensed code
- In case your application links statically against LGPL licensed code you need to provide the object files of your applications to be able to replace the LGPL'ed code with different versions
- In case your application links dynamically against LGPL licensed code you can replace the LGPL'ed libraries without the object files of your application which links against it
- Linking statically/dynamically against a LGPL'ed library does not make your library automatically LGPL as well, but you can license it with a compatible license (e.g. proprietary)
GPL v2.x
- Linking statically or dynamically against a GPL'ed library typically makes your application inherit the license, hence your application becomes GPL as well (note that there are exceptions to this e.g. the glibc runtime exception which allow for a hello-world to link against the glibc and still you can have it as a proprietary application)
LGPL v3.x and GPL v3.x
- whatever applies for (L)GPL plus
- Protection against "Tivoization" as explained below
- No Patent retaliation, as explained below
- No DRM protection, as explained below
Summary
In general with (L)GPL v2.x there is no need to make it possibly for someone to actually be able to run the application which is (L)GPL v2.x or links against a GPL v2.x library while with (L)GPL v3.x there is. You can restrict the use of (L)GPL v2.x code by locking down the device (Tivoization) which is not allowed with (L)GPL v3.x.Qt and the community
Qt commercial license cost
- pay (
- A 100 unit distro license costs 7246 EUR (before shipping the 1st unit)[2]
- LTS (long-term support) releases are not available to FOSS users, once the next minor or major release is out[1]
[1] https://www.qt.io/blog/qt-offering-changes-2020
Qt software license(s)
I will cite/copy/add/remove to stuff from here.[2][3]
One might think that there are 3 licensing options available:
- commercial license, or
- the LGPLv3 license, or
- the GPLv3 license
Qt under LGPL and GPL
If you use Qt under (L)GPL, you must give your end-users the right to study and modify source code.
Qt under LGPL
- If you use Qt under the LGPL, your end-users must be able to replace
the Qt libraries with a version of their choice.
Your device must continue to function after they perform the replacement (unless Qt itself broke compatibility with your original version).You must provide your end-users a copy of the Qt source code or make it clear to them that you will supply the Qt source code upon request.
Qt under GPL
- If you use Qt under the GPL, you must do everything you'd do under LGPL, PLUS you must also offer the same freedoms to all of your code that won't work without Qt. (In other words, you give your customers the freedom to modify and rebuild your code.)
Qt under LGPL and GPL
In addition, if you use Qt under (L)GPL, you must:
- Make it clear to your users that your device uses Qt.
- Provide a copy of the (L)GPL license to your users.
- Publish any changes that you've made to the Qt source code.
Additional things to consider with (L)GPLv3[3]
User Products
The items mentioned below (Tivoization, Not Patent retaliation, No DRM protection) apply only to "User Products".
- A "User Product" is
- A Consumer Product
- Anything designed or sold for incorporation into a dwelling
Tivoization
- Closing/Locking down devices (Tivoization) such as not allowing the end user to modify the software is prohibited
- You are not allowed to provide e.g. encryption keys or other techniques used in the device to limit tinkering and access
- But it's limited to "User Products"
- A "User Product" is
- A Consumer Product
- Anything designed or sold for incorporation into a dwelling
- Does it affect military? Depends
- Does it affect medical? Depends
- Does it affect IPTV? Set-top box yes since it's a "Consumer Product" and can be incorporated in a dwelling.
No Patent retaliation
- It's not possible to implement or enforce software patents when using a(n) (L)GPL v3 library.
- Section 10[4] prohibits people who use the software from filing patent suits against other licensees.
- This is a very important point for many, especially larger, corporations and a main reason that (L)GPLv3 is a license that several major companies specifically do not allow to use internally.
No DRM protection
- Implementing DRM systems with (L)GPLv3 licensed software will not act as an effective technological "protection" measure. No part of (L)GPLv3 forbids DRM regarding non-(L)GPLv3 licensed software.
Qt under commercial license
If you use Qt under the commercial license, you don't have to offer any of the above. Instead, you must:
- Pay the Qt Company the fees as specified in the license.
- (For small businesses) Allow your finances to be audited.
- Take care not to mix software you've developed under commercial Qt with software that you've developed under open source Qt.
- Forbid your users from modifying and sharing Qt and your software.
How does static/dynamic linking fit into the picture?
- If you use Qt under GPL Application code and Qt code must be shared under GPL.[3]
- If you use Qt under LGPL, remember that one of your obligations is to allow your customers to replace the Qt libraries. Dynamic linking provides one way to fulfill this obligation -- as long as you enable your customers to replace Qt's *.so files on your device, then the LGPL allows you to release your own software under whatever license you want.
- The LGPL does not require you to release the sources of the Application which links against the LGPL'ed libraries. In the case of static linking the LGPL does, however, require you to make available object files of your code that allow for the relinking of your code against updated versions of the LGPL'ed libraries.
- The LGPL requires you to share modifications to the LGPL'ed code.
What are possible problems?
(L)GPLv3
- Is it possible to have an image without (L)GPLv3 components?
local.conf
I turned on various licensing/Open Source compliance options in my local.conf
:
### --> license compliance INCOMPATIBLE_LICENSE = "The-Qt-Company-Commercial" # Archive the source and put them to ${DEPLOY_DIR}/sources/. # INHERIT += "archiver" # # The tarball for the patched source will be created by default, and you # can configure the archiver as follow: # # Create archive for: # 1) original (or unpacked) source: ARCHIVER_MODE[src] = "original" # 2) patched source: (default) #ARCHIVER_MODE[src] = "patched" # 3) configured source: #ARCHIVER_MODE[src] = "configured" # # 4) the patches between do_unpack and do_patch: ARCHIVER_MODE[diff] = "1" # set the files that you'd like to exclude from the diff: #ARCHIVER_MODE[diff-exclude] ?= ".pc autom4te.cache patches" # # 5) the environment data, similar to 'bitbake -e recipe': ARCHIVER_MODE[dumpdata] = "1" # # 6) the recipe (.bb and .inc): ARCHIVER_MODE[recipe] = "1" # # 7) Whether output the .src.rpm package: #ARCHIVER_MODE[srpm] = "1" # # 8) Filter the license, the recipe whose license in # COPYLEFT_LICENSE_INCLUDE will be included, and in # COPYLEFT_LICENSE_EXCLUDE will be excluded. COPYLEFT_LICENSE_INCLUDE = 'GPL* LGPL* AGPL*' COPYLEFT_LICENSE_EXCLUDE = 'CLOSED Proprietary' # # 9) Config the recipe type that will be archived, the type can be # target, native, nativesdk, cross, crosssdk and cross-canadian, # you can set one or more types. Archive all types by default. COPYLEFT_RECIPE_TYPES = 'target' # # include license text in image COPY_LIC_MANIFEST = "1" COPY_LIC_DIRS = "1" ### <-- license compliance
Let's BitBake core-image-minimal
$ bitbake core-image-minimal NOTE: Started PRServer with DBfile: /workdir/build/multi-v7-ml-qt5/cache/prserv.sqlite3, IP: 127.0.0.1, PORT: 37545, PID: 1008877 Parsing recipes: 100% |#######################################################################################################################################| Time: 0:00:57 Parsing of 2266 .bb files complete (0 cached, 2266 parsed). 3377 targets, 372 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Build Configuration: BB_VERSION = "1.46.0" BUILD_SYS = "x86_64-linux" NATIVELSBSTRING = "ubuntu-18.04" TARGET_SYS = "arm-resy-linux-gnueabi" MACHINE = "multi-v7-ml" DISTRO = "resy" DISTRO_VERSION = "3.1.2" TUNE_FEATURES = "arm armv7a vfp thumb callconvention-hard" TARGET_FPU = "hard" meta meta-poky meta-yocto-bsp = "2020-08-28-dunfell-3.1.2+:d3d80fa6fbf15189f6183a33c95fa90053535ae2" meta-multi-v7-ml-bsp = "dunfell:30a525012dcc6017beb3bdb735b53b6b07908303" meta-u-boot-wic-bsp = "dunfell:4dbfc93ee3fe797cee5a25ef7a389eeaec70f418" meta-resy = "dunfell:2968f06c1e400131e15bd726808a43195eec8c16" meta-oe meta-networking meta-filesystems meta-python = "2020-04-30-dunfell-3.1:17fd382f3467e20308924499b7531ae8b789f056" meta-qt5 = "2020-09-08-dunfell:0e7015f7a86dda995a39662edbb5c26da647c496" meta-qt5-examples = "<unknown>:<unknown>" Initialising tasks: 100% |####################################################################################################################################| Time: 0:00:01 Sstate summary: Wanted 718 Found 715 Missed 3 Current 0 (99% match, 0% complete) NOTE: Executing Tasks NOTE: Tasks Summary: Attempted 1920 tasks of which 1778 didn't need to be rerun and all succeeded. NOTE: Writing buildhistory NOTE: Writing buildhistory took: 2 seconds
target components (not native and not cross) licensed with (L)GPLv3 potentially preventing Tivoization/DRM/Patents:
$ find tmp/deploy/licenses/ | grep -i gpl | grep 3 | grep -v native | grep -v cross tmp/deploy/licenses/gcc-runtime/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/readline/generic_GPLv3 tmp/deploy/licenses/libgcc-initial/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/libgcc/generic_GPLv3 tmp/deploy/licenses/libgcc/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/gdbm/generic_GPLv3 tmp/deploy/licenses/xz/generic_GPL-3.0-with-autoconf-exception tmp/deploy/licenses/xz/COPYING.GPLv3 tmp/deploy/licenses/bash/generic_GPLv3
readline
gdbm
xz
bash
buildhistory/images/multi_v7_ml/glibc/core-image-minimal/
so core-image-minimal
seems to be free of (L)GPLv3 components. Not sure how realistic this is on bigger images.core-image-minimal-qt5
$ bitbake core-image-minimal-qt5 NOTE: Started PRServer with DBfile: /workdir/build/multi-v7-ml-qt5/cache/prserv.sqlite3, IP: 127.0.0.1, PORT: 39499, PID: 1027356 Parsing recipes: 100% |#######################################################################################################################################| Time: 0:00:56 Parsing of 2266 .bb files complete (0 cached, 2266 parsed). 3377 targets, 372 skipped, 0 masked, 0 errors. NOTE: Resolving any missing task queue dependencies Build Configuration: BB_VERSION = "1.46.0" BUILD_SYS = "x86_64-linux" NATIVELSBSTRING = "ubuntu-18.04" TARGET_SYS = "arm-resy-linux-gnueabi" MACHINE = "multi-v7-ml" DISTRO = "resy" DISTRO_VERSION = "3.1.2" TUNE_FEATURES = "arm armv7a vfp thumb callconvention-hard" TARGET_FPU = "hard" meta meta-poky meta-yocto-bsp = "2020-08-28-dunfell-3.1.2+:d3d80fa6fbf15189f6183a33c95fa90053535ae2" meta-multi-v7-ml-bsp = "dunfell:30a525012dcc6017beb3bdb735b53b6b07908303" meta-u-boot-wic-bsp = "dunfell:4dbfc93ee3fe797cee5a25ef7a389eeaec70f418" meta-resy = "dunfell:2968f06c1e400131e15bd726808a43195eec8c16" meta-oe meta-networking meta-filesystems meta-python = "2020-04-30-dunfell-3.1:17fd382f3467e20308924499b7531ae8b789f056" meta-qt5 = "2020-09-08-dunfell:0e7015f7a86dda995a39662edbb5c26da647c496" meta-qt5-examples = "<unknown>:<unknown>" Initialising tasks: 100% |####################################################################################################################################| Time: 0:00:02 Sstate summary: Wanted 810 Found 807 Missed 3 Current 0 (99% match, 0% complete) NOTE: Executing Tasks NOTE: Tasks Summary: Attempted 2131 tasks of which 1977 didn't need to be rerun and all succeeded. NOTE: Writing buildhistory NOTE: Writing buildhistory took: 2 seconds
$ find tmp/deploy/licenses/ | grep -i gpl | grep 3 | grep -v native | grep -v cross tmp/deploy/licenses/gcc-runtime/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/qtbase/LICENSE.GPL3 tmp/deploy/licenses/qtbase/generic_LGPL-3.0 tmp/deploy/licenses/qtbase/generic_GPL-3.0 tmp/deploy/licenses/qtbase/LICENSE.LGPL3 tmp/deploy/licenses/qtbase/LICENSE.GPL3-EXCEPT tmp/deploy/licenses/readline/generic_GPLv3 tmp/deploy/licenses/libgcc-initial/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/libgcc/generic_GPLv3 tmp/deploy/licenses/libgcc/generic_GPL-3.0-with-GCC-exception tmp/deploy/licenses/gdbm/generic_GPLv3 tmp/deploy/licenses/qtserialport/LICENSE.GPL3 tmp/deploy/licenses/qtserialport/generic_LGPL-3.0 tmp/deploy/licenses/qtserialport/generic_GPL-3.0 tmp/deploy/licenses/qtserialport/LICENSE.LGPL3 tmp/deploy/licenses/qtserialport/LICENSE.GPL3-EXCEPT tmp/deploy/licenses/xz/generic_GPL-3.0-with-autoconf-exception tmp/deploy/licenses/xz/COPYING.GPLv3 tmp/deploy/licenses/bash/generic_GPLv3
readline
gdbm
xz
bash
qtbase
qtserialport
Those are in the image (along with hello-qt
):
$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/installed-packages.txt | grep qt | grep -v kernel hello-qt_1.0+git0+170daf4616-r0.0_armv7at2hf-vfp.ipk libqt5serialport5_5.14.2+git0+30807cadfc-r0.3_armv7at2hf-vfp.ipk libqt5serialport-plugins_5.14.2+git0+30807cadfc-r0.3_armv7at2hf-vfp.ipk libqt5serialport-qmlplugins_5.14.2+git0+30807cadfc-r0.3_armv7at2hf-vfp.ipk qtbase-plugins_5.14.2+git0+3a6d8df521-r0.2_armv7at2hf-vfp.ipk qtbase-qmlplugins_5.14.2+git0+3a6d8df521-r0.2_armv7at2hf-vfp.ipk qtbase_5.14.2+git0+3a6d8df521-r0.2_armv7at2hf-vfp.ipk
Remember from above?
- commercial license, or
- the LGPLv3 license, or
- the GPLv3 license
qtbase_git.bb
recipe the LICENSE
field does not show quite an "or", butLICENSE = "GFDL-1.3 & BSD & ( GPL-3.0 & The-Qt-Company-GPL-Exception-1.0 | The-Qt-Company-Commercial ) & ( GPL-2.0+ | LGPL-3.0 | The-Qt-Company-Commercial )"
- GFDL-1.3, and
- BSD, and
- ( GPL-3.0 and The-Qt-Company-GPL-Exception-1.0, or
- The-Qt-Company-Commercial ), and
- ( GPL-2.0+, or
- LGPL-3.0, or
- The-Qt-Company-Commercial )
What does this mean?
This means that only in the last part we have
- ( GPL-2.0+, or
- LGPL-3.0, or
- The-Qt-Company-Commercial )
or (from the first part) we need either GPL-3.0 and The-Qt-Company-GPL-Exception-1.0 or The-Qt-Company-Commercial.
In other words if we want to set The-Qt-Company-Commercial as an INCOMPATIBLE_LICENSE
we need to allow GPL-3.0.
Does Qt add GPL-3.0 components/libraries into the rootfs as indicated by this funny LICENSE
field in the recipe? Potentially yes! One issue for your application if it links against a GPL(-3.0) library is that whatever links against a GPL(-3.0) licensed library also inherits this license no matter if linked statically or dynamically. Does our application code inherit the GPL-3.0 license?
At the moment it does not seem to due to The-Qt-Company-GPL-Exception-1.0 which goes like that:
The Qt Company GPL Exception 1.0
Exception 1:
As a special exception you may create a larger work which contains the
output of this application and distribute that work under terms of your
choice, so long as the work is not otherwise derived from or based on
this application and so long as the work does not in itself generate
output that contains the output from this application in its original
or modified form.
Exception 2:
As a special exception, you have permission to combine this application
with Plugins licensed under the terms of your choice, to produce an
executable, and to copy and distribute the resulting executable under
the terms of your choice. However, the executable must be accompanied
by a prominent notice offering all users of the executable the entire
source code to this application, excluding the source code of the
independent modules, but including any changes you have made to this
application, under the terms of this license.
Conclusion
As I pointed out above I'm not a lawyer, but I would say that you can potentially, ideally dynamically, link Qt with a GPLv3+Exception and LGPLv3 license against your proprietary application without any problem as long as you fulfill the (L)GPLv3 requirements and your Open Source License Compliance obligations.
Let's assume you manage to create an image without (L)GPLv3 components suitable for your product. Let's also assume you wanted to add Qt without a commercial Qt license. Qt will add (L)GPLv3 components, hence forget about Tivoization/Patent retaliation/DRM.
In other words if you want Qt but also Tivoization/Patent retaliation/DRM in your product you need at least a commercial Qt license.
Comments
Post a Comment