From b1c72ef8768f22ebb5097624ec7707760096f6a4 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 13 Feb 2026 13:04:12 +0100 Subject: [PATCH] Document cross-compilation toolchain findings and aarch64 mismatch 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 --- CLAUDE.md | 1 + docs/TOOLCHAIN.md | 174 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 docs/TOOLCHAIN.md diff --git a/CLAUDE.md b/CLAUDE.md index b7165ad..486e826 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,6 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co SDLamp2 is a simple SDL2-based audio player written in C, designed for a child to use. It plays long m4a/mp3 files (fairy tale cassette rips) with a cassette-player-like UI: rewind, stop, play, fast-forward, next tape. Inspired by Winamp. See `docs/sdlamp2-fsd.md` for the full functional specification and changelog. +See `docs/TOOLCHAIN.md` for cross-compilation toolchain details and the aarch64 migration plan. ## Build and Run diff --git a/docs/TOOLCHAIN.md b/docs/TOOLCHAIN.md new file mode 100644 index 0000000..3afb66c --- /dev/null +++ b/docs/TOOLCHAIN.md @@ -0,0 +1,174 @@ +# 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/`: + +1. **`docker/Dockerfile`** — Debian Buster (EOL) base image, installs build dependencies (bc, build-essential, cmake, git, etc.), copies support scripts, runs `build-toolchain.sh`, sources `setup-env.sh` in `.bashrc` +2. **`docker/support/build-toolchain.sh`** — Downloads Buildroot 2017.11, applies patches, loads `rg35xx-buildroot-2017.11.config`, runs `make world`. If a pre-built `rg35xx-toolchain.tar.xz` exists, extracts that instead of rebuilding. +3. **`docker/support/install-toolchain.sh`** — Copies host tools from `buildroot/output/host/usr/` to `/opt/rg35xx-toolchain/usr/`, copies `hwcap.h` into the sysroot, runs `relocate-sdk.sh` to fix embedded paths. +4. **`docker/support/setup-env.sh`** — Sets environment variables: + ```sh + 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=rg35xx + ``` +5. **`docker/support/package-toolchain.sh`** — Archives `/opt/rg35xx-toolchain` as `rg35xx-toolchain.tar.xz` for caching. +6. **`docker/support/relocate-sdk.sh`** — Rewrites hardcoded paths in SDK text files so the toolchain can live at a different filesystem location. +7. **`docker/Makefile`** — `make shell` builds the Docker image (tag `rg35xx-toolchain`) and drops into an interactive bash shell with `./workspace` mounted at `/root/workspace`. + +### How the Main Makefile Uses It + +The project `Makefile` detects `PREFIX` to switch modes: + +- **Cross-compile** (PREFIX set): uses `-I$(PREFIX)/include` and `-L$(PREFIX)/lib` directly. +- **Native** (no PREFIX): uses `pkg-config` to 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_ftrylockfile` checks with `_IO_EOF_SEEN`, adds `_IO_IN_BACKUP` macro +- **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`) — renames `copy_file_range()` to `copy_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 when `dontClearPixels` is set or `SDL_DOUBLEBUF` is used. **Not relevant for SDL2.** + +### Buildroot Framework Patch + +- **`toolchain-expose-BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS-for-all-toolchain-types-2017.11.1.diff`** — backports `BR2_TOOLCHAIN_EXTRA_LIBS` config option so it works with the internal Buildroot toolchain (not just external). Required for the `libasan` extra 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:** +```dockerfile +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-gcc` and 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)