Cross compile for Raspberry Pi

From GNU Radio
Jump to navigation Jump to search

Tested Setup

  • Target: Raspberry Pi Model 3 B+, running `aarch64` (Ubuntu MATE 18.04 64 bit)
  • Build host (for GNU Radio only): Ubuntu 18.04 on a PC
  • GNU Radio Version: above 3.8tech-preview, commit c7780bb2abaebd4a0a3ce0ada5d446d554b8adcc
  • Volk version: above v1.4, commit d250816c6e5cebd7a668e273c8964baddf1a9b00 (set automatically via git submodule)
  • Using Python 3


Initial setup of the Raspberry Pi

Install all GNU Radio build dependencies:

sudo apt update
sudo apt install git cmake g++ libboost-all-dev libgmp-dev swig python3-numpy \
python3-mako python3-sphinx python3-lxml doxygen libfftw3-dev libcomedi-dev \
libsdl1.2-dev libgsl-dev libqwt-qt5-dev libqt5opengl5-dev python3-pyqt5 \
liblog4cpp5-dev libzmq3-dev python3-yaml python-mako python-click-plugins

Initial setup of the build host

Install the toolchain for linux ARM aarch64 cross-compilation:

sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu binutils-aarch64-linux-gnu pkg-config-aarch64-linux-gnu

Create a folder to store the sysroot of the Raspberry Pi (RPI):

mkdir -p ~/x-compile/sysroot

Rsync the "/lib" and "/usr" folders from the RPI to the sys root folder that was created on the host:

rsync --progress -rl --delete-after --safe-links rpi-hostname:/{lib,usr} ~/x-compile/sysroot

where rpi-hostname is the hostname of your RPI.

Cross-compile GNU Radio

Clone:

mkdir -p ~/src/
cd ~/src/
git clone --recursive https://github.com/gnuradio/gnuradio.git
cd gnuradio/

Now, copy the aarch64 toolchain from volk:

cp volk/cmake/Toolchains/aarch64-linux-gnu.cmake cmake/Toolchains/

Cmake build environment

Add some custom configurations to the cmake toolchain file. First configure sysroot by adding:

set(CMAKE_SYSROOT "$ENV{HOME}/x-compile/sysroot")

set(ENV{PKG_CONFIG_DIR} "")
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig:${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/pkgconfig:${CMAKE_SYSROOT}/usr/local/lib/pkgconfig")
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})

Then, add the following:

# Search for programs only in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# Search for libraries and headers only in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Now prepare the build environment with cmake. Note many in-tree modules are disabled below. Choose whatever suits you. More importantly, note that -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/aarch64-linux-gnu.cmake must be set.

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/home/$USER/usr/local/ \
-DENABLE_DOXYGEN=OFF \
-DENABLE_SPHINX=OFF \
-DENABLE_GR_DTV=OFF \
-DENABLE_GR_FEC=OFF \
-DENABLE_GR_CHANNELS=OFF \
-DENABLE_GR_AUDIO=OFF \
-DENABLE_GR_TRELLIS=OFF \
-DENABLE_GR_VIDEO_SDL=OFF \
-DENABLE_GR_VOCODER=OFF \
-DENABLE_GR_WAVELET=OFF \
-DENABLE_GR_ZEROMQ=off \
-DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/aarch64-linux-gnu.cmake ..

> IMPORTANT: the prefix set via DCMAKE_INSTALL_PREFIX will be used both locally (in the host) as well as in the target (RPI). By the end of the build, we install locally in the prefix. Subsequently, we copy the locally installed files to the same path in the target (the RPI).

As configured above, the cmake build will try to use QT5 tools from the sysroot, particularly the QT User Interface Compiler (uic) and the QT Meta-Object Compiler (moc). This would cause problems, since binaries of these tools on sysroot folder are for the RPI, not for the host system. To overcome this, open the following files and manually substitute the path of all occurrences of “uic” and “moc” such that, instead, the locally (host’s) tool is used.

Substitute /home/$(USER)/x-compile/sysroot/usr/lib/qt5/bin/moc with /usr/lib/qt5/bin/moc, and /home/$(USER)/x-compile/sysroot/usr/lib/qt5/bin/uic with /usr/lib/qt5/bin/uic in the following files:

 * build/gr-qtgui/lib/CMakeFiles/gnuradio-qtgui.dir/build.make
 * build/gr-qtgui/examples/c++/CMakeFiles/display_qt.dir/build.make


Build and Install

In the build host, run:

make -j4
make install

> NOTE: this will install locally (on the host) at the path that was defined via CMAKE_INSTALL_PREFIX, i.e. /home/$USER/usr/local/.


Prepare GR on RPI

First copy the GR build products (executables, libraries, includes etc) from the build host to the target (RPI).

On the RPI, run:

mkdir -p ~/usr/local

Then, from the host, run:

cd ~/usr/local
rsync -av -e ssh . rpi-hostname:~/usr/local

Now, back in the RPI, create a script to set environmental variables. These vars will be necessary on RPI every time GR is to be executed, since GR build products have been placed at a non-conventional prefix. Hence, you will need to run this script every time.

Create a file named set_env.sh, for instance in your home bin folder ~/usr/local/bin, and place the following lines on it:

#!/bin/bash

PREFIX=$HOME/usr/local

export PATH=$PATH:$PREFIX/bin
export LD_LOAD_PATH=$LD_LOAD_PATH:$PREFIX/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PREFIX/lib
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PREFIX/lib/pkgconfig
export PYTHONPATH=$PYTHONPATH:$PREFIX/lib/python3.6/dist-packages

Now add executable permissions and run it such that env vars are set in the parent bash session:

chmod u+x set_env.sh
. set_env.sh

Check if GR is working. For instance, try to open gnuradio-companion:

cd ~/usr/local/bin
python3 gnuradio-companion

Or check version and built components:

gnuradio-config-info -v --enabled-components

If the above commands are succesful, your are good to start using GNU Radio on Raspberry Pi!


Building an OOT Module

In case you have an OOT module that you can afford to build natively from the RPI, all you need to do is first set the env vars to use the above GNU Radio build:

. ~/usr/local/bin/set_env.sh

Then, configure cmake with the correct installation prefix and run the build:

cd ~/src/your-oot-dir
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=~/usr/local/ ..
make
make install


Using an RTL-SDR on Raspberry Pi

In case you want to use an RTL-SDR, you can build its corresponding library directly (natively) on Raspberry Pi.

First, instal libusb:

sudo apt-get install libusb-1.0-0-dev

Next, build rtl-sdr:

cd ~/src/
git clone https://github.com/osmocom/rtl-sdr.git
cd rtl-sdr/
mkdir build
cd build/
cmake ../ -DINSTALL_UDEV_RULES=ON
make
make install DESTDIR=~

A minor note is that this build might result in the following error:

>Allocating 15 zero-copy buffers
>Bus error

The solution is to remove some lines of code from `src/librtlsdr.c` and then recompile. See this stackoverflow thread.

Finally, blacklist module dvb_usb_rtl28xxu such that it does not prevent rtl-sdr from running. To do so, edit /etc/modprobe.d/blacklist.conf and add:

blacklist dvb_usb_rtl28xxu

Finally, build gr-osmosdr. The main repository does not provide a working version for GR 3.8. However, an almost functional version can be found at igorauad/gr-osmosdr:

Clone the fork and switch to the GR 3.8 branch:

cd ~/src/
git clone https://github.com/igorauad/gr-osmosdr.git
cd gr-osmosdr/
git fetch origin
git checkout gr3.8

Build:

mkdir build
cd build/
cmake -DCMAKE_INSTALL_PREFIX=/home/$(USER)/usr/local/ ..
make
make install