Skip to content

Raspberry Pi GCC Cross Compiler ARM Toolchains CMake Usage Guide

Abhishek Thakur edited this page Jan 21, 2021 · 21 revisions

Raspberry Pi Toolchains Logo

Raspberry Pi GCC Cross-Compiler ARM Toolchains CMake Usage Guide

CMake uses a toolchain of utilities to compile, link libraries and create archives, and other tasks to drive the build. The toolchain utilities available are determined by the languages enabled. In cross-compiling scenarios, a toolchain file may be specified with information about compiler and utility paths.

This guide documents the complete steps to cross-compile a Working Software Binaries (Hello World CMake example in this case) with the help of CMake for any Raspberry Pi variant/model available, using the Raspberry Pi Toolchains available with this project only.

Prerequites:

A. Hardware:

  • Host [PC/Laptop]: Any x86/x86_64 AMD/Intel machine
  • Target [Raspberry Pi]: Raspberry Pi any variant/module

B. Software:

C. Others:

  • Networking: Your Target Machine (Raspberry Pi) and Host Machine (where you cross-compiling) both MUST have Internet Access, and MUST be on SAME Network to follow these instructions.

 

Steps/Settings for Target Machine (Raspberry Pi):

1. Start from Scratch (Optional)

Important: If you just brought a new Raspberry Pi or wanted to start from scratch just follow along. Otherwise, if you already has your Raspberry Pi setup, running, and Network Ready, then just skip to step 2.

Note: This section assume you have atleast 10GB SDcard for installing Raspbian Buster OS and a Laptop/PC for uploading it.

1.1. Download Softwares & Prepare the SD card

  • Download the latest version of Raspbian (Buster) from here on your laptop/pc.
  • You will be needing an image writer to write the downloaded OS into the SD card (micro SD card in our case). So download the open-source "win32 disk imager" from here, OR you can also use Balena Etcher instead.
  • Insert the SD card into the laptop/pc and run the image writer. Once open, browse and select the downloaded Raspbian image file. Select the correct device, that is the drive representing the SD card. Note: If the drive (or device) selected is different from the SD card then the other selected drive will become corrupted. SO BE CAREFUL!
  • Once the write is complete, eject the SD card and insert it into the Raspberry Pi and turn it on. It should start booting up.
  • Please remember that after booting the Pi, there might be situations when the user credentials like the "username" and password will be asked. Raspberry Pi comes with a default username pi and password raspberry and so use it whenever it is being asked.

1.2 Set up Network

Now the you have your Raspberry Pi up and Running, its time to connect it your network with one of following ways:

2. Set up SSH

  • If you have Monitor: On the Raspberry Pi terminal, type: sudo raspi-config and menu should pop up on your terminal. To enable SSH, go to: Interfacing Options -> SSH -> Yes, and Click OK to enable it. Choose Finish finally and exit.

  • If you don't have Monitor: After setting up the network, if you don't have monitor or you operating it remotely. Then, enable SSH by just taking out your SD card, and hook it your computer, and simply create an empty file called ssh in the /boot/parition path inside SD card. Now insert back SD card into the Raspberry Pi.

3. Open Terminal

  • From another Laptop/PC using SSH: To connect to your Pi from a different computer, copy and paste the following command into the terminal window but replace 192.160.1.47 with the IP address of the Raspberry Pi. Use Ctrl + Shift + V to paste in the terminal.

    ssh pi@192.168.1.47 

    It will ask for password, and if not changed, it is default (raspberry), and so use it whenever it is being asked.

    Note: It is possible to configure your Raspberry Pi to allow access from another computer without needing to provide a password each time you connect. For more details, see here.

  • On Raspberry Pi directly with a Monitor: Just search "Terminal" and click on it.

4. Enable Development Sources

You need to edit your sources list to enable development sources. To do this, enter the following command into pi terminal:

sudo nano /etc/apt/sources.list

In the nano text editor, uncomment the following line by removing the # character from following line:

deb-src http://raspbian.raspberrypi.org/raspbian/ buster main contrib non-free rpi

When done, press Ctrl+O and then ENTER to quit.

5. Update the system

Run the following commands in terminal to update the system

sudo apt update
sudo apt dist-upgrade

6. Enable rsync with elevated rights

Later in this guide, we will be using the rsync command to sync files between the Host PC/Laptop and the Raspberry Pi. For some of these files, root rights (i.e. sudo) is required internally.

You can do this with a single terminal command as follows:

echo "$USER ALL=NOPASSWD:$(which rsync)" | sudo tee --append /etc/sudoers

That's it. Now rsync should be setup to run with sudo if needed.

7. Install the important Development Packages

Run the following commands in Raspberry Pi terminal to install the required packages:

sudo apt install build-essential cmake unzip pkg-config gfortran

Note: Make sure to install additional packages based on software you cross-compiling with CMAKE.

That's it for Raspberry Pi setup.

 

 

Steps/Settings for Host Machine (PC/Laptop)

Now Raspberry Pi Side all setup, Let's focus on commands for our Host Machine, i.e. PC/Laptop, where you going to cross-compile software binaries (Hello world application in this case) for your Raspberry Pi.

Important: Make sure your Raspberry Pi and this Host machine (where you cross-compiling) MUST be on the SAME Network.

1. Update the Host Machine

First of all, Run the following commands to update your system and install important dependancies:

sudo apt update
sudo apt dist-upgrade
sudo apt install build-essential cmake unzip gfortran
sudo apt install gcc git bison python gperf pkg-config gdb-multiarch wget
sudo apt-get -y install gcc g++ gperf flex texinfo gawk bison openssl pigz libncurses-dev autoconf automake tar figlet

2. Setting up the directory structure

You can use these following commands to create "rpi-qt" to use as workspace for building QT Binaries:

sudo mkdir ~/rpi-qt
sudo mkdir ~/rpi-qt/build
sudo mkdir ~/rpi-qt/tools
sudo mkdir ~/rpi-qt/sysroot
sudo mkdir ~/rpi-qt/sysroot/usr
sudo mkdir ~/rpi-qt/sysroot/opt
sudo chown -R 1000:1000 ~/rpi-qt
cd ~/rpi-qt

Note: Ensure the last command should have changed your current directory to ~/rpi-qt. If not, run the last line again to make sure you are inside it, as the next steps assume you're running your commands from this directory.

3. Download & Extract QT Source

A. Download Binary:

Now, we can download the Latest source files for QT LTS (i.e. v5.15.2) by running following Terminal command to download the source files:

sudo wget http://download.qt.io/archive/qt/5.15/5.15.2/single/qt-everywhere-src-5.15.2.tar.xz

Note: You can also manually download file through browser, and place it in the ~/rpi-qt directory.

B. Extract Binary:

Extract the downloaded tar file with the following command:

sudo tar xfv qt-everywhere-src-5.15.2.tar.xz 

4. Patching QT Source

We need to slightly modify the a mkspec file within the source files to allow us to use our cross compiler. We will copy an existing directory within the source files, and modify the name of the directory and the contents of the qmake.conf file within that directory to follow the name of our compiler. To do this, run the following two command:

cp -R qt-everywhere-src-5.15.2/qtbase/mkspecs/linux-arm-gnueabi-g++ qt-everywhere-src-5.15.2/qtbase/mkspecs/linux-arm-gnueabihf-g++

sed -i -e 's/arm-linux-gnueabi-/arm-linux-gnueabihf-/g' qt-everywhere-src-5.15.2/qtbase/mkspecs/linux-arm-gnueabihf-g++/qmake.conf

5. Download & Extract the Precompiled Cross-Compiler

Let's first change into tools directory for downloading our Precompiled Cross-compiler with the following command:

cd ~/rpi-qt/tools

Note: Ensure the last command should have changed your current directory to ~/rpi-qt/tools now. If not, run it again.

A. Copy Binary URL:

Copy URL from one of following Precompiled Compressed Base-Toolchain (for maximum compatability) based on your Raspberry Pi Variant and OS you installed on it, from below:

Raspberry Pi Board Stretch(32-bit) OS Buster(32-bit) OS
Raspberry Pi - Zero/W/WH & 1 Model A/B/A+/B+ 6.3.0 8.3.0
Raspberry Pi - 2 & 3 Model A/B 6.3.0 8.3.0
Raspberry Pi - 3 & 4 Model A+/B+ & Compute 3/3-lite/3+ 6.3.0 8.3.0

Note: You can also use the latest cross-compiler binaries instead. But they are not tested.

B. Download Binary

After that, paste your copied URL and run the following command to download the Cross-compiler:

wget <Copied Binary URL goes here> #for e.g. => wget https://sourceforge.net/projects/raspberry-pi-cross-compilers/files/Raspberry%20Pi%20GCC%20Cross-Compiler%20Toolchains/Buster/GCC%208.3.0/Raspberry%20Pi%202%2C%203/cross-gcc-8.3.0-pi_2-3.tar.gz 

C. Extract Binary:

Once it is downloaded, we can extract it using the following command:

tar xf cross-gcc-*.tar.gz

6. Sync Raspberry Pi sysroot (Most Important)

First, let's move back into the rpi folder as needed for the next sections:

cd ~/rpi-qt

Now, we need to sync up our sysroot folder with the system files from the Raspberry Pi. We will be using rsync that let us sync (i.e. copy) files from the Raspberry Pi with appropriate permission onto your Host Machine, potentially saving you alot of time.

To do this, enter the following commands one by one into your terminal (change 192.168.1.47 with the IP address of your Raspberry Pi present on the same network):

  • Command 1: rsync -avz --rsync-path="sudo rsync" --delete pi@192.168.1.47:/lib sysroot
  • Command 2: rsync -avz --rsync-path="sudo rsync" --delete pi@192.168.1.47:/usr/include sysroot/usr
  • Command 3: rsync -avz --rsync-path="sudo rsync" --delete pi@192.168.1.47:/usr/lib sysroot/usr
  • Command 4: rsync -avz --rsync-path="sudo rsync" --delete pi@192.168.1.47:/opt/vc sysroot/opt

Note: Double check after each of the above commands that all the files have been copied to ~/rpi-qt/sysroot folder. There will be an information message if there were any issues.

7. Fix symbolic links

The files we copied in the previous step still have symbolic links pointing to the file system on the Raspberry Pi. We need to alter this so that they become relative links from the new sysroot directory on the host machine. We can do this with a python script by @riscv, which we can download as follows:

wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py

Once it is downloaded, you just need to make it executable and run it, using the following commands:

sudo chmod +x sysroot-relativelinks.py
./sysroot-relativelinks.py sysroot

B. Create CMAKE File:

A typical cross-compiling toolchain has content such as:

set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(tools <cross-pi-gcc-8.3.0-0>)
set(rootfs_dir <path to sysroot>)

set(CMAKE_C_COMPILER ${tools}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/arm-linux-gnueabihf-g++)

set (CMAKE_FIND_ROOT_PATH ${rootfs_dir})

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set (CMAKE_C_COMPILER_WORKS 1)
set (CMAKE_CXX_COMPILER_WORKS 1)

The CMAKE_SYSTEM_NAME is the CMake-identifier of the target platform to build for.

The CMAKE_SYSTEM_PROCESSOR is the CMake-identifier of the target architecture to build for.

The CMAKE_SYSROOT is optional, and may be specified if a sysroot is available.

The CMAKE_STAGING_PREFIX is also optional. It may be used to specify a path on the host to install to. The CMAKE_INSTALL_PREFIX is always the runtime installation location, even when cross-compiling.

The CMAKE__COMPILER variables may be set to full paths, or to names of compilers to search for in standard locations. For toolchains that do not support linking binaries without custom flags or scripts one may set the CMAKE_TRY_COMPILE_TARGET_TYPE variable to STATIC_LIBRARY to tell CMake not to try to link executables during its checks.

CMake find_* commands will look in the sysroot, and the CMAKE_FIND_ROOT_PATH entries by default in all cases, as well as looking in the host system root prefix. Although this can be controlled on a case-by-case basis, when cross-compiling, it can be useful to exclude looking in either the host or the target for particular artifacts. Generally, includes, libraries and packages should be found in the target system prefixes, whereas executables which must be run as part of the build should be found only on the host and not on the target. This is the purpose of the CMAKE_FIND_ROOT_PATH_MODE_* variables.

Clone this wiki locally