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

As I already mentioned in part one of this series the Qt company pissed off OE/Yocto project maintainers and contributors. The story goes on.
Here[0] you can see that the Qt Comany informed both the KDE e.V. board and the KDE Free QT Foundation "that the economic outlook caused by the Corona virus puts more pressure on them to increase short-term revenue. As a result, they are thinking about restricting ALL Qt releases to paid license holders for the first 12 months. They are aware that this would mean the end of contributions via Open Governance in practice."
 
[0] https://lwn.net/Articles/817129/   

Qt commercial license cost

  • Start-ups and indie developers pay $499 per year (restricted to companies with an annual revenue or funding below $100.000 and fewer than five employees).[1] 
  • 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

[2] https://forum.qt.io/topic/117551/is-distribution-licensing-cost-really-that-huge-for-low-volume-embedded-devices

Qt software license(s)

I will cite/copy/add/remove to stuff from here.[2][3]

[2] https://forum.qt.io/topic/117551/is-distribution-licensing-cost-really-that-huge-for-low-volume-embedded-devices 

[3] https://cdn2.hubspot.net/hubfs/149513/India%20Marketing%20Assets/webinar%20recording/202005-Qt%20Virtual%20Tech%20Conf_Qt%20Licensing%20Explained.pdf 

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.
[4] https://www.gnu.org/licenses/gpl-3.0.en.html

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
But they don't seem to be in the image since I can't find them in 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.

Let's BitBake 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
 
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/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
 
like before: 
  • readline
  • gdbm
  • xz
  • bash
 but also:
  • 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
If we look into e.g. the qtbase_git.bb recipe the LICENSE field does not show quite an "or", but
 
LICENSE = "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

Popular posts from this blog

Yocto: BitBake and Dependencies - e.g. One recipe to use output of another recipe

Yocto: kernel modules not showing up in the rootfs