mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-25 12:00:50 +01:00
keyboard/build.sh builds Full Keyboard in the dev container (FULL_KEYBOARD_TESTS=1 with its tests), loading SteamVR's libopenvr_api first like Frametop's other programs. frametop-keyboard.service runs it with --frametop alongside SteamVR; keyboard/run.sh installs it, and install.sh does that in its desktop step. The image builds it and keeps only what it runs from. uninstall.sh covers its process and settings. The README credits TaiKeid's Full Keyboard (MIT) and lists keyboard/; keyboard/FRAMETOP.md records the import, every Frametop change, how it works with Frametop, and how to update from upstream. docs/reference.md and docs/design.md describe it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
166 lines
9.8 KiB
Docker
166 lines
9.8 KiB
Docker
# Frametop runtime image (see pack/README.md).
|
|
#
|
|
# One image that holds everything Frametop needs: the frozen toolchain and C
|
|
# libraries, its native binaries, and its locked Python environment. A given
|
|
# image tag always behaves the same, on a PC and on the Frame.
|
|
#
|
|
# setup/dev-container.sh stays the source of truth for the package list on the
|
|
# Frame's dev container; the list below freezes the runtime-relevant subset of
|
|
# it plus the toolchain (the binaries are built in this image). Keep the two in
|
|
# sync on purpose: dev-container.sh documents *why* each package is there.
|
|
FROM registry.fedoraproject.org/fedora-toolbox:44@sha256:034cb7c472038e2d879ddc19568106a1342aa24403f0d641a0f73dda638707ad AS runtime-common
|
|
|
|
# Toolchain (the binaries are built in here) and the libraries they link.
|
|
RUN dnf -y install --setopt=install_weak_deps=False \
|
|
gcc gcc-c++ make pkgconf-pkg-config curl unzip just git cmake ninja-build \
|
|
pipewire-devel libxkbcommon-devel libinput-devel systemd-devel dbus-devel \
|
|
libdrm-devel mesa-libgbm-devel wayland-devel vulkan-loader-devel \
|
|
vulkan-headers plasma-wayland-protocols wlroots-devel pixman-devel \
|
|
libstdc++-static glibc-static jsoncpp-devel zstd \
|
|
# remote displays (stream/): moonlight-embedded's libgamestream and
|
|
# moonlight-common-c, and the host's sound (Opus, PulseAudio)
|
|
openssl-devel libcurl-devel expat-devel libuuid-devel json-devel \
|
|
opus-devel pulseaudio-libs-devel \
|
|
# Frametop Voice (voice/): glslc and the SPIR-V headers for whisper.cpp's
|
|
# Vulkan backend; ft-voiced records with pw-record and plays its sounds with pw-play
|
|
glslc spirv-headers-devel pipewire-utils \
|
|
# Frametop's keyboard (keyboard/, TaiKeid's Full Keyboard): Cairo and Pango
|
|
# draw it, SDL2 for its preview, and its input methods: Hangul, Pinyin (pyzy),
|
|
# Japanese (Anthy, loaded at run time)
|
|
cairo-devel pango-devel json-c-devel sdl2-compat-devel libhangul-devel pyzy-devel \
|
|
anthy-unicode-devel \
|
|
# Frametop Input Settings (Kirigami, PySide6) and remote desktop (krdp):
|
|
# keep the native KDE/Qt stack in matching Fedora packages
|
|
python3-shiboken6 kf6-kirigami kf6-qqc2-desktop-style \
|
|
qt6-qtwayland qt6-qtsvg qt6-qtimageformats qt6-qtpdf \
|
|
breeze-icon-theme plasma-breeze krdp freerdp tigervnc-x11-server xrandr \
|
|
&& dnf -y remove 'glibc-langpack-*' \
|
|
&& dnf -y install glibc-langpack-en \
|
|
&& dnf clean all \
|
|
&& rm -rf /usr/share/doc/* /usr/share/man/* /usr/share/info/* \
|
|
/usr/share/wallpapers
|
|
|
|
# OpenVR's API library for linking, from the SDK tag the build scripts pin
|
|
# (scripts/openvr.sh fetches the headers). The image has no SteamVR, so the
|
|
# binaries link this copy; their rpath names SteamVR's folder first, so on the
|
|
# Frame they load SteamVR's own libopenvr_api, as the on-device builds do.
|
|
RUN install -d /opt/frametop/bin /opt/frametop/lib \
|
|
&& curl -fsSL https://github.com/ValveSoftware/openvr/raw/v2.15.6/bin/linuxarm64/libopenvr_api.so \
|
|
-o /opt/frametop/lib/libopenvr_api.so \
|
|
&& echo "cc3671d24dd23fb61494e8a8327cf4fe7f638a60508ff7225984a03f2f5947e9 /opt/frametop/lib/libopenvr_api.so" | sha256sum -c
|
|
|
|
# Python: Fedora's own python3 (the digest-pinned base freezes it), with the
|
|
# locked packages in a venv on top. The venv sees the system site-packages,
|
|
# because PySide6 and Kirigami come from Fedora for this python3: one interpreter
|
|
# imports both, as in the dev container on the Frame. The check names the
|
|
# recorders' huggingface_hub (uploads) and cryptography (encrypted exports) too:
|
|
# the tests that need them skip without them. PySide6 itself is checked in the
|
|
# runtime stage at the end, where the builder's export lands. Rebuilt only when
|
|
# the lockfile changes, so source edits below reuse this layer.
|
|
# uv sync --frozen --group tracker --group voice: the default dev group (pytest/ruff
|
|
# for CI's in-image tests) plus the tracker stack and Frametop Voice's (sherpa-onnx);
|
|
# the types group (mypy) stays out.
|
|
# --no-cache keeps uv's download cache out of the image.
|
|
# uv is a pinned, checked build tool, not a runtime dependency. Extract it,
|
|
# create the environment, and remove it in one layer so neither uv nor uvx
|
|
# takes space in an installed image.
|
|
ENV UV_PROJECT_ENVIRONMENT=/opt/frametop/venv UV_PYTHON=/usr/bin/python3 UV_PYTHON_DOWNLOADS=never
|
|
COPY pyproject.toml uv.lock .python-version /src/frametop/
|
|
RUN uvdir=$(mktemp -d) \
|
|
&& curl -fsSL https://github.com/astral-sh/uv/releases/download/0.12.23/uv-aarch64-unknown-linux-gnu.tar.gz \
|
|
-o "$uvdir/uv.tar.gz" \
|
|
&& echo "6524bd338177ed50d035d39354e12545e993bbeba2ecbddf0480c5b3a81d313f $uvdir/uv.tar.gz" | sha256sum -c \
|
|
&& tar -xzf "$uvdir/uv.tar.gz" --strip-components=1 -C "$uvdir" uv-aarch64-unknown-linux-gnu/uv \
|
|
&& "$uvdir/uv" venv --system-site-packages /opt/frametop/venv \
|
|
&& cd /src/frametop && "$uvdir/uv" sync --frozen --group tracker --group voice --no-cache \
|
|
&& /opt/frametop/venv/bin/python -c 'import numpy, cv2, sherpa_onnx, sentencepiece, huggingface_hub, cryptography' \
|
|
&& rm -rf "$uvdir"
|
|
|
|
# Preserve separate base/environment layers for cached builds and rollback.
|
|
# Keep the toolchain and headers: ft dev shell/test still work in this image.
|
|
# PySide's full Fedora RPM also requires WebEngine/3D/etc. The builder exports
|
|
# the unchanged bindings Frametop uses, against these same system Qt libraries.
|
|
WORKDIR /src/frametop
|
|
ENV FRAME_IN_BOX=1 OPENVR_LIB=/opt/frametop/lib
|
|
ENV PATH=/opt/frametop/venv/bin:/opt/frametop/bin:/usr/local/bin:/usr/bin:/usr/sbin
|
|
RUN ln -s /run/host/opt/steamvr /opt/steamvr
|
|
CMD ["sleep", "infinity"]
|
|
|
|
FROM runtime-common AS builder
|
|
RUN rpm -qa --qf '%{NEVRA}\n' | sort > /tmp/runtime-rpms \
|
|
&& dnf -y install --setopt=install_weak_deps=False python3-pyside6 \
|
|
&& rpm -qa --qf '%{NEVRA}\n' | sort > /tmp/builder-rpms \
|
|
&& test -z "$(comm -23 /tmp/runtime-rpms /tmp/builder-rpms)" \
|
|
&& dnf clean all \
|
|
&& install -d /runtime/opt/frametop/bin /runtime/opt/frametop/lib
|
|
|
|
# The sources, then the binaries, built by the same build scripts as on the
|
|
# Frame (FRAME_IN_BOX=1: they run here instead of entering the dev container).
|
|
# Each program stays in its build/ folder in /src/frametop and is copied to
|
|
# /opt/frametop.
|
|
COPY . /src/frametop
|
|
RUN screens/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin screens/build/ft-screens screens/build/ft-handtest screens/build/ft-spotpanel \
|
|
&& rm -f screens/build/*.o
|
|
RUN pointer/helper/build.sh && pointer/driver/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin pointer/helper/build/ft-pointer \
|
|
&& install -t /runtime/opt/frametop/lib pointer/driver/build/driver_ft_pointer.so
|
|
RUN gaze/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin gaze/build/ft-gaze gaze/build/ft-gazepanel
|
|
# Frametop's keyboard (TaiKeid's Full Keyboard): it stays in keyboard/build/frametop,
|
|
# with the input method engines, Steam bridge and SteamVR manifests it finds beside
|
|
# itself, where frametop-keyboard.service runs it from. The rest of the build goes.
|
|
RUN keyboard/build.sh \
|
|
&& cd keyboard/build/frametop \
|
|
&& find . -mindepth 1 -maxdepth 1 ! -name framekeyboard ! -name framekeyboard-native-guard \
|
|
! -name engines ! -name bridge ! -name vr -exec rm -rf {} + \
|
|
&& strip --strip-unneeded framekeyboard framekeyboard-native-guard engines/*.so
|
|
RUN power/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin power/build/ft-powerd
|
|
RUN stream/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin stream/build/ft-stream \
|
|
&& rm -rf stream/build/mlc stream/build/gamestream
|
|
# Our own eye tracker: ft-eyegrab (it runs on the host, as root) and ft-eyes'
|
|
# build/venv, which here only points at the venv above.
|
|
RUN gaze/tracker/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin gaze/tracker/build/ft-eyegrab
|
|
# Frametop Voice: whisper.cpp's server (Vulkan), and build/venv pointing at the venv
|
|
# above. Its speech models aren't in the image: voice/models.sh fetches them on install.
|
|
RUN voice/build.sh \
|
|
&& install -t /runtime/opt/frametop/bin voice/build/bin/whisper-server
|
|
# Hand tracking: ft-camd (static: it runs on the host, with the file
|
|
# capabilities hands/run.sh install sets) and ft-hands, which builds ncnn at the
|
|
# tag hands/Makefile pins. Both stay in hands/build/, where their units and
|
|
# file capabilities point, so they aren't copied to /opt/frametop.
|
|
RUN hands/build.sh \
|
|
&& test -x hands/build/ft-camd && test -x hands/build/ft-hands
|
|
# The Hand Recorder's headset panel: it stays in hands/rec/build/, where the recorder
|
|
# (hands/rec/session.py) runs it from.
|
|
RUN hands/rec/build.sh \
|
|
&& test -x hands/rec/build/ft-handpanel
|
|
|
|
# A release installs from this image (pack/install-release.sh): it copies
|
|
# /src/frametop, built, to the Frame for its host side (services, the driver,
|
|
# the desktop's scripts), and its install.sh installs this distrobox (1.8.2.5,
|
|
# as a source install clones it, here by commit) to run the image as the
|
|
# container those programs start in (scripts/in-box).
|
|
RUN git init -q pack/build/distrobox \
|
|
&& cd pack/build/distrobox \
|
|
&& git fetch -q --depth 1 https://github.com/89luca89/distrobox.git 40c3cd724faa434aeb0a23e28776665b92de68bd \
|
|
&& git checkout -q FETCH_HEAD \
|
|
&& rm -rf .git
|
|
# Export Fedora's selected Python bindings without changing their native code.
|
|
RUN python3 pack/pyside-runtime.py --repo /src/frametop --destination /runtime
|
|
|
|
# The default environment: Frametop's binaries and the venv's python3 (Fedora's
|
|
# interpreter, with the locked packages and the Fedora Qt stack) first.
|
|
# sleep infinity as the default command keeps the image usable with distrobox
|
|
# create, like the toolbox base.
|
|
FROM runtime-common AS runtime
|
|
COPY --from=builder /runtime/usr/ /usr/
|
|
COPY --from=builder /runtime/opt/ /opt/
|
|
COPY --from=builder /src/frametop/ /src/frametop/
|
|
RUN python3 pack/pyside-runtime.py --verify /usr/share/frametop/pyside-runtime.json \
|
|
&& /usr/bin/python3 -c 'from PySide6 import QtCore, QtGui, QtQml, QtQuick, QtQuickControls2' \
|
|
&& python3 -c 'import numpy, cv2'
|