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.

@danoli3

danoli3 commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

After extensive tests. @ofTheo what do you think I can do another pass with screenshots but I this this solves most problems with make and paths even using the new paths for libraries but supporting the old too

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