ARM Crosscompiler

Wenn man jetzt schon dank MinGW unter Linux seine Windows Programme kompilieren lassen kann, warum soll man denn nicht auch unter X86 PCs die ARM Binaries für den Raspberry PI erstellen lassen können?

Und mit Debian geht das echt einfach … und am Ende klappt das Ganze sogar unter WSL in Windows 10.


Wenn man nach “Raspberry Pi crosscompile” sucht, findet man einige Beiträge, die einen alle Tools im Internet zusammentragen lassen, dann noch alle Raspberry Header und Libs per GIT klonen lassen, um endlich einen Build zu starten.

Zumindest seit Debian 9 (oder Ubuntu 18.04) geht das viel einfacher:

Debian: crossbuild-essential-armhf

Die Paketinstallation
apt install crossbuild-essential-armhf -y
legt den GCC ARM Compiler und die meisten notwendigen Libs in /usr/arm-linux-gnueabihf ab.
Und mit einer .cmake Toolchain-Datei leitet man einfach die Aufrufe zum ARM Compiler um.

CMake: Toolchain Datei

Meine CMake Toolchain-Datei arm-linux-gnueabihf.cmake sieht in etwa so aus:

 1set(CMAKE_SYSTEM_NAME "Linux")
 2set(CMAKE_SYSTEM_PROCESSOR "arm")
 3set(TOOLCHAIN_PREFIX "arm-linux-gnueabihf")
 4
 5set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}-gcc")
 6set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}-g++")
 7
 8set(CMAKE_CROSSCOMPILING TRUE)
 9set(THREADS_PTHREAD_ARG "2" CACHE STRING "THREADS_PTHREAD_ARG" FORCE)
10
11set(CMAKE_FIND_ROOT_PATH "/usr/${TOOLCHAIN_PREFIX}")
12
13set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
14set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
15set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Ich brauchte den Eintrag THREADS_PTHREAD_ARG, da ansonsten der Fehler:

CMake Error: TRY_RUN() invoked in cross-compiling mode, please set the following cache variables appropriately: THREADS_PTHREAD_ARG (advanced)

auftritt.

Schon kann man CMake mit dem Kommando:

1cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/arm-linux-gnueabihf.cmake /path/to/sources

ausführen und erhält am Ende ARMv7 Binaries.

Diese wurden zu meinem alten Raspberry Pi 2B kopiert und dieser konnte sie sofort und ohne Probleme ausführen.

Andere Plattformen

Nachdem der Raspberry Pi Zero und 1 den ARMv6 Befehlssatz nutzen, der 2er den ARMv7 und die späteren ARMv8, macht es Sinn, diese Info der Toolchain mitzugeben, damit optimierter Code für die gewünschte Plattform rauskommt.

Eine tolle Übersicht hat fm4dd unter github.com eingestellt.

Mit ein paar Zusatzzeilen

1#set(RPI_FLAGS "-mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp" CACHE STRING "RPi Zero/1")
2set(RPI_FLAGS "-mcpu=cortex-a7 -mfloat-abi=hard -mfpu=neon-vfpv4" CACHE STRING "RPi 2")
3#set(RPI_FLAGS "-mcpu=cortex-a53 -mfloat-abi=hard -mfpu=neon-fp-armv8 -mneon-for-64bits" CACHE STRING "RPi 3")
4#set(RPI_FLAGS "-mcpu=cortex-a72 -mfloat-abi=hard -mfpu=neon-fp-armv8 -mneon-for-64bits" CACHE STRING "RPi 4")
5
6set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RPI_FLAGS}" CACHE STRING "C CPU Flags")
7set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RPI_FLAGS}" CACHE STRING "C++ CPU Flags")

lässt sich der generierte Code auf den gewünschten Raspberry Pi anpassen.

Leider ist der ARMv6 Befehlssatz des RPi Zero und 1 nicht mehr in den Standardcompilern enthalten und man bekommt Fehler wie:

sorry, unimplemented: Thumb-1 hard-float VFP ABI

Aber auch hier hat ein pfiffiger User eine Lösung mit einer angepassten Toolchain eingestellt: github.com/Pro/raspi-toolchain

Fazit

Mit WSL und Ubuntu oder Debian kann ich nun also GATE Builds für die ARM Plattform bauen lassen und während mein Raspberry 4 oder 2 schon ganz schön lange rechnen müsste, schafft das mein Intel i5 in unter einer Minute.

Vermutlich enthalten ältere Distros von vor 2015 ebenfalls noch den ARMv6 Befehlssatz, aber mir reicht der ARMv7 Teil vollkommen für Tests aus.

Sollte ich also wirklich mal einen RPi Zero Build brauchen, werde ich die alternative Toolchain bemühen müssen, oder direkt am R-PI bauen lassen.

Jedenfalls wieder mal “eine coole Sache”, dass ich nun eine weitere Plattform problemfrei abhaken kann.

Es gibt zwar meines Wissens auch eine native Windows-Toolchain für ARM-Linux, doch wozu die Mühe machen, wenn es mit WSL so unkompliziert läuft.