Cross compile for Raspberry Pi
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