Skip to content

ScriptBlock/fs42-bobcat-deps

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fs42-bobcat-deps

CPU-compatible Python dependencies for running FieldStation42 on an older AMD G-T48E ("Bobcat", Family 14h) thin client (e.g. an HP/older ThinTerminal).

The problem

The target CPU is 64-bit but only x86-64-v1. It has:

sse sse2 sse3 ssse3 sse4a   (plus popcnt/abm, cx16)

but it does NOT have sse4.1, sse4.2, avx, or avx2. (sse4a is an AMD-only extension and does not include the SSE4.1 pinsr*/pextr* instructions.)

Modern prebuilt Python wheels are compiled for x86-64-v2 (SSE4.1/4.2 baseline). When such a binary runs on this CPU the kernel kills it with SIGILL — "Illegal instruction (core dumped)" and no Python traceback, because it is a hardware trap, not a Python exception.

Confirmed culprits when launching field_player.py:

Package Symptom Faulting instruction
numpy (via moviepycatalogliquid_manager) SIGILL on import pinsrq (SSE4.1) in _multiarray_umath static init
PySide6 / shiboken6 SIGILL on import pinsrq (SSE4.1) in Shiboken::init()
bundled Qt6 itself SIGABRT: "This Qt build requires: sse4.1 sse4.2" Qt's runtime baseline check

Two unrelated launch blockers were also found and are handled at deploy time:

  • tkinter missing (python3-tk) — needed by the classic channel guide.
  • (web rendering / QtWebEngine is intentionally not built — see below.)

The fix

Rebuild the offending native packages with a CPU baseline of -march=btver1 (gcc's exact target for AMD Bobcat: SSE/SSE2/SSE3/SSSE3/SSE4a, no SSE4.1+). Qt's higher SIMD paths remain runtime-dispatched, so they're simply not taken on this CPU.

We build Qt 6.11.1 qtbase only (Core/Gui/Widgets + the xcb platform plugin) and PySide6/shiboken6 6.11.1 against it, plus a from-source numpy.

QtWebEngine / QtQuick are deliberately skipped (a 204 MB Chromium build). The only FieldStation feature that needs them is the optional web channel type (rendering a web page as a TV channel). The video path (mpv→HDMI), the ticker / now-playing / NFO overlays (Qt Widgets), and the classic tkinter guide all work without it, and FieldStation degrades web rendering gracefully when the modules are absent.

numpy note: numpy has its own SIMD baseline, independent of -march. In 2.4.x it defaults to X86_V2 and the -Dcpu-baseline= meson option will not go below v2 (verified: it's floored/ignored). The reliable lever is -Ddisable-optimization=true, which turns numpy's SIMD dispatcher off and builds generic (SSE2) code with no x86-64-v2 requirement. The Bobcat has no AVX/SSE4.1 to dispatch to, so this loses nothing on the target. (Also beware: pip wheel silently skips building when the target wheel already exists in -w — the scripts delete the prior wheel first.)

Versions are pinned to match the existing venv so the rest of the install is undisturbed:

  • Qt / PySide6 / shiboken6: 6.11.1
  • numpy: 2.4.6
  • Python: 3.12 (cp312), Ubuntu 24.04 / glibc 2.39 — identical to the target.

Layout

docker/Dockerfile.builder   Ubuntu 24.04 build image (matches the target OS/toolchain)
scripts/build-qtbase.sh     clone + build qtbase 6.11.1 (btver1) -> /work/qt6
scripts/build-pyside.sh     clone + build PySide6/shiboken6 wheels (btver1) -> dist/
scripts/build-numpy.sh      build numpy 2.4.6 wheel from source (btver1) -> dist/
scripts/build-all.sh        runs the three builds in order inside the container
scripts/deploy.sh           copy wheels to the thin client + install + python3-tk
dist/                       output wheels (git-ignored; large)
work/                       sources + Qt install tree (git-ignored; large)

Build

./scripts/run-build.sh        # builds the image, then runs build-all.sh in a container

The container mounts this repo at /work; sources land in work/, wheels in dist/.

Deploy

./scripts/deploy.sh <user>@<host>   # default: fieldstation@172.16.225.187

Installs the wheels into /home/fieldstation/FieldStation42/env and ensures python3-tk is present.

Why a powerful host is fine

A build host's own CPU is irrelevant to the target baseline — only the compiler flags matter. We build with -march=btver1 inside an Ubuntu 24.04 container that matches the target's OS, glibc, gcc (13.3) and Python (3.12), so the resulting .so/wheels link and run cleanly on the Bobcat (and on any newer x86-64, since btver1 is a subset).

Build & effort reference

For community reference — this whole diagnosis, build, and deployment was done with Claude Code (Claude Opus 4.7).

Reproducible compile time on a 20-core x86-64 host (Ubuntu 24.04):

Step Time
qtbase 6.11.1 (-march=btver1) ~4m53s
PySide6 + shiboken6 (Core/Gui/Widgets) ~2–3m
numpy 2.4.6 (from source) ~3m
One-time: Docker builder image (apt build-dep qt6-base) ~5–8m
Source clones (qtbase ~414 MB, pyside-setup ~71 MB) network-bound

A clean from-scratch build is ~20–25 min end-to-end.

Whole-session effort — initial "illegal instruction" diagnosis → working, verified deploy on the target, including several debugging iterations and preparing the upstream contributions:

  • Wall-clock: ~2h 48m · API compute: ~56m · Cost: ~$21.15
  • Model: Claude Opus 4.7 (via Claude Code)
  • Tokens (Opus 4.7): ~22.3k input · ~242.4k output · ~24.9M cache read · ~405k cache write

About

x86-64-v1 (AMD Bobcat/Jaguar) rebuilds of FieldStation42's PySide6/Qt6 + numpy wheels — fixes 'Illegal instruction (core dumped)' on older CPUs

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors