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

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

Setup for Identical Debian versions

crossbuild-essential-armhf

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.1788379791.txt.gz · Last modified: by oscar