Sunday, November 18, 2012

Bring up Qt 5.0 on Raspberry Pi

NOTE: For updated information read here.
Ok, so I got my brand new Raspberry Pi! :-) I found a couple of guides on how to compile Qt 5.0 for it, but still I had some troubles doing that, and this guide is to speed up the process for others. Let's start from the beginning...

Links

First link of all is this: http://qt-project.org/wiki/RaspberryPi. The process is already explained there, and there is a summary of what Qt guys already made work on the platform. Still, as I said, I encountered some troubles, so I write down some notes.
Also another relevant source is: http://qt-project.org/wiki/Building_Qt_5_from_Git.

Platform plugin

As you might already know, Qt 5.0 comes with the QPA (Qt Platform Abstraction) mechanism. This means you can choose from the command line what platform driver to use. At the beginning I thought I could use the xcb plugin, but that turned out to be a bad idea: I had some troubles with libxcb being unable to communicate with X11 for some protocol-related incompatibility, like some version mismatching, I don't know (if you do, please share! :-)).
So, I went directly to the interesting part: getting rid of X11 in favor of the eglfs plugin. I'm leaving the wayland integration for a later time.

Setting up the image

You already know all this, anyway I downloaded to last wheezy image from the Pi website, and printed it in my SD card:

sudo dd if=the_wheezy_image.img of=/dev/your_sd_device

I later discovered the space was insufficient, so, I used gparted to enlarge it. You should have that for your distribution: I was using a Kubuntu 12.10 in a VM on Mac OS X.

Setting up the compilation environment

I chose to go with the Linaro toolchain, using hardfp support of course. If you don't know what hardfp support, look for that on the Internet: there is a simple explaination here. I found that toolchain for the Pi here: https://github.com/raspberrypi/tools/tree/master/arm-bcm2708. Download it and place it in a safe place (your_toolchain_path) :-)

The toolchain is not sufficient to compile Qt, you also need some other lib. To make sure to use the same libs that are in the wheezy image, I created an image for the Pi with all the dependencies I needed, downloading with aptitude and then bringing that image back to my compilation environment. By using that sysroot, I'm confident everything will be fine.
Another possible way to go is to simply scp all the libs from the Pi to the compilation system, but that is quite bothering. Also, I tried to use rsync, that is quite more simple to use, I don't have to spend time looking for the installed files any time I install a new package I need for the compilation.
My dream would anyway being able to mount the root of my Pi using NFS. This way, without any work at all I would have all my libs. NFS is actually available for the Pi, but still I was unable to make it work. If you are, please share! ;-)

Ok, this is what I wrote down while setting everything up. To compile the xcb platform driver I had to apt-get these libs on my Pi image.

sudo apt-get install libxcb1-dev libxcb-image0-dev ibxcb-image0-dev ibxcb-xfixes0-dev libxcb-keysyms1-dev libx11-dev

This made me able to compile that plugin.
For satisfying the (optional) dependencies of the qtcore module I also installed:

sudo apt-get install libdbus-dev libudev-dev libssl-dev

to add dbus and udev support.
Also, these are the packages I needed to install on the Pi to have qtmutimedia compiled with gstreamer support:

sudo apt-get install libasound2-dev libgstreamer0.10-dev

Everything should now be fine: using one of the proposed methods get the root filesystem of the Pi into the compilation environment and compilation shall begin!
How you do that is up to you: simple way is to shutdown your Pi, place the SD back in your Linux Box and:

sudo dd if=/dev/your_sd_device of=your_pi_image.img

then mount your image as a loopback device:

sudo mount -o loop,offset=62914560 your_pi_image.img your_sysroot_path

Also pay attention: the offset might change, so use fdisk to find the correct offset in the image file.
Now there is a problem: it seems that in the multi-arch image there are some symlinks which points to files with an absolute path. This is a problem since, typically, you want to place your_sysroot somewhere which is not the root, and therefore the symlink becomes invalid. The page I linked above provides a script to fix these paths: https://gitorious.org/cross-compile-tools/cross-compile-tools/blobs/master/fixQualifiedLibraryPaths. Give it as parameter the location of your sysroot on the compilation machine and it should fix the paths.

You'll also need some instruments on the compilation system: if you're running Kubuntu or Ubuntu, you'll need these packages, otherwise use the instruments provided by your distribution:

sudo apt-get install build-essential perl python git

Also, if you intent to also compile QtWebKit, you'll need additional packages:

sudo apt-get install flex bison gperf libicu-dev libxslt-dev ruby

I hope I didn't forget anything... if I did, please consider adding a comment!
NOTE: If you're compiling in a virtual environment, like I am, beware that QtWebKit compilation will require more than 512MB of RAM! I spent half a day trying to recompile a new toolchain because of "internal compiler error". At least 1GB of RAM should be reserved, but 2GB might be better for QtWebKit.

Getting the source code

This is pretty standard, anyway:

git clone git://gitorious.org/qt/qt5.git qt5
cd qt5
perl init-repository

This will download everything you need.

Configuration and build

You'll need to configure, building and installing the qtbase module first of all. This is the configure line I used:

./configure -prefix your_qt_prefix -release -device linux-rasp-pi-g++ -make libs -device-option CROSS_COMPILE=your_toolchain_path/bin/arm-linux-gnueabihf- -device-option DISTRO=wheezy -sysroot your_sysroot_path -qpa xcb -opensource -confirm-license -no-pch -make examples -nomake tests

I didn't select tests because it failed compilation asking for libboost, which I had no time to provide. If you want, packages for wheezy are available. In case any error occurs in the configuration process, use the -v parameter to try to guess what went wrong
If your configuration succeeds, you should see a smiling table like this:

Result is:
Building on:   linux-g++
Building for:  devices/linux-rasp-pi-g++
Architecture:  arm, features:
Host architecture: unknown, features:
Platform notes:

            - Also available for Linux: linux-kcc linux-icc linux-cxx
       
qmake vars .......... qmake switches .........
Build ..................  libs
Configuration ..........  cross_compile qpa largefile precompile_header neon pcre  minimal-config small-config medium-config large-config full-config no-pkg-config evdev xcb-poll-for-queued-event linuxfb c++11 egl eglfs opengl opengles2 shared qpa reduce_exports reduce_relocations clock-gettime clock-monotonic mremap getaddrinfo ipv6ifname getifaddrs inotify png freetype system-zlib nis iconv openssl xcb rpath icu concurrent audio-backend v8 release
Debug .................. no
C++11 support .......... yes
pkg-config ............. yes
QtDBus module .......... yes
QtConcurrent code ...... yes
QtGui module ........... yes
QtWidgets module ....... yes
JavaScriptCore JIT ..... To be decided by JavaScriptCore
QML debugging .......... yes
PCH support ............ yes
iWMMXt support ......... no
NEON support ........... yes
IPv6 ifname support .... yes
getaddrinfo support .... yes
getifaddrs support ..... yes
Accessibility .......... no
NIS support ............ yes
CUPS support ........... no
Iconv support .......... yes
Glib support ........... no
GStreamer support ...... no
PulseAudio support ..... no
Large File support ..... yes
GIF support ............ plugin
JPEG support ........... plugin (qt)
PNG support ............ yes (qt)
zlib support ........... system
Session management ..... auto
libudev support ........ yes
OpenGL support ......... yes (OpenGL ES 2.x)
OpenVG support ......... no
XShape support ......... auto
XVideo support ......... auto
XSync support .......... auto
Xinerama support ....... runtime
Xcursor support ........ runtime
Xfixes support ......... runtime
Xrandr support ......... runtime
Xi support ............. runtime
Xi2 support ............ no
MIT-SHM support ........ auto
FontConfig support ..... no
XKB Support ............ auto
immodule support ....... yes
GTK theme support ...... no
SQLite support ......... plugin (qt)
OpenSSL support ........ yes (run-time)
Alsa support ........... no
libICU support ......... yes
PCRE support ........... qt
Xcb support ............ yes
Xrender support ........ no
EGLFS support .......... yes
DirectFB support ....... no
LinuxFB support ........ yes
KMS support ............ no


This means you're pretty ok now, you can start compilation using something like:

make -j(number_of_cpus + 1)

This is the time where you might want to have a coffee.
If everything builds correctly, you're at a good point, so install:

sudo make install

and be happy now! You should see on your system your_qt_prefix now exists and contains at least the bin directory with the qmake executable. Also, in your_sysroot_path/your_qt_prefix/ you should see the compiled libs, the imports, the plugins etc...
You are done!

Compile some other exciting module

Just qtbase alone is pretty interesting, but you can now try to compile other modules! All the modules can be compiled the same way:

cd your_qt_module
your_qt_prefix/bin/qmake
make -j(number_of_cpus + 1)
sudo make install

Some of the modules should compile without bloodsheds, while for some others I'll reserve some other post. Just consider that qjsbackend seems to need a patch at the moment of writing, so, before building it:

cd qtjsbackend
git fetch https://codereview.qt-project.org/p/qt/qtjsbackend refs/changes/56/27256/4 && git cherry-pick FETCH_HEAD

This should make it work correctly.
Consider that qtmultimedia, qtwayland and qtwebkit might need more work. I'll write about QtWebKit when I'll find the time to.
Also, I tried to run Qt with 32bit color depth, and it seems again the algorithm of choice of the EGL configuration still chooses 16bit. I solved by modifying the sources, I'll write about this as soon as I'll have the time to.

Running the examples

Now, you can write some test app or try to run some of the examples on the Pi. You'll have to copy your Qt libraries back to your Pi, or create a new image to place on the SD card. To create the new image just dd your_pi_image.img back on the SD card and boot the Pi with that new filesystem. Now check your_qt_prefix to confirm that the Qt libs have been placed there. Now, in your_pi_prefix/examples you should see many possible application to test. To have a look at the performance, I suggest trying some of the Qt3d or qtquick examples on the eglfs platform plugin:

LD_LIBRARY_PATH=your_qt_prefix/lib ./some_example -platform eglfs

Sample video

This is some QML code I wrote in 10 minutes using a PathView just to show somehow the performance. Very gooooood! This is Qt 5.0 running 1080p 32 bit color depth QtQuick2 with the eglfs plugin!

14 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Did you run the fixQualifiedLibraryPaths script? Check libdl and libm are correctly placed in your sysroot.

    ReplyDelete
    Replies
    1. Thank so much, I could to solve that wrong, I required some dependences, but a I have the next problem when I execute any program:

      ****************************************************************
      ****************************************************************
      Failed to load platform plugin "eglfs". Available platforms are:
      linuxfb
      minimal
      xcb

      Aborted
      ******************************************************************
      ******************************************************************

      Well, I tried to compile "qtbase" with "eglfs" plugin, I think that maybe I need any dependences but I don´t know. Could you help me? Thanks.

      Delete
    2. It seems you don't have libqeglfs.so in your plugins path. Look for it. If you don't have it, compile from the sources: it is located in qtbase/src/plugins/platforms/eglfs. Then place it in your plugins path.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Hi Luca, do you know howto get keyboard layout working under QT5 and raspbian? On xcb it's fine but when using eglfs I have just default probably EN layout.

    ReplyDelete
  5. Hy Lica! There are two 'l's missing:

    libxcb-image0-dev libxcb-xfixes0-dev

    I am trying to get Qt5 and QtWebKit working on the raspbian, its a lot of work and already spend some hours of compiling something what is not working... but i will try it again with your posts ;)

    ReplyDelete
  6. Hi
    I am new to Linux and trying to lean. Can you please help with this part?

    What files and or directres do i need and where do they need to be placed on the compilation environment?

    "To make sure to use the same libs that are in the wheezy image, I created an image for the Pi with all the dependencies I needed, downloading with aptitude and then bringing that image back to my compilation environment. By using that sysroot, I'm confident everything will be fine."

    ReplyDelete
    Replies
    1. Go on reading after that. The steps are described.

      Delete
  7. Thank you for you reply.

    When i run this: sudo mount -o loop,offset=62914560 home/juhl/wheezy_with_libs.img /.
    it comes up with "mount: you must specify the filesystem type"

    Please can you help? :'(

    ReplyDelete
  8. Not sure if you got to access RPi partitions on device using NFS, if not here is what you shall do,
    0) package nfs-kernel-server, rpcbind are present on target
    1) ensure /etc/exports has correct entries
    2) sudo rpcbind
    3) sudo /etc/init.d/nfs-kernel-server restart

    ReplyDelete
  9. The https://gitorious.org/cross-compile-tools/cross-compile-tools/blobs/master/fixQualifiedLibraryPaths is down. Do you have the correct fix script? I found one (https://github.com/darius-kim/cross-compile-tools), but still getting the make error...

    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libdl.a(dlopen.o): In function `dlopen':
    (.text+0xc): undefined reference to `__dlopen'
    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libdl.a(dlclose.o): In function `dlclose':
    (.text+0x0): undefined reference to `__dlclose'
    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libdl.a(dlsym.o): In function `dlsym':
    (.text+0xc): undefined reference to `__dlsym'
    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libdl.a(dlerror.o): In function `dlerror':
    (.text+0x0): undefined reference to `__dlerror'
    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libm.a(feholdexcpt.o): In function `feholdexcept':
    (.text+0x48): undefined reference to `_dl_hwcap'
    /home/aba/mount/usr/lib/arm-linux-gnueabihf/libm.a(fesetenv.o): In function `fesetenv':
    (.text+0x64): undefined reference to `_dl_hwcap'
    collect2: error: ld returned 1 exit status
    Makefile:1213: recipe for target '../../lib/libQt5Core.so.5.5.1' failed
    make[2]: *** [../../lib/libQt5Core.so.5.5.1] Error 1
    make[2]: Leaving directory '/home/aba/opt/qt5/qtbase/src/corelib'
    Makefile:170: recipe for target 'sub-corelib-make_first' failed
    make[1]: *** [sub-corelib-make_first] Error 2
    make[1]: Leaving directory '/home/aba/opt/qt5/qtbase/src'
    Makefile:45: recipe for target 'sub-src-make_first' failed
    make: *** [sub-src-make_first] Error 2

    ReplyDelete