Yocto/Qt5: hello-qt part1 - Community/Wrapper/Image Size

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.


Community not valued by the Qt Company

Qt 5 was officially released on 19 December 2012 and on 31 August 2020 was the Qt 6 feature freeze so one would think the community prepares meta-qt6.

But the Qt Company sufficiently pissed off well known and respected community members and contributors to meta-qt5[1] so that it does not look like there will be community support for Qt 6 any time soon.

[1] meta-qt5 is a community project outside of The Qt Company and it's a lot more stable and easier to maintain then the Qt 5 layer from Qt.

The Qt Company decided to make their own meta-qt6 layer, but there are some concerns from the community: "The Qt policy for the layer changes is not well aligned with the way we usually maintain Yocto Project layers. We denied some of the changes they tried to do in the past and I always prefer when this kind of key component is maintained in a more neutral way.

Maintaining Qt is time-consuming and Martin has done a great job. If Qt is willing to do it, it is good but it'd be nice if it respects the good practices. I am a little concerned since Qt last tentative of closing source." 

Let me add to this that the Qt Company has quite interesting ideas about  licensing fees of their stuff as well as source code licensing, but this will be discussed in another blog post.

One wrapper to rule them all

"One framework. One codebase. Any platform."

This is the first thing you read on the Qt website. In my humble opinion every operating system has it's own philosophy and patterns and Qt (plus some others) try to sell us that it's possible to have "one for all". "Qt is the fastest and smartest way to produce industry-leading software that users love." Here is my definition of a wrapper: "The least optimal subset of features available to all supported operating systems used in the least optimal way."

I remember a project where we had to support various operating systems (including Linux) and decided to write our own POSIX wrapper for it. Eventually all the other operating systems except for Linux went away but we never dared to rewrite the sub-optimal code (least optimal subset of features used in the least optimal way) for Linux only.

I also remember a consulting gig at some customer where they wanted to port their Embedded Windoze stuff to Embedded Linux. In Windoze there are messages flying around everywhere and the API is similar to a Unix/Linux message queue, but for the Unix/Linux person it's like using a message queue for every event and bolting on extra stuff because it does not quite work like that. I would redesign it for Linux.

Still want to use Qt?

hello-qt

Let's say we wanted to run a minimal hello-qt application. No GUI just "Hello, Qt!". Something like that:

#include <QTextStream>

int main()
{
        QTextStream(stdout) << "Hello, Qt!" << Qt::endl;
        return 0;
}

You can find more about it here.

core-image-minimal-qt5.bb

The image recipe looks like this:

# Copyright (C) 2020 Robert Berger <robert.berger@ReliableEmbeddedSystems.com>
# Released under the MIT license (see COPYING.MIT for the terms)

require recipes-core/images/common-img.inc
require recipes-core/images/core-image-minimal.bb

# qt support in SDK
inherit populate_sdk_qt5

IMAGE_INSTALL += "\
                  dropbear \
                  udev-extraconf \
"

# let's include a few qt components
IMAGE_INSTALL += "\
                  qtbase \
                  qtserialport \
                  hello-qt \
"
# this is a pure qt5 embedded demo image without X
CONFLICT_DISTRO_FEATURES = "x11 wayland"

site.conf

I typically turn on buildhistory. You will see later why.

An excerpt of my site.conf looks like this:

PRSERV_HOST = "localhost:0"

# It is recommended to activate "buildhistory" for testing the PR service
# it also looks like with PR service + buildhistory packages are versioned
# automatically if we change meta data
INHERIT += "buildhistory"
BUILDHISTORY_COMMIT = "1"

buildhistory.bbclass

The buildhistory class records a history of build output metadata, which can be used to detect possible regressions as well as used for analysis of the build output. For more information on using Build History, see the "Maintaining Build Output Quality" section in the Yocto Project Development Tasks Manual.

local.conf

Recent Yocto versions enable ptests in the poky distro by default, which pulls in GPL-3.0 components and increases the image size. Let's remove those.

An excerpt of my local.conf looks like this:

### --> remove ptest

# remove some test cases and GPL-3.0 dependencies
# Impact of ptest feature is now more significant
# The Poky distribution configuration (DISTRO = "poky") enables ptests by default 
# to enable runtime testing of various components. In this release, a dependency 
# needed to be added that has resulted in a significant increase in the number of 
# components that will be built just when building a simple image such as core-image-minimal. 
# If you do not need runtime tests enabled for core components, then it is recommended that 
# you remove "ptest" from DISTRO_FEATURES to save a significant amount of build time 
# e.g. by adding the following in your configuration:
DISTRO_FEATURES_remove = "ptest" 
 
# <-- remove ptest

Another excerpt, which adds license compliance stuff to the image is here:

# include license text in image
COPY_LIC_MANIFEST = "1"
COPY_LIC_DIRS = "1"

Image size

core-image-minimal

Let's BitBake a 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: 46873, PID: 981784
Loading cache: 100% |#########################################################################################################################################| Time: 0:00:00
Loaded 3375 entries from dependency cache.
Parsing recipes: 100% |#######################################################################################################################################| Time: 0:00:01
Parsing of 2266 .bb files complete (2264 cached, 2 parsed). 3377 targets, 141 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      = "universal"
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 2 Found 0 Missed 2 Current 716 (0% match, 99% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 1920 tasks of which 1913 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 1 seconds

Let's see the image size:

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal/image-info.txt 
DISTRO = resy
DISTRO_VERSION = 3.1.2
USER_CLASSES = buildstats image-mklibs image-prelink
IMAGE_CLASSES = license_image
IMAGE_FEATURES = debug-tweaks
IMAGE_LINGUAS = 
IMAGE_INSTALL = packagegroup-core-boot
BAD_RECOMMENDATIONS = 
NO_RECOMMENDATIONS = 
PACKAGE_EXCLUDE = 
ROOTFS_POSTPROCESS_COMMAND = write_package_manifest; license_create_manifest;   ssh_allow_empty_password;  ssh_allow_root_login;  postinst_enable_logging;  rootfs_update_timestamp ;   write_image_test_data ;   empty_var_volatile; sort_passwd; rootfs_reproducible;
IMAGE_POSTPROCESS_COMMAND =  buildhistory_get_imageinfo ;
IMAGESIZE = 66216

core-image-minimal-qt5

Let's BitBake a 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: 45129, PID: 992954
Loading cache: 100% |#########################################################################################################################################| Time: 0:00:00
Loaded 3375 entries from dependency cache.
Parsing recipes: 100% |#######################################################################################################################################| Time: 0:00:01
Parsing of 2266 .bb files complete (2264 cached, 2 parsed). 3377 targets, 141 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      = "universal"
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 0 Found 0 Missed 0 Current 1142 (0% match, 100% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 2842 tasks of which 2842 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 1 seconds

 Let's see the image size:

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/image-info.txt 
DISTRO = resy
DISTRO_VERSION = 3.1.2
USER_CLASSES = buildstats image-mklibs image-prelink
IMAGE_CLASSES = license_image
IMAGE_FEATURES = debug-tweaks
IMAGE_LINGUAS = 
IMAGE_INSTALL = packagegroup-core-boot dropbear udev-extraconf qtbase qtserialport hello-qt
BAD_RECOMMENDATIONS = 
NO_RECOMMENDATIONS = 
PACKAGE_EXCLUDE = 
ROOTFS_POSTPROCESS_COMMAND = write_package_manifest; license_create_manifest;   ssh_allow_empty_password;  ssh_allow_root_login;  postinst_enable_logging;  rootfs_update_timestamp ;   write_image_test_data ;   empty_var_volatile; sort_passwd; rootfs_reproducible;
IMAGE_POSTPROCESS_COMMAND =  buildhistory_get_imageinfo ;
IMAGESIZE = 115496

This means the image size grew from 66216 to 115496 which is a 74% increase.

Some guilty Qt libraries:

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/files-in-image.txt | grep libQt | sort -r -n -k4
-rwxr-xr-x root       root          4672392 ./usr/lib/libQt5Core.so.5.14.2
-rwxr-xr-x root       root          4523576 ./usr/lib/libQt5Widgets.so.5.14.2
-rwxr-xr-x root       root          4489300 ./usr/lib/libQt5Gui.so.5.14.2
-rwxr-xr-x root       root          1267084 ./usr/lib/libQt5Network.so.5.14.2
-rwxr-xr-x root       root           841944 ./usr/lib/libQt5XcbQpa.so.5.14.2
-rwxr-xr-x root       root           435568 ./usr/lib/libQt5DBus.so.5.14.2
-rwxr-xr-x root       root           288100 ./usr/lib/libQt5PrintSupport.so.5.14.2
-rwxr-xr-x root       root           243188 ./usr/lib/libQt5Test.so.5.14.2
-rwxr-xr-x root       root           238952 ./usr/lib/libQt5OpenGL.so.5.14.2
-rwxr-xr-x root       root           214364 ./usr/lib/libQt5Sql.so.5.14.2
-rwxr-xr-x root       root           169304 ./usr/lib/libQt5Xml.so.5.14.2
-rwxr-xr-x root       root            71008 ./usr/lib/libQt5SerialPort.so.5.14.2
-rwxr-xr-x root       root            17860 ./usr/lib/libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               28 ./usr/lib/libQt5PrintSupport.so.5 -> libQt5PrintSupport.so.5.14.2
lrwxrwxrwx root       root               28 ./usr/lib/libQt5PrintSupport.so.5.14 -> libQt5PrintSupport.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5SerialPort.so.5 -> libQt5SerialPort.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5SerialPort.so.5.14 -> libQt5SerialPort.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt# include license text in image
COPY_LIC_MANIFEST = "1"
COPY_LIC_DIRS = "1"
5Concurrent.so.5 -> libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5Concurrent.so.5.14 -> libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Widgets.so.5 -> libQt5Widgets.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Widgets.so.5.14 -> libQt5Widgets.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Network.so.5 -> libQt5Network.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Network.so.5.14 -> libQt5Network.so.5.14.2
lrwxrwxrwx root       root               22 ./usr/lib/libQt5XcbQpa.so.5 -> libQt5XcbQpa.so.5.14.2
lrwxrwxrwx root       root               22 ./usr/lib/libQt5XcbQpa.so.5.14 -> libQt5XcbQpa.so.5.14.2
lrwxrwxrwx root       root               22 ./usr/lib/libQt5OpenGL.so.5 -> libQt5OpenGL.so.5.14.2
lrwxrwxrwx root       root               22 ./usr/lib/libQt5OpenGL.so.5.14 -> libQt5OpenGL.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Test.so.5 -> libQt5Test.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Test.so.5.14 -> libQt5Test.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5DBus.so.5 -> libQt5DBus.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5DBus.so.5.14 -> libQt5DBus.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Core.so.5 -> libQt5Core.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Core.so.5.14 -> libQt5Core.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Xml.so.5 -> libQt5Xml.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Xml.so.5.14 -> libQt5Xml.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Sql.so.5 -> libQt5Sql.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Sql.so.5.14 -> libQt5Sql.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Gui.so.5 -> libQt5Gui.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Gui.so.5.14 -> libQt5Gui.so.5.14.2

License Compliance artifacts plus a few libs and executables coming from Qt:

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/files-in-image.txt | grep qt | sort -r -n -k4 | more
-rw-r--r-- root       root            79543 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.QT-LICENSE-AGREEMENT
-rw-r--r-- root       root            79543 ./usr/share/common-licenses/qtbase-plugins/LICENSE.QT-LICENSE-AGREEMENT
-rw-r--r-- root       root            79543 ./usr/share/common-licenses/qtbase/LICENSE.QT-LICENSE-AGREEMENT
-rwxr-xr-x root       root            42328 ./usr/lib/plugins/generic/libqtuiotouchplugin.so
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtserialport-qmlplugins/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtserialport-plugins/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtserialport/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtbase-plugins/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            36363 ./usr/share/common-licenses/qtbase/LICENSE.GPL3-EXCEPT
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtserialport-qmlplugins/LICENSE.GPL3
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtserialport-plugins/LICENSE.GPL3
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtserialport/LICENSE.GPL3
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.GPL3
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtbase-plugins/LICENSE.GPL3
-rw-r--r-- root       root            35147 ./usr/share/common-licenses/qtbase/LICENSE.GPL3
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtserialport-qmlplugins/LICENSE.FDL
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtserialport-plugins/LICENSE.FDL
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtserialport/LICENSE.FDL
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.FDL
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtbase-plugins/LICENSE.FDL
-rw-r--r-- root       root            22961 ./usr/share/common-licenses/qtbase/LICENSE.FDL
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtserialport-qmlplugins/LICENSE.GPL2
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtserialport-plugins/LICENSE.GPL2
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtserialport/LICENSE.GPL2
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.GPL2
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtbase-plugins/LICENSE.GPL2
-rw-r--r-- root       root            18092 ./usr/share/common-licenses/qtbase/LICENSE.GPL2
-rw-r--r-- root       root            18032 ./usr/share/common-licenses/hello-qt/LICENSE
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtserialport-qmlplugins/LICENSE.LGPL3
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtserialport-plugins/LICENSE.LGPL3
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtserialport/LICENSE.LGPL3
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtbase-qmlplugins/LICENSE.LGPL3
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtbase-plugins/LICENSE.LGPL3
-rw-r--r-- root       root             7651 ./usr/share/common-licenses/qtbase/LICENSE.LGPL3
-rwxr-xr-x root       root             5556 ./usr/bin/hello-qt
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtserialport-qmlplugins
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtserialport-plugins
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtserialport
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtbase-qmlplugins
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtbase-plugins
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/qtbase
drwxr-xr-x root       root             4096 ./usr/share/common-licenses/hello-qt
-rw-r--r-- root       root             3253 ./usr/share/mime/text/vnd.qt.linguist.xml
-rw-r--r-- root       root             2458 ./usr/share/mime/application/x-qtiplot.xml
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtserialport/recipeinfo
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtserialport-qmlplugins/recipeinfo
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtserialport-plugins/recipeinfo
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtbase/recipeinfo
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtbase-qmlplugins/recipeinfo
-rw-r--r-- root       root              195 ./usr/share/common-licenses/qtbase-plugins/recipeinfo
-rw-r--r-- root       root               54 ./usr/share/common-licenses/hello-qt/recipeinfo
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Exc
eption-1.0
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtserialport-plugins/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Except
ion-1.0
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtserialport/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Exception-1.0
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtbase-qmlplugins/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Exception
-1.0
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtbase-plugins/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Exception-1.
0
lrwxrwxrwx root       root               43 ./usr/share/common-licenses/qtbase/generic_The-Qt-Company-GPL-Exception-1.0 -> ../generic_The-Qt-Company-GPL-Exception-1.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport-plugins/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport-plugins/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtserialport/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase-qmlplugins/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase-qmlplugins/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase-plugins/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase-plugins/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase/generic_LGPL-3.0 -> ../generic_LGPL-3.0
lrwxrwxrwx root       root               19 ./usr/share/common-licenses/qtbase/generic_GFDL-1.3 -> ../generic_GFDL-1.3
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport-plugins/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport-plugins/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtserialport/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase-qmlplugins/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase-qmlplugins/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase-plugins/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase-plugins/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase/generic_GPL-3.0 -> ../generic_GPL-3.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/qtbase/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               18 ./usr/share/common-licenses/hello-qt/generic_GPL-2.0 -> ../generic_GPL-2.0
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtserialport-qmlplugins/generic_BSD -> ../generic_BSD
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtserialport-plugins/generic_BSD -> ../generic_BSD
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtserialport/generic_BSD -> ../generic_BSD
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtbase-qmlplugins/generic_BSD -> ../generic_BSD
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtbase-plugins/generic_BSD -> ../generic_BSD
lrwxrwxrwx root       root               14 ./usr/share/common-licenses/qtbase/generic_BSD -> ../generic_BSD

Attempt to decrease image size

PACKAGECONFIG

This variable provides a means of enabling or disabling features of a recipe on a per-recipe basis. PACKAGECONFIG blocks are defined in recipes when you specify features and then arguments that define feature behaviors. Here is the basic block structure (broken over multiple lines for readability):

     PACKAGECONFIG ??= "f1 f2 f3 ..."
     PACKAGECONFIG[f1] = "\
                          --with-f1, \
                          --without-f1, \
                          build-deps-for-f1, \
                          runtime-deps-for-f1, \
                          runtime-recommends-for-f1, \
                          packageconfig-conflicts-for-f1 \
                          "
     PACKAGECONFIG[f2] = "\
                         ... and so on and so on ...
                    

The PACKAGECONFIG variable itself specifies a space-separated list of the features to enable. Following the features, you can determine the behavior of each feature by providing up to six order-dependent arguments, which are separated by commas. You can omit any argument you like but must retain the separating commas. The order is important and specifies the following:

  1. Extra arguments that should be added to the configure script argument list (EXTRA_OECONF or PACKAGECONFIG_CONFARGS) if the feature is enabled.

  2. Extra arguments that should be added to EXTRA_OECONF or PACKAGECONFIG_CONFARGS if the feature is disabled.

  3. Additional build dependencies (DEPENDS) that should be added if the feature is enabled.

  4. Additional runtime dependencies (RDEPENDS) that should be added if the feature is enabled.

  5. Additional runtime recommendations (RRECOMMENDS) that should be added if the feature is enabled.

  6. Any conflicting (that is, mutually exclusive) PACKAGECONFIG settings for this feature.

Consider the following PACKAGECONFIG block taken from the librsvg recipe. In this example the feature is gtk, which has three arguments that determine the feature's behavior.

     PACKAGECONFIG[gtk] = "--with-gtk3,--without-gtk3,gtk+3"
                    

The --with-gtk3 and gtk+3 arguments apply only if the feature is enabled. In this case, --with-gtk3 is added to the configure script argument list and gtk+3 is added to DEPENDS. On the other hand, if the feature is disabled say through a .bbappend file in another layer, then the second argument --without-gtk3 is added to the configure script instead.

The basic PACKAGECONFIG structure previously described holds true regardless of whether you are creating a block or changing a block. When creating a block, use the structure inside your recipe.

If you want to change an existing PACKAGECONFIG block, you can do so one of two ways:

  • Append file: Create an append file named recipename.bbappend in your layer and override the value of PACKAGECONFIG. You can either completely override the variable:

          PACKAGECONFIG = "f4 f5"
                                

    Or, you can just append the variable:

         PACKAGECONFIG_append = " f4"
                                
  • Configuration file: This method is identical to changing the block through an append file except you edit your local.conf or mydistro.conf file. As with append files previously described, you can either completely override the variable:

         PACKAGECONFIG_pn-recipename = "f4 f5"
                                

    Or, you can just amend the variable:

         PACKAGECONFIG_append_pn-recipename = " f4"
                                

local.conf

Qt tends to pull in lots of stuff via PACKAGECONFIG, so let's try to remove a couple of things globally.

An excerpt of my local.conf looks like this:

### --> qt-5 remove stuff

DISTRO_FEATURES_remove = "wayland"
DISTRO_FEATURES_remove = "vulkan"
DISTRO_FEATURES_remove = "x11"
DISTRO_FEATURES_remove = "opengl"

DISTRO_FEATURES_remove = "alsa"
DISTRO_FEATURES_remove = "pulseaudio"
DISTRO_FEATURES_remove = "gobject-introspection-data"
DISTRO_FEATURES_remove = "3g"
DISTRO_FEATURES_remove = "nfc"

### <-- qt-5 remove stuff

qtbase_git.bbappend

I created a meta-qt5-examples layer, which contains, among other things, a qtbase_git.bbappend file where I'll try to remove more things via PACKAGECONFIG

An excerpt of my meta-qt5-examples/recipes-qt/qt5/qtbase_git.bbappend looks like this:

# Things we don't use:
# PACKAGECONFIG_DEFAULT="accessibility udev evdev widgets tools libs freetype tests pcre"
 
PACKAGECONFIG_DEFAULT_remove = "accessibility"
PACKAGECONFIG_DEFAULT_remove = "dbus"
PACKAGECONFIG_DEFAULT_remove = "tests"
PACKAGECONFIG_DEFAULT_remove = "widgets"

# PACKAGECONFIG="release accessibility udev evdev tools libs freetype  pcre openssl no-opengl jpeg libpng zlib"
# we could remove a few more here
 
You might wonder how I got the values of PACKAGECONFIG_DEFAULT and PACKAGECONFIG for qtbase. That's how it looks like after the changes from above:

pokyuser@200239fdab09:/workdir/build/multi-v7-ml-qt5$ bitbake qtbase -e | grep ^PACKAGECONFIG_DEFAULT=
PACKAGECONFIG_DEFAULT="  udev evdev  tools libs freetype  pcre           "
pokyuser@200239fdab09:/workdir/build/multi-v7-ml-qt5$ bitbake qtbase -e | grep ^PACKAGECONFIG=
PACKAGECONFIG="     release       udev evdev  tools libs freetype  pcre                openssl     no-opengl                         jpeg libpng zlib      "

core-image-minimal-qt5 - Second attempt

Let's BitBake a 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: 44461, PID: 1007916
Loading cache: 100% |#########################################################################################################################################| Time: 0:00:00
Loaded 3375 entries from dependency cache.
Parsing recipes: 100% |#######################################################################################################################################| Time: 0:00:01
Parsing of 2266 .bb files complete (2264 cached, 2 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      = "universal"
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 5 Found 5 Missed 0 Current 805 (100% match, 100% complete)
NOTE: Executing Tasks
NOTE: Tasks Summary: Attempted 2131 tasks of which 2131 didn't need to be rerun and all succeeded.
NOTE: Writing buildhistory
NOTE: Writing buildhistory took: 1 seconds

Let's see the image size:

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/image-info.txt 
DISTRO = resy
DISTRO_VERSION = 3.1.2
USER_CLASSES = buildstats image-mklibs image-prelink
IMAGE_CLASSES = license_image
IMAGE_FEATURES = debug-tweaks
IMAGE_LINGUAS = 
IMAGE_INSTALL = packagegroup-core-boot dropbear udev-extraconf qtbase qtserialport hello-qt
BAD_RECOMMENDATIONS = 
NO_RECOMMENDATIONS = 
PACKAGE_EXCLUDE = 
ROOTFS_POSTPROCESS_COMMAND = write_package_manifest; license_create_manifest;   ssh_allow_empty_password;  ssh_allow_root_login;  postinst_enable_logging;  rootfs_update_timestamp ;   write_image_test_data ;   empty_var_volatile; sort_passwd; rootfs_reproducible;
IMAGE_POSTPROCESS_COMMAND =  buildhistory_get_imageinfo ;
IMAGESIZE = 82752

This means the image size grew from 66216 to 82752 which is a 25% increase and a decrease of 28% compared to 115496 which we had before.

Some guilty Qt libraries (less then before):

$ cat buildhistory/images/multi_v7_ml/glibc/core-image-minimal-qt5/files-in-image.txt | grep libQt | sort -r -n -k4
-rwxr-xr-x root       root          4664104 ./usr/lib/libQt5Core.so.5.14.2
-rwxr-xr-x root       root          3895380 ./usr/lib/libQt5Gui.so.5.14.2
-rwxr-xr-x root       root          1267084 ./usr/lib/libQt5Network.so.5.14.2
-rwxr-xr-x root       root           243188 ./usr/lib/libQt5Test.so.5.14.2
-rwxr-xr-x root       root           214364 ./usr/lib/libQt5Sql.so.5.14.2
-rwxr-xr-x root       root           169304 ./usr/lib/libQt5Xml.so.5.14.2
-rwxr-xr-x root       root            71008 ./usr/lib/libQt5SerialPort.so.5.14.2
-rwxr-xr-x root       root            17860 ./usr/lib/libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5SerialPort.so.5 -> libQt5SerialPort.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5SerialPort.so.5.14 -> libQt5SerialPort.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5Concurrent.so.5 -> libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               26 ./usr/lib/libQt5Concurrent.so.5.14 -> libQt5Concurrent.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Network.so.5 -> libQt5Network.so.5.14.2
lrwxrwxrwx root       root               23 ./usr/lib/libQt5Network.so.5.14 -> libQt5Network.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Test.so.5 -> libQt5Test.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Test.so.5.14 -> libQt5Test.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Core.so.5 -> libQt5Core.so.5.14.2
lrwxrwxrwx root       root               20 ./usr/lib/libQt5Core.so.5.14 -> libQt5Core.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Xml.so.5 -> libQt5Xml.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Xml.so.5.14 -> libQt5Xml.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Sql.so.5 -> libQt5Sql.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Sql.so.5.14 -> libQt5Sql.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Gui.so.5 -> libQt5Gui.so.5.14.2
lrwxrwxrwx root       root               19 ./usr/lib/libQt5Gui.so.5.14 -> libQt5Gui.so.5.14.2

Conclusion

If you really want to use Qt and keep your image small you should definitly have a look at PACKAGECONFIG and how it works. And even if you don't use Qt it's a good idea to learn how to use PACKAGECONFIG.

Part two is here.

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

Yocto/Qt5: hello-qt part2 - Licensing