Skip to content

Latest commit

 

History

History
145 lines (97 loc) · 8.11 KB

SDK_cross_compile_example.md

File metadata and controls

145 lines (97 loc) · 8.11 KB

Cross Compiling the Azure IoT Hub SDK

Background

The SDK for the Azure IoT Hub was written to use the C99 standard in order to retain a high level of compatibility with hardware platforms that have not yet seen an official release of the SDK. This should ease the burden of porting the SDK code to those platforms.

One of the challenges that might be encountered though is that the platform in question is not capable of building the code. Many such platforms may require that the executables are compiled on a host with a different chipset architecture from its own. This process of building executables on a host to target a disparate platform is known as cross compiling.

Purpose of this document

This document presents an example of how to cross compile the Azure IoT Hub SDK using the make system, cmake, that is employed by the project. In this example it will demonstrate the process of cross compiling the SDK on a Debian 64-bit system targeting a Raspberry Pi. It demonstrates how one must set up the file system and the cmake options to achieve this which should assist developers attempting to cross compile for other targets.

Procedure

Version Information

The host machine is running Debian GNU/Linux 8 (jessie) amd64

The target machine is running Raspbian GNU/Linux 8 (jessie)

Note: This example was built and tested on an amd64 build of Debian on the host and will use the 64-bit version of the Raspbian toolchain. You will need to select a different target toolchain if your host is not running a 64-bit Linux operating system.

Though it may be possible to use a host machine running a variant of Windows this would likely be very complex to set up and thus is not addressed in this document.

Setting up the Build Environment

Open a terminal prompt on your host machine in the manner you prefer.

We need to acquire the SDK source code. This is available in the C SDK GitHub repository. We clone this too our host machine as follows:

cd ~
mkdir Source
cd Source
git clone https://github.com/Azure/azure-iot-sdk-c.git
cd azure-iot-sdk-c
git submodule update --init

Further information regarding this step and other set up requirements can be found in this guide. This step is only included in this document to establish the directory structure used for the rest of the example.

You might consider building the SDK for your local platform at this point simply to ensure you have all the required components. At the very least, you must ensure that the SDK's prerequisite libraries are installed on your Raspberry Pi. You can achieve this by running the script setup.sh found in azure-iot-sdk-c/build_all/linux.

In order to cross compile for a different target the first requirement is to set up an environment containing the required toolchain, system libraries and system headers that may be required to build the code. In the instance of the Raspberry Pi this is simplified by the existence of a GitHub project that has much of that work already done for us. Change to your home directory, create a new directory for the Raspberry Pi Tools and clone the project at https://github.com/raspberrypi/tools into that directory. For example:

cd ~
mkdir RPiTools
cd RPiTools
git clone https://github.com/raspberrypi/tools.git

Unfortunately, this does not give us all the files that are required to build the project. At this point you will need to copy some files from a running Raspberry Pi to your host machine. Make sure you can access your Raspberry Pi via SSH (you can enable this using raspi-config and select "9. Advanced Options". Further instructions are beyond the scope of this document).

Make sure these libraries are installed in the Raspberry Pi before proceeding.

On your host's terminal enter:

cd ~/RPiTools/tools/arm-bcm2708/\
gcc-linaro-arm-linux-gnueabihf-raspbian-x64/arm-linux-gnueabihf
rsync -rl --exclude '/usr/lib/cups/backend/vnc' --safe-links pi@<your Pi identifier>:/{lib,usr} .

In the above command replace <your Pi identifier> with the IP address of your Raspberry Pi. If you no longer have a user identity on your Raspberry Pi called pi, then you will need to substitute an existing user identity.

This command will copy many more files to your host than you actually need but, for brevity, we copy them all. If you wish, you could optimize the sync action to exclude files that are not required.

Setting up cmake to cross compile

In order to tell cmake that it is performing a cross compile we need to provide it with a toolchain file. To save us some typing and to make our whole procedure less dependent upon the current user we are going to export a value. Whilst in the same directory as above enter the following command

export RPI_ROOT=$(pwd)

You can use export -p to verify RPI_ROOT has been added to the environment.

Now we need to switch to the SDK directory tree. Enter this command

cd ~/Source/azure-iot-sdk-c/build_all/linux

Using the text editor of your choice, create a new file in this directory and call it toolchain-rpi.cmake. Into this file place the following lines

INCLUDE(CMakeForceCompiler)

SET(CMAKE_SYSTEM_NAME Linux)     # this one is important
SET(CMAKE_SYSTEM_VERSION 1)     # this one not so much

# this is the location of the amd64 toolchain targeting the Raspberry Pi
SET(CMAKE_C_COMPILER $ENV{RPI_ROOT}/../bin/arm-linux-gnueabihf-gcc)

# this is the file system root of the target
SET(CMAKE_FIND_ROOT_PATH $ENV{RPI_ROOT})

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

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

and save the toolchain file. Your cross compilation environment is now complete.

Building the SDK

The final step in the process is to run the actual build. For this you will need to be in the Linux build directory as shown above. Enter the following commands

cd ~/Source/azure-iot-sdk-c/build_all/linux
./build.sh --toolchain-file toolchain-rpi.cmake -cl --sysroot=$RPI_ROOT

This will tell cmake to build the SDK using the toolchain file toolchain-rpi.cmake. Finally, and absolutely critical is the use of the --sysroot option. Without this the compiler will fail to find required headers and libraries.

Specifying Additional Build Flags

If you need to provide additional build flags for your cross compile to function you can add further -cl parameters to the build script's command line. For example, adding -cl -v will turn on the verbose output from the compile and link process or to pass options only to the linker for example to pass -v to the linker you can use -cl Wl,-v.

See this page for a summary of available gcc flags: https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html.

Notes

These instructions have been tested on both the Raspberry Pi 2, 3 and 4.

Known Issues and Circumventions

If you encounter the error error adding symbols: DSO missing from command line try adding a reference to libdl with -cl -ldl added to your build script command line.

For Raspberry Pi 4 the following workaround is neccessary to properly link the samples with pthread. Run the following commands and recompile the Azure IoT C SDK.

cd $RPI_ROOT/usr/lib/arm-linux-gnueabihf; 
ln -s ../../../lib/arm-linux-gnueabihf/libpthread.so.0 libpthread.so

Summary

This document has demonstrated how to cross compile the Azure IoT SDK on a 64-bit Debian host targeting the Raspbian operating system.

References

https://github.com/Azure/azure-iot-sdks

https://github.com/Azure/azure-iot-sdks/blob/master/c/doc/devbox_setup.md

https://github.com/raspberrypi/tools

https://cmake.org/Wiki/CMake_Cross_Compiling

https://www.raspberrypi.org

http://stackoverflow.com/questions/19162072/installing-raspberry-pi-cross-compiler (See answer)