The Docker/Buildroot toolchain produces 32-bit ARM binaries but the RG35XX target runs a 64-bit aarch64 userland. Add docs/TOOLCHAIN.md covering the full pipeline, config details, patches, and three possible approaches to fix the architecture mismatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.7 KiB
Cross-Compilation Toolchain
This document describes the current Docker/Buildroot cross-compilation toolchain, the architecture mismatch with the target device, and possible approaches to fix it.
Current Toolchain Architecture
Pipeline Overview
The toolchain is built via a Docker container defined in docker/:
docker/Dockerfile— Debian Buster (EOL) base image, installs build dependencies (bc, build-essential, cmake, git, etc.), copies support scripts, runsbuild-toolchain.sh, sourcessetup-env.shin.bashrcdocker/support/build-toolchain.sh— Downloads Buildroot 2017.11, applies patches, loadsrg35xx-buildroot-2017.11.config, runsmake world. If a pre-builtrg35xx-toolchain.tar.xzexists, extracts that instead of rebuilding.docker/support/install-toolchain.sh— Copies host tools frombuildroot/output/host/usr/to/opt/rg35xx-toolchain/usr/, copieshwcap.hinto the sysroot, runsrelocate-sdk.shto fix embedded paths.docker/support/setup-env.sh— Sets environment variables:export PATH="/opt/rg35xx-toolchain/usr/bin:${PATH}:/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/bin" export CROSS_COMPILE=/opt/rg35xx-toolchain/usr/bin/arm-buildroot-linux-gnueabihf- export PREFIX=/opt/rg35xx-toolchain/usr/arm-buildroot-linux-gnueabihf/sysroot/usr export UNION_PLATFORM=rg35xxdocker/support/package-toolchain.sh— Archives/opt/rg35xx-toolchainasrg35xx-toolchain.tar.xzfor caching.docker/support/relocate-sdk.sh— Rewrites hardcoded paths in SDK text files so the toolchain can live at a different filesystem location.docker/Makefile—make shellbuilds the Docker image (tagrg35xx-toolchain) and drops into an interactive bash shell with./workspacemounted at/root/workspace.
How the Main Makefile Uses It
The project Makefile detects PREFIX to switch modes:
- Cross-compile (PREFIX set): uses
-I$(PREFIX)/includeand-L$(PREFIX)/libdirectly. - Native (no PREFIX): uses
pkg-configto find SDL2/FFmpeg.
CROSS_COMPILE is prepended to gcc to select the cross-compiler (e.g. arm-buildroot-linux-gnueabihf-gcc).
The Problem
The Buildroot config targets 32-bit ARM Cortex-A9 but the Anbernic RG35XX runs a 64-bit aarch64 userland.
The cross-compiled binary is ELF 32-bit LSB executable, ARM, EABI5 while the device only has 64-bit aarch64 shared libraries. The binary cannot run — the dynamic linker and every .so it needs are the wrong architecture.
Key mismatched settings in the config:
| Setting | Current Value | Needed |
|---|---|---|
BR2_arm |
y (32-bit ARM) |
BR2_aarch64=y |
BR2_cortex_a9 |
y |
Cortex-A53 or similar |
BR2_ARM_EABIHF |
y |
LP64 ABI |
BR2_GCC_TARGET_ABI |
aapcs-linux |
lp64 |
BR2_GCC_TARGET_CPU |
cortex-a9 |
cortex-a53 |
BR2_GCC_TARGET_FPU |
neon |
(implicit in AArch64) |
| Sysroot triple | arm-buildroot-linux-gnueabihf |
aarch64-buildroot-linux-gnu |
Buildroot Config Details
File: docker/support/rg35xx-buildroot-2017.11.config
Architecture
BR2_arm=y
BR2_cortex_a9=y
BR2_ARM_EABIHF=y
BR2_ARM_FPU_NEON=y
BR2_ARM_INSTRUCTIONS_THUMB2=y
Toolchain Versions
| Component | Version |
|---|---|
| Buildroot | 2017.11 |
| GCC | 7.2.0 (BR2_GCC_VERSION_7_X) |
| Binutils | 2.28.1 (BR2_BINUTILS_VERSION_2_28_X) |
| Kernel headers | 3.10.108 (BR2_KERNEL_HEADERS_3_10) |
| glibc | 2.28 (BR2_TOOLCHAIN_BUILDROOT_GLIBC) |
Packages Enabled
- FFmpeg — all encoders, decoders, muxers, demuxers, parsers, protocols, filters; nonfree codecs enabled
- SDL2 — with KMS/DRM support, SDL2_image (PNG), SDL2_mixer, SDL2_net, SDL2_TTF
- SDL 1.2 (legacy) — with framebuffer backend, SDL_image, SDL_TTF
- ALSA — PCM, mixer, raw MIDI, HWDEP, sequencer plugins
- Graphics — FreeType, libjpeg (SIMD), libpng, libdrm, zlib
- Utilities — evtest, tree
Other Settings
- Optimization: size (
BR2_OPTIMIZE_S) - LTO and OpenMP enabled
- No stack smashing protection (
BR2_SSP_NONE) - Shared libraries only (
BR2_SHARED_LIBS) - Extra libs: libasan (
BR2_TOOLCHAIN_EXTRA_LIBS="libasan")
Patches Applied
All patches live in docker/support/patches/.
glibc 2.28 Compatibility Fixes
Three packages fail to build against glibc 2.28 because _IO_ftrylockfile was removed from the private API:
- bison (
package/bison/110-glibc-change-work-around.patch) — replaces_IO_ftrylockfilechecks with_IO_EOF_SEEN, adds_IO_IN_BACKUPmacro - m4 (
package/m4/000-fix-fseeko.patch) — same pattern across fflush.c, fpending.c, fpurge.c, freadahead.c, freading.c, fseeko.c, stdio-impl.h - e2fsprogs (
package/e2fsprogs/000-fix-gcc-conflict.patch) — renamescopy_file_range()tocopy_file_chunk()to avoid conflict with the new glibc function of the same name
SDL 1.2 RG35XX Patches
package/sdl/0003-rg35xx-sdlk-additions.patch— adds 9 RG35XX-specific scancodes and key mappings (KATAKANA, HIRAGANA, HENKAN, POWER, etc.) to SDL 1.2's framebuffer input driver. Not relevant for SDL2.package/sdl/0004-modernize-SDL_FBCON_DONT_CLEAR.patch— changes framebuffer clearing behavior: skips palette restoration and pixel clearing whendontClearPixelsis set orSDL_DOUBLEBUFis used. Not relevant for SDL2.
Buildroot Framework Patch
toolchain-expose-BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS-for-all-toolchain-types-2017.11.1.diff— backportsBR2_TOOLCHAIN_EXTRA_LIBSconfig option so it works with the internal Buildroot toolchain (not just external). Required for thelibasanextra lib.
Possible Approaches
A: Replace Buildroot with Debian Multiarch (Recommended)
Use apt with dpkg --add-architecture arm64 inside a Debian Docker container to install aarch64 cross-compiler and libraries directly from Debian repos.
Pros:
- Modern toolchain (GCC 12+, recent glibc, recent FFmpeg/SDL2)
- No Buildroot config to maintain, no patches needed
- Fast setup — apt install instead of multi-hour Buildroot build
- Libraries match what's on the device (Debian-based firmware)
Cons:
- Library versions must match the device's firmware (or ship them)
- Less control over exact build options
Outline:
FROM debian:bookworm
RUN dpkg --add-architecture arm64 && apt-get update && \
apt-get install -y gcc-aarch64-linux-gnu \
libsdl2-dev:arm64 libsdl2-image-dev:arm64 \
libavformat-dev:arm64 libavcodec-dev:arm64 \
libavutil-dev:arm64 libswresample-dev:arm64
B: Fix Buildroot Config for aarch64
Stay with Buildroot but update the defconfig to target aarch64 instead of ARM.
Pros:
- Minimal conceptual change — same pipeline, just different arch settings
- Full control over every library version
Cons:
- Buildroot 2017.11 is ancient and may not have good aarch64 support
- Would likely need to upgrade Buildroot to a modern release (2024.x)
- Upgrading Buildroot may break existing patches or require new ones
- Multi-hour rebuild from scratch
- Still maintaining a custom Buildroot config long-term
Key config changes needed:
BR2_aarch64=y
# Remove all BR2_arm, BR2_cortex_a9, BR2_ARM_* settings
# Update kernel headers to match device
C: Skip Docker, Cross-Compile on Host Directly
Install aarch64-linux-gnu-gcc and aarch64 libraries on the host system (e.g. Arch Linux) without Docker.
Pros:
- Simplest setup — just
pacman -S aarch64-linux-gnu-gccand aarch64 libs - No Docker overhead
- Fast iteration
Cons:
- Not reproducible across machines without documenting exact packages
- Harder to match device library versions
- Host distro package availability varies (Arch has good cross-compile support, others may not)