User Tools

Site Tools


raspberry:cross-platform-compile:cross-compile-overview

This is an old revision of the document!


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:

  1. Exact identical Linux/Debian versions on X86 build host and Raspberry runtime target
  2. Different Linux/Debian versions on X86 build host and Raspberry runtime target

crossbuild-essential-armhf

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

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.

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])

Links

raspberry/cross-platform-compile/cross-compile-overview.1788380911.txt.gz · Last modified: by oscar