Cross compiling autotools projects for the Raspberry Pi

2016-10-13

There is a lot of information on the internet that explains how to cross compile software for the Raspberry Pi. But this information is scattered into tiny pieces and a lot of advice is just wrong or cumbersome.

In this blog post I will explain how to cross compile most autotools projects.

Toolchain

At first we need to get a cross compile toolchain and a sysroot environment for the Raspberry Pi. Luckily the Raspberry Pi Foundation does provide both on their github profile. So we’ll can just clone them to our computer.

1
$ git clone --depth 1 https://github.com/raspberrypi/tools rpi-tools

Note that I used the attribute --depth 1 which tells git only to fetch data from the latest commit. As the tools repository is rather large this minimizes the amount of data we have to download.

We will use the arm-linux-gnueabihf cross compiler which is at the time of this the latest and seems to support all Raspberry Pi devices. The next step is to get a hold of tools the toolchain provides.

1
2
3
4
5
6
7
8
9
TOOLCHAIN_HOST="arm-linux-gnueabihf"
TOOLCHAIN_PATH="$PWD/rpi-tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin"
CPP="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-cpp"
CC="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-gcc"
CXX="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-g++"
LD="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ld"
AS="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-as"
AR="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ar"
RANLIB="${TOOLCHAIN_PATH}/${TOOLCHAIN_HOST}-ranlib"

There are more but for most projects those are sufficient. Further we need the sysroot environment for this toolchain and add it to our compiler flags.

1
2
3
4
SYSROOT=$PWD/rpi-tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/arm-linux-gnueabihf/sysroot
CFLAGS+="--sysroot=${SYSROOT}"
CPPFLAGS+="--sysroot=${SYSROOT}"
CXXFLAGS+="--sysroot=${SYSROOT}"

Cross Compiling

Any autotools project is configured with a configure script. Thus we need to provide the configure script with the tools and flags we prepared.

1
2
3
4
5
6
7
8
9
10
11
12
CONFIG_OPTS=()
CONFIG_OPTS+=("CFLAGS=${CFLAGS}")
CONFIG_OPTS+=("CPPFLAGS=${CPPFLAGS}") CONFIG_OPTS+=("CXXFLAGS=${CXXFLAGS}")
CONFIG_OPTS+=("LDFLAGS=${LDFLAGS}") CONFIG_OPTS+=("PKG_CONFIG_DIR=")
CONFIG_OPTS+=("--host=${TOOLCHAIN_HOST}")
CONFIG_OPTS+=("CPP=${CPP}")
CONFIG_OPTS+=("CC=${CC}")
CONFIG_OPTS+=("CXX=${CXX}")
CONFIG_OPTS+=("LD=${LD}")
CONFIG_OPTS+=("AS=${AS}")
CONFIG_OPTS+=("AR=${AR}")
CONFIG_OPTS+=("RANLIB=${RANLIB}")

To get the cross compiled resources we need to install them to a location of our choosing.

1
2
BUILD_PREFIX=$PWD/tmp
CONFIG_OPTS+=("--prefix=${BUILD_PREFIX}")

A lot of project use pkgconf to find dependencies. Therefore we tell autotools where to find Raspberry Pi specific pkgconf configuartions.

1
2
3
CONFIG_OPTS+=("PKG_CONFIG_DIR=")
CONFIG_OPTS+=("PKG_CONFIG_LIBDIR=${SYSROOT}/usr/lib/arm-linux-gnueabihf/pkgconfig:${SYSROOT}/usr/share/pkgconfig")
CONFIG_OPTS+=("PKG_CONFIG_SYSROOT=${SYSROOT}")

We might have to cross compile dependencies ourselves. That’s why we let pkgconf look into our install directory for dependencies as well.

1
CONFIG_OPTS+=("PKG_CONFIG_PATH=${BUILD_PREFIX}/lib/pkgconfig")

Building

Finally we can start building our project. In this example I will compile ZeroMQ’s libzmq and higher level binding czmq to demonstrate that self compiled dependencies are detected as well. If you’ve used autotools before you should be familar with the build steps. Only difference are the CONFIG_OPTS we supply.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
git clone --depth 1 https://github.com/zeromq/libzmq.git
pushd libzmq
(
./autogen.sh &&
./configure "${CONFIG_OPTS[@]}" &&
make -j4 &&
make install
) || exit 1
popd
git clone --depth 1 https://github.com/zeromq/czmq.git
pushd czmq
(
./autogen.sh &&
./configure "${CONFIG_OPTS[@]}" &&
make -j4
make install
) || exit 1
popd

Kommentare: