This is an old revision of the document!
Table of Contents
Cross Platform Development for Raspberry
Cross-development means developing and compiling programs on another platform then it intended to run upon. It is a common approach for Pi, since it’s also how Raspian is built. For quite some time I did compile Pi applications on the Pi itself. Which works quite well, but has one large drawback: performance. Being able to compile these programs on my 8 core 16GB desktop, improved compilation time enorm. And it is quite simple.
There are multiple approaches to setup a cross-compile environment. The most essential aspect is the following:
- Exact identical Linux/Debian versions on X86 build host and Raspberry runtime target
- Different Linux/Debian versions on X86 build host and Raspberry runtime target
The problem with using host-version ARM libraries
The important guideline is that the target system's ABI, headers, libraries and library versions vs. what you build against. For example:
HOST
Debian Trixie x86-64
│
│ cross compiler
▼
arm-linux-gnueabihf-gcc
│
┌───────┴────────┐
WRONG approach CORRECT approach
│ │
▼ ▼
Trixie armhf libs Bookworm Raspbian armhf libs
│ │
▼ ▼
ARM executable ARM executable
│ │
└───────┬────────┘
▼
Raspbian Bookworm
Suppose your x86 host is Debian Trixie, and you install libc6:armhf from Trixie. Your compiler might then build against something like glibc 2.41 while your Raspberry Pi's Raspbian Bookworm has glibc 2.36. Your executable may therefore acquire a dependency on a newer GLIBC symbol. For example, conceptually:
program
└── was linked against and requires GLIBC_2.41
│
▼
Raspbian Bookworm only has GLIBC_2.36
│
✗
program won't run, with errors like:
./program: /lib/arm-linux-gnueabihf/libc.so.6: version `GLIBC_2.41' not found
This is one of the most common reasons why building on a newer distribution for an older target causes trouble.
But the reverse is usually fine
Suppose:
Host: Debian Trixie Target: Raspbian Bookworm
and you use the Raspbian Bookworm sysroot.
Then:
Trixie GCC
│
▼
Raspbian Bookworm headers
+
Raspbian Bookworm libraries
│
▼
Raspbian Bookworm executable
The host's distribution version becomes much less important. You are essentially saying:
“Use this compiler, but pretend the target filesystem is this Raspbian Bookworm system.”
That's exactly what --sysroot is for.
There's another subtle reason
It isn't only the libraries that matter. The headers matter too. Suppose you compile against Trixie's headers:
/usr/include
but run on Bookworm.
You can potentially get differences in:
* API definitions * feature macros * structure definitions * constants * kernel interfaces * glibc interfaces * library-specific APIs
So the ideal relationship is:
Raspbian Bookworm
┌─────────────────┐
│ headers │
│ libraries │
│ linker files │
│ ABI │
└────────┬────────┘
│
▼
cross compiler
│
▼
your executable
That's why a target-specific sysroot is the clean solution.
One important exception
If you deliberately want to require a newer target system, that's perfectly legitimate.
For example:
Build against Trixie armhf
↓
Deploy only to Trixie armhf
No problem.
The rule is simply:
Don't build against a newer userspace than the oldest target you intend to support.
This is particularly important for glibc.
This distinction matters:
Target = Debian armhf
Debian Bookworm x86-64
↓
Debian Bookworm armhf
Excellent fit for: crossbuild-essential-armhf
Target = Raspberry Pi OS 32-bit
Debian Bookworm x86-64
↓
Raspberry Pi OS armhf
You should ideally use the actual Raspberry Pi OS sysroot/libraries. This becomes particularly important if you're linking against anything beyond libc. you want the headers and libraries corresponding to the actual target system. Otherwise you can end up with:
compile successfully
↓
link successfully
↓
copy to Pi
↓
runtime/library incompatibility
Raspberry Pi OS vs Debian armhf
One important distinction: Raspberry Pi OS vs Debian armhf
There is, however, a very important caveat for Raspberry Pi.
If your target is Raspberry Pi OS 32-bit, don't blindly assume that Debian Bookworm's armhf libraries are an exact match.
Debian itself points this out:
Raspberry Pi OS armhf can be subtly incompatible with Debian armhf.
In particular, Raspberry Pi OS/Raspbian has historically had differences in its ARM ABI/build configuration. Debian recommends using a target-specific chroot when cross-compiling packages for Raspberry Pi OS armhf. ([Debian Wiki][2])
