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
Compatibility rule
Build against the oldest operating-system release and CPU that the resulting binary must support.
Do not link a Bookworm target against Trixie ARM libraries. Doing so can create dependencies on newer glibc or library symbols that are unavailable on the Bookworm target.
For example:
Incorrect: Trixie compiler + Trixie armhf libraries -> Bookworm target Correct: Trixie compiler + Bookworm armhf sysroot -> Bookworm target
The problem with different host and target 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:
".../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. 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.
But the reverse is usually fine
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 simple: Don't build against a newer userspace than the oldest target you intend to support. This is particularly important for glibc.
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])
