May 29, 2020 Open Source

Developing Qt5 applications natively on Wind River Linux

By Nathan Hartman

nathan_hartman-headshot-small

Introduction

Wind River Linux provides the technologies essential to building a flexible, stable, and secure platform for your embedded devices.

Based on OpenEmbedded releases from the Yocto Project, it is designed to let you customize your platform to include only the packages and features you need. Powered by bitbake, it provides the ability to build an entire Linux distribution from source by following repeatable recipes. This is really powerful, but can be foreign to application developers that already have a workflow they are comfortable with.

Developers building graphical user interfaces (GUI) have their own set of tools that they rely on. Often they prefer to use an Integrated Development Environment (IDE) tailored to the language and frameworks they are working with. Typically this IDE and the tools it uses are running natively on the same platform they are building for.

Fortunately, these developers can still do this on Wind River Linux. This tutorial describes building Wind River Linux with the GCC toolchain and Qt Creator included to enable native application development.

Requirements

Building the entire platform has a few simple requirements to get started. Many Linux distributions are self-hosted meaning you can only build the next version of the distribution with the previous release.

Wind River Linux supports a wide variety of hosts. The official supported list of hosts is below, but many newer releases have been tested and known to work.

Supported Distribution for Wind River Linux LTS 19:

  • CentOS 7.6
  • Fedora 30
  • openSUSE Leap 15
  • Red Hat Enterprise Linux 7.6 and 8.0
  • SUSE Linux Enterprise Desktop 15
  • Ubuntu Desktop 16.04 and 18.04 LTS

For details on necessary Linux Host System Libraries and Executables please refer to the documentation.

For example, on Ubuntu systems the following packages must be installed:

$ sudo apt install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping libsdl1.2-dev xterm file git bmap-tools coreutils parted e2fsprogs

In addition, the deployment steps require root or sudo access for deploying to an SD Card or USB flash device.

Lastly, this tutorial has been validated for the Raspberry Pi 4 and Intel NUC devices (NUC5i3MYBE, NUC6i7KYK, NUC7i5DNK). These instructions should work on other devices, however we tested these devices specifically to ensure that the hardware acceleration was enabled for top performance.

Cloning the Wind River Linux repository

The first step is to clone the Wind River Linux GitHub repository.

  1. Create a directory for the tools needed to create the Wind River Linux image. This will be referred to as the parent directory from this point onwards:

    $ mkdir wrlinux_qt
    $ cd wrlinux_qt
    
  2. In a Linux terminal, clone the repository into your build folder with the following command:

    $ git clone https://github.com/WindRiver-Labs/wrlinux-x.git
    

    Note: A clone of wrlinux-x defaults to the WRLINUX_10_19_BASE branch with the latest update tagged. WRLINUX_10_19_BASE_UPDATE0003 or greater is required for the Raspberry Pi 4 BSP. This tutorial was written using WRLINUX_10_19_BASE_UPDATE0007.

Configure the build for your device

This section describes the usage of the Wind River setup.sh tool for easy configuration of the build. We will use it to specify the target board, download the layers required, and pre-populate the configuration file.

  1. In the parent directory that wrlinux-x was cloned into (wrlinux_qt), run the setup.sh script. Accept the End User License Agreement (EULA).

    For Raspberry Pi 4 use:

    $ ./wrlinux-x/setup.sh --machine bcm-2xxx-rpi4 --dl-layers
    

    For an Intel NUC use:

    $ ./wrlinux-x/setup.sh --machine intel-x86-64 --dl-layers
    

    Note: The --machine flag specifies that it should include the board support package for your device, the --dl-layers flag downloads the package source now instead of later at build time.

    After some time, you will see:

    Fetching projects: 100% (16/16), done.
    Syncing work tree: 100% (16/16), done.
    

    At which point the following files and directories should have been generated:

    $ ls -al
    total 64
    drwxr-xr-x  8 nhartman users 4096 May 25 16:53 .
    drwxr-xr-x  3 nhartman users 4096 May 25 15:44 ..
    drwxr-xr-x  5 nhartman users 4096 May 25 16:53 bin
    lrwxrwxrwx  1 nhartman users   22 May 25 16:53 bitbake -> layers/oe-core/bitbake
    drwxr-xr-x  5 nhartman users 4096 May 25 16:42 config
    -rw-r--r--  1 nhartman users 2279 May 25 16:42 default.xml
    lrwxrwxrwx  1 nhartman users   89 May 25 16:42 environment-setup-x86_64-wrlinuxsdk-linux -> /home/nhartman/wrlinux_qt/bin/buildtools/environment-setup-x86_64-wrlinuxsdk-linux
    drwxr-xr-x  8 nhartman users 4096 May 25 16:53 .git
    -rw-r--r--  1 nhartman users  111 May 25 16:42 .gitconfig
    -rw-r--r--  1 nhartman users  147 May 25 16:42 .gitignore
    -rw-r--r--  1 nhartman users   61 May 25 16:42 .gitmodules
    drwxr-xr-x 16 nhartman users 4096 May 25 16:53 layers
    lrwxrwxrwx  1 nhartman users   19 May 25 16:53 meta -> layers/oe-core/meta
    lrwxrwxrwx  1 nhartman users   32 May 25 16:53 oe-init-build-env -> layers/oe-core/oe-init-build-env
    -rw-r--r--  1 nhartman users 2882 May 25 16:42 README
    drwxr-xr-x  7 nhartman users 4096 May 25 16:53 .repo
    -rw-r--r--  1 nhartman users  205 May 25 16:42 .repo_.gitconfig.json
    lrwxrwxrwx  1 nhartman users   22 May 25 16:53 scripts -> layers/oe-core/scripts
    -rw-r--r--  1 nhartman users   73 May 25 16:42 .templateconf
    drwxr-xr-x  5 nhartman users 4096 May 25 13:53 wrlinux-x
    
  2. Run the environment setup scripts that were generated in the parent directory. They will create and change to the build sub-directory.

    $ . ./environment-setup-x86_64-wrlinuxsdk-linux
    $ . ./oe-init-build-env
    
    You had no conf/local.conf file. This configuration file has therefore been
    created for you with some default values. You may wish to edit it to, for
    example, select a different MACHINE (target hardware). See conf/local.conf
    for more information as common configuration options are commented.
    
    You had no conf/bblayers.conf file. This configuration file has therefore been
    created for you with some default values. To add additional metadata layers
    into your configuration please add entries to conf/bblayers.conf.
    
    The Yocto Project has extensive documentation about OE including a reference
    manual which can be found at:
        http://yoctoproject.org/documentation
    
    For more information about OpenEmbedded see their website:
        http://www.openembedded.org/
    
    This project was configured with the following options:
        --machine bcm-2xxx-rpi4 --dl-layers
    
    Common Wind River images are:
        wrlinux-image-small     (suggests distro: wrlinux and feature/busybox)
        wrlinux-image-core      (suggests distro: wrlinux)
        wrlinux-image-std       (suggests distro: wrlinux)
        wrlinux-image-std-sato  (requires distro: wrlinux-graphics)
    
    Common Yocto Project images, typically built with distro poky, are:
        core-image-minimal
        core-image-base
        core-image-sato
    
    You can also run generated qemu images with a command like 'runqemu qemux86-64'
    

    These scripts will set environment variables for the build tool as well as generate some pre-built configuration files.

    Note: If you have previously built an image, running these scripts will not overwrite your existing configurations. Rename, move or delete previous configuration files to ensure the correct configuration files are generated.

Patching the project directories

This section describes how to add the required template files using git.

  1. Clone the meta-qt5 and the meta-qt5-extra repositories in a my-layers directory

    $ mkdir my-layers
    $ git clone -b zeus https://github.com/meta-qt5/meta-qt5.git my-layers/meta-qt5
    $ git clone -b zeus https://github.com/schnitzeltony/meta-qt5-extra.git my-layers/meta-qt5-extra
    
  2. Download the required patches listed below into the wrlinux_qt/build directory:

    Credit goes to my colleague, Quanyang Wang, for creating the patches to integrate LxQt desktop on Wind River Linux.

  3. In the meta-qt5-extra directory, apply the first patch:

    $ cd my-layers/meta-qt5-extra
    $ git am ../../0001-polkit-qt-1-fix-compile-error.patch
    $ cd $BUILDDIR
    
  4. In the wrlinux layer directory, apply the wrlinux patches:

    $ cd ../layers/wrlinux
    $ git am ../../0001-wrlinux-template-add-template-qt5-for-wrlinux.patch
    $ git am ../../0002-wrlinux-template-add-lxqt-support-for-wrlinux.patch
    $ cd $BUILDDIR
    

Adding the Qt5 layer, GCC toolchain, and desktop environment

This section describes how to clone the meta-qt5 and meta-qt5-extra layer repositories. In addition, how to add the layers, GCC toolchain and desktop environment to the image.

  1. Using the bitbake-layers tool, add the layers to the conf/bblayers.conf file. This allow bitbake to locate the custom layer when building the image. In addition, if using a Raspberry Pi add the Raspberry Pi Graphics layer to enable hardware acceleration.

    $ bitbake-layers add-layer my-layers/meta-qt5
    $ bitbake-layers add-layer my-layers/meta-qt5-extra
    

    If building for the Raspberry Pi, add in addition for hardware acceleration:

    $ bitbake-layers add-layer ../layers/bcm-2xxx-rpi/rpi-graphics/
    
  2. Edit conf/local.conf configuration file to add the GCC toolchain, packages required for Qt5 and the desktop environment. Append the following lines to the end of conf/local.conf:

    BB_NO_NETWORK = "0"
    BB_NUMBER_THREADS = "16"
    PARALLEL_MAKE = "-j 16" 
    WRTEMPLATE = "feature/qt5 feature/lxqt"
    IMAGE_INSTALL_append += "\
        packagegroup-core-buildessential \
        xserver-xorg \
        xserver-xorg-extension-glx \
        mesa \
        mesa-demos \
        openssh \
        git"
    DISTRO_FEATURES_append += " x11 opengl polkit"
    

    Note: this tutorial uses the LxQt desktop, but you may replace feature/lxqt with feature/xfce if you prefer to use the desktop featured with the Raspberry Pi Foundation images.

    If building for the Raspberry Pi, also add the following to enable hardware acceleration:

    LICENSE_FLAGS_WHITELIST = "commercial"
    
  3. If building for Raspberry Pi, edit ../layers/bcm-2xxx-rpi/recipes-bsp/boot-config/boot-config/cmdline.txt file to adjust the kernel parameters.

    $ cat ../layers/bcm-2xxx-rpi/recipes-bsp/boot-config/boot-config/cmdline.txt
    dwc_otg.lpm_enable=0 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait ip=dhcp
    $  echo 'dwc_otg.lpm_enable=0 console=tty root=/dev/mmcblk0p2 rootfstype=ext4 rootwait' > ../layers/bcm-2xxx-rpi/recipes-bsp/boot-config/boot-config/cmdline.txt
    

    Note: These changes ensure that the console output appears on the HDMI display and that the boot sequence doesn't wait for a DHCP connection.

Building the image

This section describes building the Wind River Linux image

  1. Build the image of your choice. As seen in the image in step 4, there are several suggested images. We will build wrlinux-image-std-sato, an image optimized for a desktop environment.

    $ bitbake wrlinux-image-std-sato
    Processing Wind River template files...
    Parsing recipes:    2% |#####
    

    After some time, you will see the following when the build is finished:

    Initialising tasks: 100% |######################################################################| Time: 0:00:07
    Sstate summary: Wanted 3536 Found 0 Missed 3536 Current 0 (0% match, 0% complete)
    NOTE: Executing Tasks
    NOTE: Setscene tasks completed
    
    NOTE: Tasks Summary: Attempted 4643 tasks of which 0 didn't need to be rerun and all succeeded.
    

Identifying your USB device

This section describes how to identify your USB SD Card adapter or USB flash drive using fdisk.

  1. Use the fdisk command to list the block devices detected by Linux:

    $ sudo fdisk -l
    
  2. Identify your device through the model name or capacity.

    Disk /dev/sdx: 7.43 GiB, 7969177600 bytes, 15564800 sectors
    Disk model: SD Card Reader
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x70e121a4
    
    Device    Boot  Start     End Sectors  Size Id Type
    /dev/sdx1 *      8192  532479  524288  256M  c W95 FAT32 (LBA)
    /dev/sdx2      532480 3133739 2601260  1.2G 83 Linux
    

    Note: In this case the device is '/dev/sdx' as seen by the capacity and 'Disk model'. The device name should take the format of '/dev/sdx' where x is a letter specific to your machine.

Flashing the image

This section describes how to write the generated .wic and .wic.bmap or .iso files to the SD card or USB flash drive.

For the Raspberry Pi 4:

  1. Locate the images generated by bitbake. Relative to the build directory, the image path is:

    tmp-glibc/deploy/images/bcm-2xxx-rpi4
    
  2. Specifically, we need the wrlinux-image-std-sato-bcm-2xxx-rpi4.wic and wrlinux-image-std-sato-bcm-2xxx-rpi4.wic.bmap files.

  3. Using bmaptool, flash the generated files to the usb device

    $ sudo bmaptool copy --bmap <PATH_TO_IMAGE>/IMAGE_NAME-bcm-2xxx-rpi4.wic.bmap <PATH_TO_IMAGE>/IMAGE_NAME-bcm-2xxx-rpi4.wic /dev/sdx
    
  4. After up to several minutes (depending on the speed of your USB device) you should see:

    $ sudo bmaptool copy --bmap wrlinux-image-std-bcm-2xxx-rpi4.wic.bmap wrlinux-image-std-bcm-2xxx-rpi4.wic /dev/sdx
    [sudo] password for nhartman:
    bmaptool: info: block map format version 2.0
    bmaptool: info: 391718 blocks of size 4096 (1.5 GiB), mapped 247338 blocks (996.2 MiB or 63.1%)
    bmaptool: info: copying image 'wrlinux-image-std-bcm-2xxx-rpi4.wic' to block device '/dev/sdx using bmap file 'wrlinux-image-std-bcm-2xxx-rpi4.wic.bmap'
    bmaptool: info: 100% copied
    bmaptool: info: synchronizing '/dev/sdx'
    bmaptool: info: copying time: 43.7s, copying speed 22.1 MiB/sec
    

For the Intel NUC:

  1. Locate the images generated by bitbake. Relative to the build directory, the image path is:

    tmp-glibc/deploy/images/intel-x86-64
    
  2. Specifically, we need the wrlinux-image-std-sato-intel-x86-64.iso file.

  3. Flash your image using ‘dd’

    $ sudo dd if=PATH_TO_IMAGE/wrlinux-image-std-sato-intel-x86-64.hddimg of=/dev/sdx status=progress && sync
    

    In some cases, dd can appear to hang while writing from memory to the USB. Check the progress with:

    $ sudo cat /proc/meminfo | grep Dirty
    

    It should approach the low hundreds when the write is finished.

Resizing the root partition and filesystem

This section describes how to resize the root filesystem to take up the full capacity of the SD card. With the USB device inserted, run the following commands, replacing ‘/dev/sdx’ with your device.

  1. Resize the second partition to fill 100% of the storage device.
    $ sudo parted /dev/sdx resizepart 2 100%
    Information: You may need to update /etc/fstab.
    
  2. Run the EXT2/3/4 filesystem check tool on the second partition to fix any potential problems.
    $ sudo e2fsck -f /dev/sdx2
    e2fsck 1.45.3 (14-Jul-2019)
    Pass 1: Checking inodes, blocks, and sizes
    Pass 2: Checking directory structure
    Pass 3: Checking directory connectivity
    Pass 4: Checking reference counts
    Pass 5: Checking group summary information
    root: 52648/1796640 files (0.4% non-contiguous), 662799/3723264 blocks
    
  3. Resize the EXT4 filesystem with resize2fs to expand it and fill the entire partition.
    $ sudo resize2fs /dev/sdx2
    resize2fs 1.45.3 (14-Jul-2019)
    Resizing the filesystem on /dev/sdx2 to 373264 (4k) blocks.
    The filesystem on /dev/sdx2 is now 3723264 (4k) blocks long.
    

Results

For the LxQt desktop, the login and password are ‘wrluser’ and the $HOME directory is /home/wrluser.

After logging in you will be presented with the LxQt Desktop:

LxQt Desktop

Note: If you chose to use the the XFCE desktop, the login is ‘root’ with no password and the $HOME directory is /root.

Before running the examples

The sample applications come from Qt git repositories. Cloning the repositories requires that you have a working network connection. If for any reason your device didn't automatically get a dynamic IP address you may use the following commands to obtain one.

  1. Open QTerminal by clicking on the icon in the bottom left corner, then click System Tools > QTerminal.

    Open QTerminal

  2. In a QTerminal, execute the su command to become the root user.

  3. Then execute the "ip a" command to verify that your device has retrieved an IP address. Refer to the inet line under eth0 to see your IP address.

    ip a

  4. If you do not already have an IP address, then you may execute dhclient eth0 to request a dynamic IP address.

  5. Execute exit to stop running commands as the root user and become wrluser again.

Sample Application: glxgears

This section demonstrates the mesa-demos glxgears application.

  1. Open QTerminal by clicking on the icon in the bottom left corner, then click System Tools > QTerminal.

  2. Execute glxgears to try the OpenGL example. If the hardware acceleration is working, it should report around 60 frames per second on the Raspberry Pi 4.

    glxgears

Sample Application: OpenGLwindow

This section demonstrates an OpenGL example from the Qtbase repository.

  1. Use git to clone the repository containing the OpenGL examples

    $ git clone --depth 1 -b dev git://code.qt.io/qt/qtbase.git
    Cloning into 'qtbase'...
    remote: Counting objects: 23735, done.
    remote: Compressing objects: 100% (18386/18386), done.
    remote: Total 23735 (delta 5511), reused 16062 (delta 3270)
    Receiving objects: 100% (23735/23735), 63.00 MiB | 3.92 MiB/s, done.
    Resolving deltas: 100% (5511/5511), done.
    Updating files: 100% (23031/23031), done.
    
  2. Copy the examples folder out of the qtbase directory so that Qt Creator will let us build the project.

    $ cp -r qtbase/examples $HOME
    
  3. Launch Qt Creator from the GUI

    Launch Qt Creator

  4. Open the openglwindow.pro file by selecting File > Open File or Project from the menu.

    Open openglwindow.pro

  5. Navigate to $HOME/examples/opengl/openglwindow/openglwindow.pro. Then click, Open.

    Open openglwindow.pro

  6. Select "openglwindow" as the Active Project, then click the Configure Project button.

    Configure openglwindow project

  7. Build and run the application by clicking Build > Run in the menu.

  8. (Optional) You may click the "Compile Output" tab along the bottom to watch the toolchain output as the project builds.

    Build and run

  9. After a few moments the openglwindow should appear with a spinning rainbow triangle.

    OpenGL triangle

Sample Application: QtCluster

This section demonstrates the QtCluster example from the Qtbase docs repository.

  1. Open a terminal and clone the repository containing the Qt docs:

    git clone git://code.qt.io/qt/qtdoc.git --branch 5.10
    Cloning into 'qtdoc'...
    remote: Counting objects: 24976, done.
    remote: Comrpessing objects: 100% (12628/12628), done.
    remote: Total 24976 (delta 17217), reused 17635 (delta 11944)
    Receiving objects: 100% (24976/24976), 42.44 MiB | 6.23 MiB/s, done.
    Resolving deltas: 100% (17217/17217), done.
    
  2. Launch Qt Creator from the GUI

  3. Open the qtcluster-base.pro file by selecting File > Open File or Project from the menu.

  4. Navigate to $HOME/qtdoc/doc/src/snippets/qtcluster/qtcluster-base.pro. Then click, Open.

    OpenGL triangle

  5. Select qtcluster-base"* as the Active Project, then click the Configure Project button.

  6. Build and run the application by clicking Build > Run in the menu.

    Qt Cluster example

    Note: If the hardware acceleration is working, it should report around 60 frames per second on the Raspberry Pi 4.

Conclusions

Today's embedded devices are more powerful than ever before and capable of displaying beautiful graphical user interfaces. This allows GUI developers to work directly on the device in a way that may not have been possible before. By providing the tools on the embedded device with drivers for enabling hardware acceleration it helps make it easier to get started and accelerate development.

References

All product names, logos, and brands are property of their respective owners.
All company, product and service names used in this software are for identification purposes only. Wind River are registered trademarks of Wind River Systems.

Disclaimer of Warranty / No Support: Wind River does not provide support and maintenance services for this software, under Wind River’s standard Software Support and Maintenance Agreement or otherwise. Unless required by applicable law, Wind River provides the software (and each contributor provides its contribution) on an “AS IS” BASIS, WITHOUT WARRANTIES OF ANY KIND, either express or implied, including, without limitation, any warranties of TITLE, NONINFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the software and assume ay risks associated with your exercise of permissions under the license.

OpenGL is a registered trademark of Silicon Graphics, Inc. in the United States and other countries.

Qt is a registered trademark of The Qt Company Ltd in the United States and other countries.

Previous NVIDIA container runtime for Wind River Linux
Next Wind River Cloud Platform Honored as Bronze Stevie® Winner in 2020 American Business Awards®