GRAndDeps

From GNU Radio
Jump to navigation Jump to search

Setup and Building the Dependencies

Android Build System Prerequisites

We need Android Lollipop (5.0) to support the use of complex numbers. This is Android API 21 and the latest Android NDK, which is r10d.

IMPORTANT: Please use the NDK version r10e. Newer versions (r11c out currently) have removed GCC version 4.8 and only include 4.9. We have some C++ build issues with 4.9 and must use 4.8.

Optionally:

Unpack the NDK into /opt/android-ndk-<version>. Create a symlink to /opt/ndk.

Unpack Android Studio into /opt/android-studio. Run /opt/android-studio/bin/studio.sh. The first thing this will do is download and install the Android SDK. If you downloaded this yourself above, I installed it into /opt/android-sdk-linux and created a symlink to /opt/android. When I ran Android Studio, it asks where you would like to install this. Give it /opt/android-sdk-linux. If you did not install the SDK yourself, this will install everything you need. If you did install it, this will just install updates.

You can then run /opt/android/tools/android to do any tweaking of the SDK. Make sure your Android SDK and NDK supports API 21 (5.0).

Export these variables pointing to where you installed the SDK (/opt/android) and NDK (/opt/ndk):

export ANDROID_SDK=/opt/android
export ANDROID_NDK=/opt/ndk
export PATH=$PATH:$ANDROID_SDK/tools:$ANDROID_NDK

Dependencies Build Script

The following build script packages up all of the steps to build the following dependencies as well as VOLK, GNU Radio, GRAnd, and gr-osmosdr (see GRAndBuild). It is known to work with Ubuntu 15.10, 64-bit. There are likely a handful of apt-gettable programs necessary for this to complete. You will definitely need the following:

- cmake, git, make, xutils-dev, automake, autoconf, libtool, wget, perl, tar, sed

Download the Build Script.

Building the Toolchain

We will create our own tool chain that uses GCC 4.8. The 4.9 toolchain has some issues still. To make the toolchain, run the command:

/opt/ndk/build/tools/make-standalone-toolchain.sh --stl=gnustl --arch=arm --platform=android-21 --abis=armeabi-v7a --install-dir=/opt/android-toolchain

You can select your own --install-dir; we'll set a variable later for this to make it flexible.

Then, let's update some of the environmental variables:

export ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain
export PATH=$ANDROID_STANDALONE_TOOLCHAIN/bin:$PATH

Dependency Setup

The basic dependencies we need to build GNU Radio and its most interesting/useful components are Boost and FFTW.

Make a directory to install all of the dependencies and GNU Radio and make it owned by you. For example:

sudo mkdir /opt/grandroid
sudo chown user1:user1 /opt/grandroid
export PREFIX=/opt/grandroid

Boost for Android

NOTE: Recently changed; See the "Older Boost (1.55) for Android" section below for the original instructions we were using.

Download Boost >= 1.58 from http://www.boost.org/. This can either be a bzip or gzip tarball. We'll unpack it, fix some configuration issues for Android, and build:

tar xjf boost_1_58_0.tar.bz2  (use 'xzf' flags instead of 'xjf' if you have the tar.gz version)
cd boost_1_58_0

Create a file called tools/build/src/user-config.jam and put the following into it:

import os ;

local ANDROID_STANDALONE_TOOLCHAIN = [ os.environ ANDROID_STANDALONE_TOOLCHAIN ] ;

using gcc : android :
     $(ANDROID_STANDALONE_TOOLCHAIN)/bin/arm-linux-androideabi-g++ :
     --sysroot=$(ANDROID_STANDALONE_TOOLCHAIN)/sysroot
     -march=armv7-a
     -mfloat-abi=softfp
     -Os
     -fno-strict-aliasing
     -O2
     -DNDEBUG
     -g
     -lstdc++
     -I$(ANDROID_STANDALONE_TOOLCHAIN)/include/c++/4.8/
     -I$(ANDROID_STANDALONE_TOOLCHAIN)/include/c++/4.8/arm-linux-androideabi/armv7-a
     -D__GLIBC__
     -D_GLIBCXX__PTHREADS
     -D__arm__
     -D_REENTRANT
     -DBOOST_SP_USE_PTHREADS
     -L$(ANDROID_STANDALONE_TOOLCHAIN)/lib/gcc/arm-linux-androideabi/4.8/
     $(ANDROID_STANDALONE_TOOLCHAIN)/bin/arm-linux-androideabi-ar
     $(ANDROID_STANDALONE_TOOLCHAIN)/bin/arm-linux-androideabi-ranlib
     ;

Then run the build scripts. You can play with the options for which libraries to build and not build. Here, we are building the set of libraries required for GNU Radio but no others.

./bootstrap.sh
./b2 \
  --without-python --without-container --without-context \
  --without-coroutine --without-graph --without-graph_parallel \
  --without-iostreams --without-locale --without-log --without-math \
  --without-mpi --without-signals --without-timer --without-wave \
  link=static runtime-link=static threading=multi threadapi=pthread \
  target-os=linux --stagedir=android --build-dir=android \
  stage

{{collapse(Details on the results (click to unfold))
When done correctly, the initial output will show us the configuration, which will looks like this using the above settings:

Performing configuration checks

    - 32-bit                   : yes
    - arm                      : yes
    - has_icu builds           : no
    - lockfree boost::atomic_flag : no

Component configuration:

    - atomic                   : building
    - chrono                   : building
    - container                : not building
    - context                  : not building
    - coroutine                : not building
    - date_time                : building
    - exception                : building
    - filesystem               : building
    - graph                    : not building
    - graph_parallel           : not building
    - iostreams                : not building
    - locale                   : not building
    - log                      : not building
    - math                     : not building
    - mpi                      : not building
    - program_options          : building
    - python                   : not building
    - random                   : building
    - regex                    : building
    - serialization            : building
    - signals                  : not building
    - system                   : building
    - test                     : building
    - thread                   : building
    - timer                    : not building
    - wave                     : not building

It is important to make sure that this is saying that it will be building 32-bit for ARM.

When that finishes, we will have a set of static libraries in the android/lib directory. We can verify that these are correctly cross-compiled for our ARM systems with:

readelf -A android/lib/libboost_system.a
File: android/lib/libboost_system.a(error_code.o)
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "7-A"
  Tag_CPU_arch: v7
  Tag_CPU_arch_profile: Application
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-2
  Tag_FP_arch: VFPv2
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_ABI_HardFP_use: SP and DP
  Tag_ABI_optimization_goals: Aggressive Speed
  Tag_CPU_unaligned_access: v6

So this library is for ARMv7-a, which is what we want.
}}

Now, install it into our PREFIX:

./b2 \
  --without-python --without-container --without-context \
  --without-coroutine --without-graph --without-graph_parallel \
  --without-iostreams --without-locale --without-log --without-math \
  --without-mpi --without-signals --without-timer --without-wave \
  link=static runtime-link=static threading=multi threadapi=pthread \
  target-os=linux --stagedir=android --build-dir=android \
  --prefix=$PREFIX install

FFTW for Android

  • Unpack it
tar xzf fftw-3.3.4.tar.gz
cd fftw-3.3.4
  • Setup the environment, build, and install:
mkdir build; cd build
export SYS_ROOT="$ANDROID_STANDALONE_TOOLCHAIN/sysroot"
export CC="arm-linux-androideabi-gcc --sysroot=$SYS_ROOT"
export LD="arm-linux-androideabi-ld"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip"
../configure --enable-single --enable-static --enable-threads \
  --enable-float  --enable-neon \
  --host=armv7-eabi --build=x86_64-linux \
  --prefix=$PREFIX \
  LIBS="-lc -lgcc -march=armv7-a -mfloat-abi=softfp -mfpu=neon" \
  CC="arm-linux-androideabi-gcc -march=armv7-a -mfloat-abi=softfp -mfpu=neon"
make
make install
  • puts libfftw3f.a and libfftw3_threads.a into $PREFIX/lib
  • and fftw3.h into $PREFIX/include

Thrift

Required for using ControlPort on Android.

(Work-in-progress: Thrift stopped building cleanly for me so the following instructions are just a placeholder as I work through that.)

OpenSSL for Android

Thrift requires some OpenSSL libraries, like libcrypto, so we need to build these first and install them into the toolchain.

  • IMPORTANT: Do all of this in a new shell since we'll be polluting the environmental variables.
  • Set the toolchain bin path to the prebuilt one in the NDK since that's where OpenSSL will go look for everything:
export PATH=$ANDROID_NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin:$PATH
export ANDROID_NDK_ROOT=$ANDROID_NDK
  • Download OpenSSL

' https://www.openssl.org/source/

' Select the latest in the 1.0.2 series (1.0.2a as of writing this)

'* Update: 1.1.0 has been released but is structured differently; we have not updated for that, yet.

tar xzf openssl-1.0.2a.tar.gz 
cd openssl-1.0.2a/
  • Get and edit a special shell script to build OpenSSL for Android:
wget https://wiki.openssl.org/images/7/70/Setenv-android.sh
chmod +x Setenv-android.sh
. ./Setenv-android.sh
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
./config --prefix=/usr shared no-ssl2 no-ssl3 no-comp no-hw no-engines --openssldir=$ANDROID_STANDALONE_TOOLCHAIN/sysroot/usr/ssl/$ANDROID_API
make depend
make all
cp libcrypto.* $ANDROID_STANDALONE_TOOLCHAIN/sysroot/usr/lib
cp libssl.* $ANDROID_STANDALONE_TOOLCHAIN/sysroot/usr/lib/
ln -s `pwd`/include/openssl $ANDROID_STANDALONE_TOOLCHAIN/sysroot/usr/include
  • Close this shell! Do not proceed to the next steps within this shell.

Apache Thrift

  • Download Apache Thrift:

' https://thrift.apache.org/download

git clone https://git-wip-us.apache.org/repos/asf/thrift.git thrift
cd thrift
git checkout 0.9.3
  • Go into configure.ac and comment out lines:
    • 598 (AC_FUNC_MALLOC)
    • 600 (AC_FUNC_REALLOC)
  • Configure and build thrift
export SYS_ROOT="$ANDROID_STANDALONE_TOOLCHAIN/sysroot/"
export CC="arm-linux-androideabi-g++ --sysroot=$SYS_ROOT"
export CXX="arm-linux-androideabi-g++ --sysroot=$SYS_ROOT"
export LD="arm-linux-androideabi-ld"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip"
./bootstrap.sh
./configure --prefix=$PREFIX   --disable-tests --disable-tutorial --with-cpp \
 --without-python --without-c_glib --without-php --without-csharp --without-java \
 --without-libevent --without-zlib \
 --with-boost=$PREFIX --host=arm-eabi --build=x86_64-linux \
 CPPFLAGS="-I$ANDROID_STANDALONE_TOOLCHAIN/include/c++/4.8/arm-linux-androideabi/armv7-a" \
 LDFLAGS="-L$ANDROID_STANDALONE_TOOLCHAIN/arm-linux-androideabi/lib/armv7-a -lgnustl_shared"
make
make install
  • We should now have a libthrift.a file in $PREFIX/lib.

Zeromq (optional)

  • Download ZeroMQ
wget http://download.zeromq.org/zeromq-3.2.4.tar.gz
tar -xvf zeromq-3.2.4.tar.gz
cd zeromq-3.2.4
  • Turn off Werror. Edit configure by setting libzmq_werror="yes" to no.
# By default compiling with -Werror except OSX.
libzmq_werror="no"
  • Configure, and build. We turn off libsodium since we haven't built it.
./configure --enable-static --disable-shared --host=arm-linux-androideabi \
    --prefix=$PREFIX LDFLAGS="-L$OUTPUT_DIR/lib \
    -L$ANDROID_STANDALONE_TOOLCHAIN/arm-linux-androideabi/lib/armv7-a \
    -lgnustl_shared" CPPFLAGS="-fPIC -I$PREFIX/include \
    -I$ANDROID_STANDALONE_TOOLCHAIN/include/c++/4.8/arm-linux-androideabi/armv7-a" \
    LIBS="-lgcc" --with-libsodium=no
make
make install
  • Get the C++ ZMQ header that doesn't come with the normal (C-only) source:
wget -O $PREFIX/include/zmq.hpp https://raw.githubusercontent.com/zeromq/cppzmq/master/zmq.hpp

Support for Radio Front-Ends

Once again, from the previous steps in building up the GNU Radio support, I set up a few environmental variables:

Make sure that ANDROID_STANDALONE_TOOLCHAIN points to the toolchain project we've created; PREFIX points to where we'll install everything; and TOOLCHAIN points to the Android Toolchain cmake file that comes with GNU Radio. These are the examples from what we have been using:

export ANDROID_NDK=/opt/ndk
export PATH=$PATH:$ANDROID_NDK
export PREFIX=/opt/grandroid
export TOOLCHAIN=/cmake/Toolchains/AndroidToolchain.cmake
export ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain

libusb

Clone a forked version of the libusb repo that includes a patch for an Android 5 selinux problem:

git clone https://github.com/trondeau/libusb
cd libusb
git checkout v1.0.19-and5

Now build the libusb-1.0.so from the JNI and make links to it in our prefix:

cd android/jni
ndk-build
ln -s /android/libs/armeabi-v7a/libusb1.0.so $PREFIX/lib
ln -s /libusb $PREFIX/include

RTL-SDR

Clone the trondeau's forked repo that includes a set of patches for Android 5 selinux issues and to work with our patched libusb.

git clone https://github.com/trondeau/rtl-sdr.git
cd rtl-sdr
git checkout android5

Now build and install using the CMake toolchain:

mkdir build; cd build
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX \
  -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN \
  -DLIBUSB_INCLUDE_DIR=$PREFIX/include/libusb \
  -DLIBUSB_LIBRARIES=$PREFIX/lib/libusb1.0.so \
  ../

Run this twice. The first time produces an error, but the second time succeeds. Seems to work, though it's probably not the "right thing." (NOTE: add -DTHREADS_PTHREAD_ARG=0. See /opt/code/rtl-sdr/build/TryRunResults.cmake for details. Gist is THREADS_PTHREAD_ARG would be the return code of a demo example)

make
make install

UHD

The UHD library requires libusb, so make sure that is built first.

The current support for UHD is still experimental. It only works with a B200 or a B210. The UHD driver will load the firmware and FPGA images onto the device, but there are issues still with permissions. Because the firmware changes how the USRP looks to the OS, the OS needs to get the permissions from the user again. In my test apps, I (annoyingly) run it once to load the firmware, kill the app, and run it a second time. It asks for USB permissions both times, but the second time it will load the FPGA image and start running. So long as the device is powered on, it will keep the firmware and FPGA images so we don't have to do this again. If you have access to wall power, this can help make sure that the device stays programmed.

NOTE When testing on a Nexus 7 tablet, the USB OTG is not able to provide enough power to the B210. Wall power is required for operating this device. The B200 will run off of just the USB cable. Other devices might provide different results.

If you have any issues loading the firmware and/or FPGA images, it might be easier to pre-load them onto the device. To do this, make sure it's plugged into wall power, connect it to a computer, and run uhd_usrp_probe that will load both the firmware and FPGA files. Then you can reconnect the USRP to the Android device's USB port and continue from there.

git clone https://github.com/trondeau/uhd.git
cd uhd/host
git checkout android
mkdir build; cd build
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX \
      -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN \
      -DBOOST_ROOT=$PREFIX \
      -DLIBUSB_INCLUDE_DIRS=$PREFIX/include/libusb \
      -DLIBUSB_LIBRARIES=$PREFIX/lib/libusb1.0.so \
      -DPYTHON_EXECUTABLE=/usr/bin/python \
      -DENABLE_STATIC_LIBS=True -DENABLE_USRP1=False \
      -DENABLE_USRP2=False -DENABLE_B100=False \
      -DENABLE_X300=False -DENABLE_OCTOCLOCK=False \
      -DENABLE_TESTS=False -DENABLE_ORC=False \
      ../
make
make install

Other Info / Older and Obsolete Stuff

Older Boost (1.55) for Android

Originally, we had found this Boost-for-Android repo on github that made it pretty easy to build Android 1.55. More recent versions of Boost, 1.58 at least, have direct support for building Android, and so we have updated the directions. We are keeping these instructions here in case you still wish to use this older method.

Follow these steps:

git clone https://github.com/wuqian/Boost-for-Android.git
  • In build-android.sh:
    • Change BOOST_VER2=55 (line 31)
    • Add "10d (64-bit)" to build-android.sh (line 260)
    • change to using the 4.8 toolchain (line 261)
  • Building Boost 1.55
cd Boost-for-Android
./build-android.sh --prefix=$PREFIX
ln -s $PREFIX/include/boost-1_55/boost $PREFIX/include/boost
for f in `ls $PREFIX/lib/libboost*.a`; do ln -s $f ${f%-gcc-mt-1_55.*}.a; done
  • In the installed thread_data.hpp file,comment out the include <asm/page.h>
#if defined(__ANDROID__)
//#include  // http://code.google.com/p/android/issues/detail?id=39983
#endif
  • Found: $PREFIX/include/boost/thread/pthread/thread_data.hpp
  • Looks like a previous problem with an Andriod NDK no longer applicable to the version we're using.