Skip to content

Native Compiler: Installation Instructions

Abhishek Thakur edited this page Oct 6, 2024 · 67 revisions

Raspberry Pi Toolchains Logo

Raspberry Pi 32-Bit OS : GCC Native-Compiler ARM Toolchains Setup Guide

These ARM toolchains can be used directly on any Raspberry Pi 32-bit OSes for compiling programs for it.

 

Warning

The Stretch (Debian Version 9) 32-bit/64-bit toolchains are no longer supported!

  • Buster: Used and generate code for Raspberry Pi Buster 32-bit OS (a.k.a Debian Version 10) and any equivalent OS only.
  • Bullseye: Used and generate code for Raspberry Pi Bullseye 32-bit OS (a.k.a Debian Version 11) and any equivalent OS only.
  • Bookworm: Used and generate code for Raspberry Pi Bookworm 32-bit OS (a.k.a Debian Version 12) and any equivalent OS only.

 

Important

  • These instructions are exclusively for GCC version 14.2.0 but will work with any native-compiler version available with this project.
  • These instructions are Raspberry Pi 32-Bit OS flavors specific only.

 

Table of content

 

 

A. Prerequisites for Raspberry Pi

  • Update your environment:

    sudo apt update && sudo apt dist-upgrade
  • Install Important Packages (including default gcc):

    sudo apt-get install build-essential cmake gawk gcc g++ gfortran git texinfo bison wget bzip2 libncurses-dev libssl-dev openssl zlib1g-dev

 

 

B. Download Binary

Our pre-compiled TAR-PIGZ compressed and OS-targeted GCC Toolchain binaries can easily be downloaded from the project's SourceForge Repository or by clicking the links provided in the following table:

Download Raspberry Pi GCC Toolchains

Note

  • Host OS: on which the toolchain is executed/used.
  • Target OS: for which the toolchain generates code.

Warning

The Stretch (Debian Version 9) 32-bit/64-bit toolchains are no longer supported!

Toolchains Host OS Target OS Current Status Precompiled GCC versions available
Raspberry Pi GCC Native-Compiler Toolchains (Buster) Buster 32-bit OS (Debian Version 10) only Buster 32-bit OS (Debian Version 10) only Stable/Production 13.3.0, 14.2.0
Raspberry Pi GCC Native-Compiler Toolchains (Bullseye) Bullseye 32-bit OS (Debian Version 11) only Bullseye 32-bit OS (Debian Version 11) only Stable/Production 13.3.0, 14.2.0
Raspberry Pi GCC Native-Compiler Toolchains (Bookworm) Bookworm 32-bit OS (Debian Version 12) only Bookworm 32-bit OS (Debian Version 12) only Stable/Production 13.3.0, 14.2.0

 

 

C. Build Dummy Hello-World Project on Raspberry Pi

This sections documents the complete steps to compile a working Software Binaries (Hello-World CMAKE example in this case) with CMAKE using only the Raspberry Pi 32-bit GCC Native-Compiler Toolchains available within our project.

0. Setting up the directory structure

You can use these following commands to create "cmake-test" to use as workspace for the project:

sudo mkdir ~/cmake-test
sudo mkdir ~/cmake-test/tools
sudo mkdir ~/cmake-test/build
sudo chown -R 1000:1000 ~/cmake-test
cd ~/cmake-test

Note

Ensure the last command should have changed your current directory to ~/cmake-test. 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.

1. Setup Important Symlinks

Our toolchains requires few additional symbolic links to work properly. Therefore, to create all required symbolic link reliably, we need to download SSymlinker bash script as follows:

wget https://raw.githubusercontent.com/abhiTronix/raspberry-pi-cross-compilers/refs/heads/master/utils/SSymlinker

Once it is downloaded, you just need to make it executable, and then run it for each path manually using the following commands:

sudo chmod +x SSymlinker
./SSymlinker -s /usr/include/arm-linux-gnueabihf/asm -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/gnu -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/bits -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/sys -d /usr/include
./SSymlinker -s /usr/include/arm-linux-gnueabihf/openssl -d /usr/include
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crtn.o -d /usr/lib/crtn.o
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crt1.o -d /usr/lib/crt1.o
./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crti.o -d /usr/lib/crti.o

2. Download, Extract, and Setup the Precompiled Native-Compiler Toolchain Binary

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

cd ~/cmake-test/tools

Caution

Ensure the last command should have changed your current directory to ~/cmake-test/tools now. If not, run it again.

2.1. Copy Toolchain Binary URL

Copy URL from one of Precompiled Native-compiler Toolchain version based on your Raspberry Pi Variant and OS you installed on it from Above.

2.2. Download Toolchain Binary

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

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

2.3. Extract Toolchain Binary

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

tar xf <filename e.g native-gcc-14.2.0-pi_2-3.tar.gz>

2.4. Setup Environment Variable

Warning

Make sure to run this command before running compiled binary.

Since Raspberry Pi OS 32-bit is running a older version of GLIBC binaries for Raspberry OS 32-bit missing GLIBCXX_3.4.32, we are required to add the lib folder inside our toolchain to the LD_LIBRARY_PATH path using following command:

# add libs to path
export LD_LIBRARY_PATH=~/cmake-test/tools/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/lib:$LD_LIBRARY_PATH

3. Create C++ main.cpp File

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

cd ~/cmake-test

Now for this example project, Let's try to compile and run the following C++17 code that uses an if block with init-statement (the example is a bit simple, but will show you how to compile C++17 programs):

Note

This C++ program demonstrates the use of an if statement with an init-statement, a C++17 feature that allows declaring a variable within the if condition, limiting its scope to the if-else block.

// Include necessary header files
#include <iostream>  // For input/output operations

// Using the standard namespace (Note: generally not recommended in larger projects)
using namespace std;

int main() {
    // Demonstrating an if statement with an init-statement (C++17 feature)
    // The init-statement allows you to declare and initialize a variable
    // that is scoped to the if-else block
    if (int a = 5; a < 8) {
        // This block executes if 'a' is less than 8
        cout << "Local variable a is < 8\n";
    } else {
        // This block executes if 'a' is greater than or equal to 8
        // Note: In this case, this block will never execute because 'a' is always 5
        cout << "Local variable a is >= 8\n";
    }

    // Return 0 to indicate successful program execution
    return 0;
}

4. Create PI.cmake CMAKE File

Let's create a typical cmake compiling toolchain that has content such as:

Caution

Replace Toolchain's absolute path and version with yours in following CMAKE file before saving it.

# Enable verbose output for debugging
set(CMAKE_VERBOSE_MAKEFILE ON)

# Set the target system details
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm)

# Set the path to the compilation toolchain
# WARNING: Change this path to match your toolchain location
set(tools $ENV{HOME}/cmake-test/tools/native-pi-gcc-14.2.0-1)

# Set the target architecture
set(CMAKE_LIBRARY_ARCHITECTURE arm-linux-gnueabihf)

# Configure flags for linking and compiling
set(common_flags "-fPIC -Wl,-rpath-link,/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} -L/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${common_flags}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${common_flags}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${common_flags}")

# Set the prefix for the compiler binaries
set(BIN_PREFIX ${tools}/bin/arm-linux-gnueabihf)
# Set the version for the compiler binaries
# WARNING: Change this version to match your toolchain
set(BIN_VERSION "14.2.0")

# Configure the compiler tools
set(CMAKE_C_COMPILER ${BIN_PREFIX}-gcc-${BIN_VERSION})
set(CMAKE_CXX_COMPILER ${BIN_PREFIX}-g++-${BIN_VERSION})
set(CMAKE_Fortran_COMPILER ${BIN_PREFIX}-gfortran-${BIN_VERSION})

# Configure additional compiler tools
set(CMAKE_LINKER ${BIN_PREFIX}-ld-${BIN_VERSION} CACHE STRING "Set the compiler tool LD" FORCE)
set(CMAKE_AR ${BIN_PREFIX}-ar-${BIN_VERSION} CACHE STRING "Set the compiler tool AR" FORCE)
set(CMAKE_NM ${BIN_PREFIX}-nm-${BIN_VERSION} CACHE STRING "Set the compiler tool NM" FORCE)
set(CMAKE_OBJCOPY ${BIN_PREFIX}-objcopy-${BIN_VERSION} CACHE STRING "Set the compiler tool OBJCOPY" FORCE)
set(CMAKE_OBJDUMP ${BIN_PREFIX}-objdump-${BIN_VERSION} CACHE STRING "Set the compiler tool OBJDUMP" FORCE)
set(CMAKE_RANLIB ${BIN_PREFIX}-ranlib-${BIN_VERSION} CACHE STRING "Set the compiler tool RANLIB" FORCE)
set(CMAKE_STRIP ${BIN_PREFIX}-strip-${BIN_VERSION} CACHE STRING "Set the compiler tool STRIP" FORCE)

# Configure the behavior for finding programs, libraries, and include files
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_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

5. Create CMakeLists.txt File

Finally create a suitable project name (for e.g. cmake_hello_world_test) in CMakeLists.txt file:

# Specify the minimum version of CMake required
cmake_minimum_required(VERSION 3.10)

# Define the project name
project(cmake_hello_world_test)

# Enable verbose output during the build process
# This is useful for debugging build issues
set(CMAKE_VERBOSE_MAKEFILE ON)

# Set the C++ standard to C++17
# This ensures that C++17 features are available for the project
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Define the executable target
# This creates an executable named 'cmake_hello_world_test' from the 'main.cpp' source file
add_executable(cmake_hello_world_test main.cpp)

# Optional: Add include directories if needed
# include_directories(include)

# Optional: Link libraries if needed
# target_link_libraries(cmake_hello_world_test some_library)

# Optional: Set compile options if needed
# target_compile_options(cmake_hello_world_test PRIVATE -Wall -Wextra)

6. Configure CMAKE Project

Let's move into the build directory for further steps, as we don't want to build within that source directory as its crowded, so we will access it from within this this directory:

cd ~/cmake-test/build

Caution

Ensure you are still in the ~/cmake-test/build directory.

Finally, Now we can configure our Hello-World CMAKE Project as follows:

cmake -DCMAKE_TOOLCHAIN_FILE=~/cmake-test/PI.cmake  -DCMAKE_BUILD_TYPE=Debug ..

Important

If you get error like CMake Error at ...... (file): file failed to open for writing (No such file or directory). Then it is a permission issue and can be fixed using command:

sudo chown -R 1000:1000 ~/cmake-test

7. Build Project

Our build has been configured now, and it is time to actually build the source files, and run the following command:

make -j$(nproc)

Note

The -j$(nproc) option indicates that the job should be spread into multiple threads and run in parallel on available cores.

and your compiled binary cmake_hello_world_test will be available at ~/cmake-test/build.

8. Run/Test our Cross-compiled Binary

Let's move into the Raspberry Pi's home directory where we copied our compiled binary cmake_hello_world_test, and then run it:

# move into build directory
~/cmake-test/build

# run the compiled binary
./cmake_hello_world_test

Check output and it should look something as follows:

$ ./cmake_hello_world_test
Local variable a is < 8

The Local variable a is < 8 output indicates the compilation and if statement with an init-statement (C++17 feature) worked correctly.

 

 

C. Advanced Information

C1: Permanent Installation of Native Binaries

  • Extraction: Extract using tar terminal command as follows:

    tar xf <filename e.g native-gcc-14.2.0-pi_2-3.tar.gz>
  • Configuring: Move extracted folder to any location (for e.g. /opt) by using following command:

    sudo mv <extracted folder-name e.g native-pi-gcc-14.2.0-1> /opt
  • Linking: Properly link Path/Environment Variables permanently with either of the following given methods:

    • Appending variables to your .profile: (Recommended)

       echo 'export PATH=/opt/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/bin:$PATH' >> .profile  
       echo 'export LD_LIBRARY_PATH=/opt/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/lib:$LD_LIBRARY_PATH' >> .profile
       echo 'export CC="gcc-14.2.0"' >> .profile
       echo 'export CXX="g++-14.2.0"' >> .profile
       echo 'export CPP="cpp-14.2.0"' >> .profile
       echo 'export FC="gfortran-14.2.0"' >> .profile
       echo 'export AR="gcc-ar-14.2.0"' >> .profile
       echo 'export RANLIB="gcc-ranlib-14.2.0"' >> .profile
       source .profile
    • Appending variables to your .bashrc: ⚠️ Some Linux users reported some trouble with configuring path variables at .profile that doesn't seem to work for them. If you encounter a similar problem, try setting/configure by adding paths to your .bashrc file instead of as follows:

       echo 'export PATH=/opt/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/bin:$PATH' >> .bashrc
       echo 'export LD_LIBRARY_PATH=/opt/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/lib:$LD_LIBRARY_PATH' >> .bashrc
       echo 'export CC="gcc-14.2.0"' >> .bashrc
       echo 'export CXX="g++-14.2.0"' >> .bashrc
       echo 'export CPP="cpp-14.2.0"' >> .bashrc
       echo 'export FC="gfortran-14.2.0"' >> .bashrc
       echo 'export AR="gcc-ar-14.2.0"' >> .bashrc
       echo 'export RANLIB="gcc-ranlib-14.2.0"' >> .bashrc
       source .bashrc
  • Handling Symlinks: Our toolchains requires few additional symbolic links to work properly. Therefore, to create all required symbolic link reliably, we need to download SSymlinker bash script as follows:

    wget https://raw.githubusercontent.com/abhiTronix/raspberry-pi-cross-compilers/refs/heads/master/utils/SSymlinker

    Once it is downloaded, you just need to make it executable, and then run it for each path manually using the following commands:

    sudo chmod +x SSymlinker
    ./SSymlinker -s /usr/include/arm-linux-gnueabihf/asm -d /usr/include
    ./SSymlinker -s /usr/include/arm-linux-gnueabihf/gnu -d /usr/include
    ./SSymlinker -s /usr/include/arm-linux-gnueabihf/bits -d /usr/include
    ./SSymlinker -s /usr/include/arm-linux-gnueabihf/sys -d /usr/include
    ./SSymlinker -s /usr/include/arm-linux-gnueabihf/openssl -d /usr/include
    ./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crtn.o -d /usr/lib/crtn.o
    ./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crt1.o -d /usr/lib/crt1.o
    ./SSymlinker -s /usr/lib/arm-linux-gnueabihf/crti.o -d /usr/lib/crti.o

C2: Enable Link-time-optimization (LTO)

To fully implement LTO in your build process, you would typically add these flags to your build configuration or Makefile:

Caution

Replace Toolchain's absolute path with yours in following CMAKE file before saving it.

 GCCPATH="/<extracted folder-name e.g native-pi-gcc-14.2.0-1>/libexec/gcc/arm-linux-gnueabihf/14.2.0"
 ARFLAGS += "--plugin $GCCPATH/liblto_plugin.so"
 RANLIBFLAGS += "--plugin $GCCPATH/liblto_plugin.so"
 CFLAGS += "-flto=$(nproc) -fno-fat-lto-objects"
 CXXFLAGS += "-flto=$(nproc) -fno-fat-lto-objects"
 LDFLAGS += "-flto=$(nproc) -fno-fat-lto-objects"

Note

The ARFLAGS and RANLIBFLAGS are exported with the path to the LTO plugin, allowing the archiver and ranlib to work with LTO objects.

Clone this wiki locally