-
-
Notifications
You must be signed in to change notification settings - Fork 104
Native Compiler: Installation Instructions
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.
- A. Prerequisites for Raspberry Pi
- B. Download Binary
-
C. Build Dummy Hello-World Project on Raspberry Pi
- 0. Setting up the directory structure
- 1. Setup Important Symlinks
- 2. Download, Extract, and Setup the Precompiled Native-Compiler Toolchain Binary
- 3. Create C++
main.cpp
File - 4. Create
PI.cmake
CMAKE File - 5. Create
CMakeLists.txt
File - 6. Configure CMAKE Project
- 7. Build Project
- 8. Run/Test our Cross-compiled Binary
- C. Advanced Information
-
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
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:
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 |
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.
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.
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
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.
Copy URL from one of Precompiled Native-compiler Toolchain version based on your Raspberry Pi Variant and OS you installed on it from Above.
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
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>
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
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;
}
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)
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)
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
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
.
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.
-
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
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.
If these binaries helped you big time, please consider supporting it. Thank you.
Also, don't forget to share your views & drop a ⭐
- Native-Compiler ARM Toolchains Guide
- Cross-Compiler ARM Toolchains Guide
- Native-Compiler 64-Bit GCC ARM64 Toolchains Guide
- Cross-Compiler 64-Bit GCC ARM64 Toolchains Guide