Building Qt for PocketCHIP
The PocketCHIP is a device sold by Next Thing Co.(NTC) and is a hobbyist device similar to the Raspberry Pi. It features an Allwinner R8 SOC which contains both an Cortex-A8 CPU and Mali-400 GPU. The default image on the PocketCHIP has a Debian (jessie) userspace and a Linux(mainline) kernel. This guide intends to describe how it is possible to setup a development environment for the PocketCHIP, how to build and deploy Qt to the device, and how to setup the Qt Creator IDE to enable one-click deployment and debugging of Qt Applications.
The tutorial assumes you are using a modern Linux Desktop for your host system. It's ok to use VMWare or VirtualBox (I do).
The actual software environment on the device is basically already setup. If you install/update the factory image from NTC (via their online flasher), you will get a nice demo environment that serves as a great starting point. However you will need to install a few additional packages to the device to facilitate Qt application development. Connect the PocketCHIP to your WiFi network because we will primarily using SSH to deploy software to the device, and we will need a network connection to download additional Debian packages.
I also recommend getting a serial connection the the PocketCHIP as it is much easier to type in commands before you have an SSH connection to the device. You actually have a few options to get a serial console. First if you connect the PocketCHIP to your Linux host machine via the micro-usb outlet, you will see a new device which can given you serial access:
sudo minicom -D /dev/ttyACM0
Alternatively you could use the exposed UART:RX, UART:TX, and Ground pins with a USB to serial converter, and connect the same way as above.
Once you have a console connection to your device, update your apt database and install the following:
sudo apt-get update
sudo apt-get install ssh rsync gdbserver libxcb-xkb1 libxkbcommon-x11-0 libxcb-render-util0 libxcb-xfixes0 xinput-calibrator
This should get you everything you need. There is also an optional dependency that is a custom homescreen that will allow you to add any Qt(or non-Qt) application to the home-screen menu:
wget -O install-pockethome http://bit.ly/29zN90q
chmod a+x ./install-pockethome
You can read more about this here.
After a reboot you should be ready to go. You can tell the install was successful by the percentage of battery life being printed next the battery icon.
So now back to the host machine. As with any embedded cross-compilation setup, you need a toolchain and a sysroot to do anything useful.
First the toolchain: Since this device is running a userspace based on Debian (jessie), you need a version of GCC that is compatible with the C/C++ runtimes on the device. In this case the version of GCC you need is 4.9. You also need to get a toolchain that works the the target SOC, which is the Allwinner R8 (Cortex-A8). The runtime being used is compiled for ARMv7 gnueabi with the hard-float calling convention, so then its just a matter of finding the correct cross-compile toolchain that meets those guidelines. (Spoiler: I did it for you):
tar -xvf gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf.tar.xz
- move it too a place where you keep toolchains
mv -r gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf ~/SDK/toolchains/
Getting the correct toolchain is easy, but is pretty useless if you plan on using more than the STL features. So we also need to get a sysroot that represents the available development files (include headers / shared object files) on the PocketCHIP. Because the PocketCHIP uses Debian for it's userspace, we can actually take a few shortcuts to get a sysroot. Rather than installing the development packages on the device and cloning them to your host machine (which can take of limited space on the PocketCHIP), it's possible to simply build up the same Debian environment locally on your host machine via downloading the Debian ARM packages you need. This is similar to how Google builds Chrome for Linux (in fact the script I used is based on that). And again I've done most of the work needed for you via this script:
- download it wherever you feel like it
cd ~/Code/ git clone https://github.com/nezticle/debian-sysroot-image-creator.git cd debian-sysroot-image-creator ./scripts/sysroot-creator-chip.sh UpdatePackageListsARM ./scripts/sysroot-creator-chip.sh BuildSysrootARM
- extract the generated sysroot to your preferred sysroot location
mkdir -p ~/SDK/CHIP/sysroot
tar -xvf build/jessie/debian_jessie_arm_sysroot.tgz -C ~/SDK/CHIP/sysroot/
Now you have a mostly working sysroot. There are a few manual steps however. To be able to use EGL and OpenGLESv2 with Qt, you need to have the Mali 400's userspace development files for the PocketCHIP. This is pretty strait-forward to do though:
git clone https://github.com/NextThingCo/chip-mali-userspace.git
cp -r chip-mali-userspace/usr ~/SDK/CHIP/sysroot/
- That only gets you libMali.so + Khronos headers
ln -s libMali.so libEGL.so
ln -s libMali.so libGLESv2.so
And now you should be able to build/link applications that use EGL and OpenGL (like Qt).
Building Qt for any platform is easy once you have a working development environment. There is however one thing that is missing from Qt that you will need to add before you can build for the Allwinner R8 SOC. That is adding a new mkspec for our device.
After you've gotten a copy of Qt 5 (which I'll use assume have have and its located at ~/Code/qt5/) create the new mkspec:
mkdir -p mkspecs/devices/linux-allwinner-r8
Then edit the two new files to look like this:
- qmake.conf configuration for the Allwinner R8
R8_CFLAGS = -march=armv7-a -mfpu=neon -DLINUX=1 QMAKE_CFLAGS += $$R8_CFLAGS QMAKE_CXXFLAGS += $$R8_CFLAGS
DISTRO_OPTS += hard-float
QT_QPA_DEFAULT_PLATFORM = xcb
- include "../../linux-g++/qplatformdefs.h"
This mkspec defines how qmake will use the toolchain we downloaded.
Then it's just a matter of configuring Qt with the right magic variables. Here I assume we are building with Qt 5.8 from git and building it in shadow directory:
~/Code/qt5/configure -commercial -confirm-license -release -separate-debug-info -force-debug-info \
-prefix /usr/local/Qt-5.8 -hostprefix /home/nezticle/SDK/CHIP/Qt-5.8-chip -sysroot /home/nezticle/SDK/CHIP/sysroot \
-device r8 \
-device-option CROSS_COMPILE=/home/nezticle/SDK/toolchains/gcc-linaro-4.9-2016.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- \
-nomake tests -nomake examples -no-pch -skip qtquick1 -skip qtscript -skip qtwebkit -skip qtwebengine \
There is not too much magic here:
-prefix is where we want to install on the PocketCHIP
-hostprefix is where we want to install the host tools (like qmake, moc, uic)
-sysroot is the location of the sysroot we built eariler
-device is the name of the mkspec we created (it pattern matches to find the closes name)
-device-option CROSS_COMPILE= is the path + name of the compiler tools (everything except the tool name)
and the rest is really up to your preference.
- replace 5 with the number of build jobs you want
The "make install" command will install everything to the correct places specified by -prefix and -hostprefix. In the case of -prefix it will actually be installed to the value of -sysroot + -prefix on your host machine.
Now we have working Qt application development environment, but before we can run anything on the PocketCHIP you must first deploy the Qt libs/bins to the device. This is really easy if you have a network connection because we can just use rsync to sync the files we installed to the sysroot via "make install". In the following excerpt the IP address of the PocketCHIP is aliased to "chip" via /etc/hosts
rsync -avz --exclude=doc --exclude=include --exclude=*.debug --exclude=*.a ~/SDK/CHIP/sysroot/usr/local/Qt-* root@chip:/usr/local/
This should deploy all necessary files (ignoring unnecessary ones) to the PocketCHIP
At this point you are done, everything else is just convenience.
Setting up Qt Creator
This is pretty strait-forward. If you skip to the Qt Creator section of this blog post the instructions are the same for the PocketCHIP, just replace the location of the debugger, toolchain, qt5, and the target/device name with those you used above.
The only tricky thing is that when you want to run an X11 application on a remote device as user who does not have the X11 session, you set a couple of special values.
Whenever you run an application you are given the option to add runtime environment variables. Just make sure these two are set:
This lets the chip know which X11 server you want to run on (the local one), and that you have permission to do so (.Xauthority has the cookie needed to let you access the screen).