Skip to content

Cross compiling for Raspberry Pi

adamjalkemo edited this page Nov 12, 2017 · 15 revisions

Cross Compiling ofnode for Raspberry Pi

Requirements:

I'm using Ubuntu 16.10

Preparing the Raspberry Pi

1. Copy RPi image to SD

Use Ubuntu disk utility if you're lazy like me. You can do it with dd too, there are plenty of command line example on the net but you should end up with something like :

$ sudo dd bs=1m if=2016-11-25-raspbian-jessie-lite.img of=/dev/rdisk2

2. Connect the Raspberry Pi directly to your host network

You can either connect the RPi directly to your computer and share a Wifi connection via ethernet adapter, or connect it to the same router your computer is connected to.

3. Configure your RPi

On 2016-11-25-raspbian-jessie-lite.img ssh is not enabled by default. The simplest way to set up is to plug a screen, a keyboard and a power cable to the RPi then on the Pi terminal :

$ sudo raspi-config

In the raspi-config menu, select Option 1 Expand Filesystem, then go to 5 Interfacing Options and choose P2 SSH Enable/Disable remote command line access to your Pi using SSH (this menu position may change according to your raspi-config version) then enable the SSH service. You can also change Keyboard layout, localization, time zone, etc. and reboot.

Now you connect through SSH to the RPi with :

And use this session to enter the following command line instructions.

4. Install gcc-6 and openFrameworks dependencies into Raspberry Pi

4.1 Installing gcc-6 (optional)

gcc-4.9 becomes outdated and it becomes more and more difficult to build a working cross-compiler, we may jump into the future and use gcc-6 instead. Unfortunately, it is not available into jessie repo, so we will grab the scretch one. Here is a sum-up of a step by step tutorial :

pi@raspberrypi:~ $ sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak
pi@raspberrypi:~ $ sudo sed -i -- 's/jessie/stretch/g' /etc/apt/sources.list
pi@raspberrypi:~ $ sudo apt update
pi@raspberrypi:~ $ sudo apt install gcc-6 g++-6
pi@raspberrypi:~ $ sudo mv /etc/apt/sources.list_bak /etc/apt/sources.list # revert changes to sources.list
pi@raspberrypi:~ $ sudo apt update

4.2 Install openFrameworks dependencies

Now, update the dependencies required when cross-compiling by downloading and running raspbian.sh.

pi@raspberrypi:~ $ wget  https://github.com/raw/ofnode/of/master/dev/install/linux/raspbian.sh
pi@raspberrypi:~ $ chmod +x raspbian.sh
pi@raspberrypi:~ $ sudo ./raspbian.sh

5. Make an new image file from the existing and updated Raspberry Pi

Shutdown the Raspberry Pi with :

pi@raspberrypi:~ $ sudo shutdown -P now

Then remove the SD card from the Raspberry Pi, insert the SD card in your host and use dd to make an new image file.

$ df # and identify where is your SD card, note both first and last item in the line
Sys. de fichiers blocs de 1K   Utilisé Disponible Uti% Monté sur
/dev/sdc2            7513804   6000140    1158168  84% /media/antoine/13d368bf-6dbf-4751-8ba1-88bed06bef77
/dev/sdc1              57288     20384      36904  36% /media/antoine/boot
$ umount /media/antoine/boot /media/antoine/13d368bf-6dbf-4751-8ba1-88bed06bef77
$ sudo dd bs=1m if=/dev/sdc of=raspbian-jessie-lite+of+ofnode_dependency.img # you could try to increase bs value but bbe careful this could cause read/write error and then you'll end up with a corrupted image.

Or use Linux disk utility GUI to do the same. I am using raspbian-jessie-lite+of+ofnode_dependency.img as the image name.

6. Mount image in read/write mode

Now we need to mount the .img but default image loader (when you double click it) mount in read only mode and we need to fix dead symlink.

Get the partition table with :

$ fdisk -lu raspbian-jessie-lite+of+ofnode_dependency.img
Périphérique                                                                                Amorçage  Start     Fin Secteurs  Size Id Type
raspbian-jessie-lite+of+ofnode_dependency.img1            8192  137215   129024   63M  c W95 FAT32 (LBA)
raspbian-jessie-lite+of+ofnode_dependency.img2          137216 7774207  7636992  3,7G 83 Linux

Then get the start offset of the second partition (The Linux one) and multiply it by 512 to get an offset in octet rather than in sector. Here it is 137216 * 512 = 70254592. Then mount the partition with read/write permission :

$ mkdir /tmp/rpi/root
$ sudo mount -o loop,offset=70254592,rw,sync  raspbian-jessie-lite+of+ofnode_dependency.img  /tmp/rpi/root

7. Fix dead link

Many symbolic links in Linux system refered to absolute path with cause error when mounting the image in a folder, like we do. So we need to fix the links with :

$ cd /tmp/rpi/root/usr/lib/arm-linux-gnueabihf
$ sudo ln -fs ../../../lib/arm-linux-gnueabihf/libudev.so.1.5.0 libudev.so
$ sudo ln -fs ../../../lib/arm-linux-gnueabihf/libglib-2.0.so.0 libglib-2.0.so
$ sudo ln -fs ../../../lib/arm-linux-gnueabihf/libz.so.1 libz.so
$ sudo ln -fs ../../../lib/arm-linux-gnueabihf/libdl.so.2 libdl.so

Prepare host

Get a cross-compiler

In Ubuntu 16.10 you can get arm-linux-gnueabihf-gcc-4.9 and arm-linux-gnueabihf-g++-4.9 with :

$ sudo apt install gcc-4.9-arm-linux-gnueabihf g++-4.9-arm-linux-gnueabihf pkg-config-arm-linux-gnueabihf

If you need gcc-6, then just do :

$ sudo apt install gcc-arm-linux-gnueabihf  g++-arm-linux-gnueabihf pkg-config-arm-linux-gnueabihf

Download ofnode

If you don't have it already :

$ git clone https://github.com/ofnode/of.git

Configure and build

We need to define some environnement variable, CMake can't do it because of an annoying bug.

$ export RPI_ROOT_PATH=/tmp/rpi/root
$ export PKG_CONFIG_SYSROOT_DIR=$RPI_ROOT_PATH
$ export PKG_CONFIG_LIBDIR=${RPI_ROOT_PATH}/usr/lib/pkgconfig:${RPI_ROOT_PATH}/usr/share/pkgconfig:${RPI_ROOT_PATH}/usr/lib/arm-linux-gnueabihf/pkgconfig/

Then configure build system :

$ mkdir build-of-rpi-debug 
$ cd build-of-rpi-debug 
$ cmake ../of -DCMAKE_TOOLCHAIN_FILE=${PWD}/../of/dev/arm-linux-gnueabihf-4.9.cmake -DRPI_ROOT_PATH='/tmp/rpi/root'  -DOF_STATIC=ON -DCMAKE_BUILD_TYPE=Debug -G Ninja

I strongly recommand to build a static library, then you don't need to copy all the shared library to the RPi but just the resulting binary (and its data folder if needed). Replace arm-linux-gnueabihf-4.9.cmake with arm-linux-gnueabihf.cmake if you need gcc-6.

Then you're ready to build :

$ ninja

Take a rest and a coffee :-)

You can now build an example :

 $ cd ..
 $ git clone https://github.com/ofnode/ofApp.git
 $ mkdir build-ofApp-rpi-debug
 $ cd build-ofApp-rpi-debug
 $ cmake ../ofApp -DCMAKE_TOOLCHAIN_FILE=${PWD}/../of/dev/arm-linux-gnueabihf-4.9.cmake -DRPI_ROOT_PATH='/tmp/rpi/root'  -DOF_STATIC=ON -DCMAKE_BUILD_TYPE=Debug -G Ninja
 $ ninja

Then you just have to copy the new binary to the Raspberry Pi.

$ scp ../bin/ofApp-armv7-Debug [email protected]:~/

And test it :

$ ssh [email protected] /home/pi/ofApp-armv7-Debug

Using QtCreator to build and run

You can use QtCreator to edit your code and build your app and even start it.

Configuration

There are at least 2 ways to configure it : you can setup a kit for Raspberry Pi or configure by command line and then tell QtCreator to use that configuration. I choose the second one.

After configuring the build with the command above, open the CMakeLists.txt in QtCreator. Then go to the project settings page and display build configuration. In the build folder field, put the path to the folder where you configured the buidl. And at the bottom of the page in Build environment, display details and clic on batch edit then enter :

PKG_CONFIG_LIBDIR=${RPI_ROOT_PATH}/usr/lib/pkgconfig:${RPI_ROOT_PATH}/usr/share/pkgconfig:${RPI_ROOT_PATH}/usr/lib/arm-linux-gnueabihf/pkgconfig/
PKG_CONFIG_SYSROOT_DIR=${RPI_ROOT_PATH}
RPI_ROOT_PATH=/tmp/rpi/root

This will ensure that the environment variable are correctly set when you run CMake.

Run

It appears that network copy is quite slow for me and to avoid it, I add the bin folder of my app to my NFS export, by adding the following line to /etc/exports :

/<custom path>/ofApp 192.168.0.0/24(rw,sync,no_root_squash,no_subtree_check)

Restart nfs-kernel-server

$ sudo service nfs-kernel-server reload

Then I mount it on the Raspberry Pi with :

pi@raspberrypi:~ $ mkdir -p ~/ofApp
pi@raspberrypi:~ $ sudo mount <host ip>:/<custom path>/ofApp/bin ~/ofApp

and run :

pi@raspberrypi:~ $ ~/ofApp/bin/ofApp-Debug

You can start it directly from QtCreator by adding a custom executable with command ssh and arguments [email protected] /home/pi/ofApp/bin/ofApp.

Of course, adapt paths to your configuration and it's much easier to setup a passwordless SSH authentication.