Skip to content

Linux2026 - Updates for arm64 / Raspberry Pi - #8540

Open
danoli3 wants to merge 68 commits into
openframeworks:masterfrom
danoli3:linux2026
Open

danoli3 wants to merge 68 commits into
openframeworks:masterfrom
danoli3:linux2026

Conversation

@danoli3

@danoli3 danoli3 commented Aug 15, 2026 •

Copy link
Copy Markdown
Member

Linux 2026

Draft for the makefile / download path split that matches current apothecary Linux artifacts.

Companion: openframeworks/apothecary#585 (Raspberry Pi aarch64 / armv7l / armv6l QEMU + GCC 10, all platforms green).

Lib paths (makefile + apothecary)

Target ARCH Path
Desktop x86_64 64 lib/linux/64
Generic aarch64 arm64 lib/linux/arm64
Raspberry Pi 64-bit aarch64 lib/linux/aarch64
Raspberry Pi 32-bit v7 armv7l lib/linux/armv7l
Raspberry Pi 32-bit v6 armv6l lib/linux/armv6l

Legacy flat folders (linux64, linuxarmv6l, …) stay as addon fallbacks.

Official archives (GCC 10 baseline)

openFrameworksLibs_<tag>_linux_<ARCH>_gcc10.tar.bz2

download_libs.sh now:

  • Detects Raspberry Pi so Pi 64-bit stays aarch64 (does not pull generic linux_arm64)
  • Always requests _gcc10 for the five official Linux targets
  • Extracts archives as-is (no --strip-components=1)
  • Promotes leftover pre-0.13 flat folders up to lib/linux/<arch>
  • Only removes the arch being installed

Status

@danoli3
danoli3 marked this pull request as draft August 15, 2026 04:20
@danoli3 danoli3 self-assigned this Aug 15, 2026
@danoli3 danoli3 added this to the 0.12.2 milestone Aug 15, 2026
@danoli3 danoli3 moved this to In Progress in openFrameworks Development Aug 15, 2026
@danoli3
danoli3 force-pushed the linux2026 branch 2 times, most recently from f240cd9 to 78062f7 Compare September 15, 2026 07:41
@danoli3
danoli3 marked this pull request as ready for review October 10, 2026 07:30
@danoli3 danoli3 changed the title Linux2026 - draft Linux2026 - Updates for arm64 / Raspberry Pi Oct 10, 2026
@danoli3

danoli3 commented Oct 10, 2026

Copy link
Copy Markdown
Member Author

Test run: Ubuntu 26.04 LTS, aarch64 (Parallels VM, Wayland, virgl GL 4.0 / Mesa 26.0.3)

Tested at 56d7b479 (same as pull/8540/head), system GCC 15.2.0, glibc 2.43.

Check Result
scripts/linux/download_libs.sh ✅ Picked openFrameworksLibs_latest_linux_arm64_gcc10, SHA-256 verified, deployed to lib/linux/arm64
scripts/linux/compileOF.sh ✅ Release and Debug built with GCC 15.2, no warnings
examples/graphics/graphicsExample ✅ Builds; app launches under Wayland and keeps running with nothing on stderr
scripts/ci/linux/test_lib_paths.sh ✅ 30/30
tests/gl/glRenderSmokeTest ✅ GL_SMOKE_TEST RESULT=PASS frames=12 api=GL3.2 instancing=1
scripts/ci/linux/64/run_tests.sh ✅ Exit 0, every suite passed (e.g. 273/273, 100/100, 91/91)

Notes:

  • Old lib/linux/aarch64 folders (kiss, tess2, openFrameworksCompiled) are detected and left in place, which is harmless.
  • Minor: download_libs.sh logs Deployed libraries from [...] to [/libs]. The path in the message looks wrong, but the files land in the right place.
  • Unrelated to this PR: a hand-built GCC 14 in /usr/local/gcc-14 fails to compile even a plain std::mutex on glibc 2.43 because of a stale include-fixed/pthread.h. The distro GCC works fine.

@danoli3

danoli3 commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

RPi CI failure: apothecary GLFW built without X11/Wayland

Both rpi-build jobs (aarch64, armv6l) compile but fail at link of emptyExample:

ofAppGLFWWindow.cpp:791:  undefined reference to `glfwGetX11Window'
ofAppGLFWWindow.cpp:1810: undefined reference to `glfwGetWaylandDisplay'
ofAppGLFWWindow.cpp:1824: undefined reference to `glfwGetGLXContext'
collect2: error: ld returned 1 exit status

Cause

Checked the glfwGet* native symbols exported by libglfw3.a in the current apothecary latest packages:

package native symbols
linux_64_gcc10 EGL, GLX, X11, Wayland
linux_aarch64_gcc10 EGL only
linux_armv6l_gcc10 EGL only

In apothecary formulas/glfw.sh (~line 132):

if [[ "$PLATFORM" =~ ^arm64$ ]] && [ "$TYPE" = "linux" ]; then
    GLFW_WAYLAND=1; GLFW_X11=1
else   # <- aarch64, armv6l, armv7l all land here
    DEFINES="$DEFINES -DGLFW_USE_EGL=1 -DGLFW_CLIENT_LIBRARY=glesv2"
    GLFW_WAYLAND=0; GLFW_X11=0
fi

The RPi workflow (build-linux-rpi.yml) builds with ARCH=aarch64, not arm64, so it takes the else branch and disables both X11 and Wayland. GLFW_USE_EGL / GLFW_CLIENT_LIBRARY are GLFW 3.2-era options that 3.4 ignores. The result is likely a null-platform-only GLFW that couldn't open a window on a Pi even if it linked (Bookworm defaults to Wayland).

Proposed fix (apothecary)

Build all Linux ARM targets with X11 and Wayland on. GLFW 3.4 still creates EGL/GLES contexts on either backend:

if [[ "$PLATFORM" =~ ^(arm64|aarch64|armv6l|armv7l|armv8)$ ]]; then
    export GLFW_WAYLAND=1
    export GLFW_X11=1
else

Then rebuild the RPi latest packages. The sysroot will probably also need libwayland-dev, libxkbcommon-dev, wayland-protocols and the X11 dev packages (libx11-dev, libxrandr-dev, libxinerama-dev, libxcursor-dev, libxi-dev), plus wayland-scanner on the host.

A stopgap would be to guard the X11/Wayland/GLX native calls in ofAppGLFWWindow.cpp for RPi/GLES builds. CI would go green, but we'd still be shipping a GLFW that can't open a window on a Pi.

@danoli3

danoli3 commented Oct 12, 2026

Copy link
Copy Markdown
Member Author

Apothecary fixed for raspberry Pi GLFW builds now. This is looking good.

@danoli3

danoli3 commented Oct 12, 2026

Copy link
Copy Markdown
Member Author

@ofTheo

== source contracts ==
OK config.shared.mk defines find_platform_lib_path
OK config.project.mk uses find_platform_lib_path for core libs
OK config.addons.mk uses find_platform_lib_path for addon libs

== MSYS2 ABI library paths expand without recursion ==
OK MSYS2 x86_64 paths expand
OK MSYS2 arm64 paths expand

== find_platform_lib_path (new wins, old is fallback) ==
OK linux/64: both present -> new path
OK linux/64: only new -> new path
OK linux/64: only old linux64 -> old path
OK linux/64: neither -> empty
OK linux/arm64: both present -> new path
OK linux/arm64: only new -> new path
OK linux/arm64: only old linuxarm64 -> old path
OK linux/arm64: neither -> empty
OK linux/aarch64: both present -> new path
OK linux/aarch64: only new -> new path
OK linux/aarch64: only old linuxaarch64 -> old path
OK linux/aarch64: neither -> empty
OK linux/armv7l: both present -> new path
OK linux/armv7l: only new -> new path
OK linux/armv7l: only old linuxarmv7l -> old path
OK linux/armv7l: neither -> empty
OK linux/armv6l: both present -> new path
OK linux/armv6l: only new -> new path
OK linux/armv6l: only old linuxarmv6l -> old path
OK linux/armv6l: neither -> empty

== PLATFORM_LEGACY_LIB_SUBPATHS aliases in config.shared.mk ==
OK makefile still maps linux/64 <-> linux64
OK makefile still maps linux/arm64 <-> linuxarm64
OK makefile still maps linux/aarch64 <-> linuxaarch64
OK makefile still maps linux/armv7l <-> linuxarmv7l
OK makefile still maps linux/armv6l <-> linuxarmv6l

Passed: 30 Failed: 0
Linux lib path fallbacks OK

@danoli3 danoli3 mentioned this pull request Oct 12, 2026
@danoli3
danoli3 force-pushed the linux2026 branch 2 times, most recently from 01ecf76 to e7d9652 Compare October 16, 2026 00:53
Detect Raspberry Pi so aarch64 stays the Pi 64-bit package, not
generic arm64. Request the GCC 10 baseline for all official Linux
targets, extract archives as-is, and keep lib/linux/<arch> instead
of flattening back to linux64/linuxarmv6l.
OF_DIR was unset so compileOF/PG/examples resolved the repo root
wrong. compileOF now maps 64/arm64/aarch64/armv6l/armv7l/jetson to
lib/linux/<arch>. RPi CI looks at scripts/ci/linux/rpi/raspbian.
scripts/ci/linux/rpi is one directory deeper than the old linuxrpi
path, so OF_ROOT resolved to scripts/ and the armv7l template copy
failed. Walk up four levels. Do not cancel sibling RPi slices on
one failure.
CI is not a Pi, so RPI_DETECTED is no and armv6l/armv7l fell through
to a tab-prefixed $(error) ("recipe commences before first target").
aarch64 was remapped to generic arm64 and looked in lib/linux/arm64.

Treat armv6l/armv7l/aarch64, RPI_DETECTED, and RPI_ROOT as RPi so
libs resolve under lib/linux/<arch>. Keep generic ARM desktop on
linux/arm64. Resolve third-party and addon libs via canonical then
legacy subpaths. Official Linux archives are GCC 10 only.

Skip the RPi example build until latest includes glm/tess2. Drop the
22.04 apt cache that used 24.04 package names.
Run a dedicated workflow on push and pull_request that extracts
find_platform_lib_path and checks each official arch: new nested
folder wins, pre-0.13 flat folder still resolves, missing stays empty.
linux/64/run_tests.sh copied a host Makefile into every tests/* folder
and executed the binary. android / emscripten / ios / tvOS are not
headless Linux unit tests (GLFW needs DISPLAY). Use the linux64
templates to match build.sh.
Latest msys2 clang64/mingw64/ucrt64 packages embed both a GNU and an
MSVC symbol index in kiss/tess2/videoInput .a files. MinGW ld then
treats the archive as a linker script; lld reports unknown file type.

Rebuild those archives with ar/ranlib after extract. Prefer
lib/msys2/x86_64 when apothecary nests an arch folder.
Add scripts/ci/check_deployed_libs.sh and run it after download_libs
on linux, RPi, and msys2. Fail if tess2/kiss/zlib (or msys2
videoInput) are missing or not GNU ar. RPi still allows the zlib-only
smoke-test archive. The Linux lib-paths workflow also downloads
linux_64 and checks real files.
reindexMsys2StaticLibs extracted each archive with "ar x" into one
directory and repacked it with "ar rcs". Same-named members overwrite
each other on extraction, so the repacked libopencv_world.a lost 17 of
its 512 objects (13 duplicate names, incl. core/src/parallel.cpp.o and
core/src/tables.cpp.o) and the msys2 allAddonsExample link failed with
undefined cv::parallel_for_ / cv::g_Saturate8u - even though the
apothecary package itself is correct.

Archives with duplicate member names now only get their symbol index
rebuilt in place ("ar s" + ranlib), as apothecary does since openframeworks#606.
scripts/ci/linux64/run_tests.sh moved to scripts/ci/linux/64/run_tests.sh on
this branch; carry master's build_or_fail (openframeworks#8590) over to the moved script.
@danoli3

danoli3 commented Oct 18, 2026

Copy link
Copy Markdown
Member Author

Third-party addons with old (pre-0.13) library paths: tested on 61fdd4489

Machine: aarch64 Linux (Ubuntu 26.04 VM, g++ 15.2), so the project arch is linux/arm64. Both addons are cloned unmodified from upstream, and neither addon_config.mk was edited. Each addon's arm64 static lib was placed in the old flat folder lib/linuxarm64/, next to the addon's existing linux64 / linuxarmv6l / linuxarmv7l folders. The makefile has to find it through the new legacy fallback (linux/arm64 → linuxarm64 → linuxaarch64).

ofxTurboJpeg (armadillu/ofxTurboJpeg @ 06d14a7)

  • libjpeg-turbo 2.1.5 built static for arm64 (NEON) into libs/turbo-jpeg/lib/linuxarm64/
  • Link line picks up …/turbo-jpeg/lib/linuxarm64/libjpeg.a and …/libturbojpeg.a; the armv6l/armv7l libs are correctly skipped.
Check Result
tjCompress to file (q90) PASS, 13237 bytes
tjDecompress from file PASS, 320x240
Round trip vs original PASS, mean error 0.75 / 255
Memory buffer round trip PASS, identical to file decode
FreeImage decodes the TurboJPEG file PASS, diff 0.96 vs TurboJPEG decode

Note, not a linux2026 issue: the addon bundles a static libjpeg (API v62), and the executable exports its jpeg_* symbols over the system libjpeg.so.8 (v80) that libfreeimage uses. Without a workaround, ofImage::load() of any JPEG then fails inside the same app ("Wrong JPEG library version: library is 62, caller expects 80"). Adding PROJECT_LDFLAGS = -Wl,--exclude-libs,libjpeg.a:libturbojpeg.a to the project's config.make fixes it, and that's what the run above uses. The same thing would happen on master with this addon.

ofxLibwebsockets (robotconscience/ofxLibwebsockets @ f29422e)

  • libwebsockets 1.4 (v1.4-chrome43-firefox-36, the version the addon's headers expect) built static for arm64 with OpenSSL, into libs/libwebsockets/lib/linuxarm64/
  • Link line picks up …/libwebsockets/lib/linuxarm64/libwebsockets.a plus system -lssl -lcrypto -lz. The addon's x86_64 linux64 lib and the armv6l/armv7l libs are correctly skipped.
Check Result
Server::setup() on port 9095 PASS
Client::connect() to ws://localhost:9095 PASS
5 messages client → server → echo → client PASS, 5/5 matched

Screenshots

Screenshots of both test apps to follow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant