Packaging: containerised CI, Flatpak/AppImage, bundled simd, licence notices, and release-please (#53)

This commit is contained in:
David Scott
2026-09-10 14:34:56 -04:00
committed by GitHub
parent cd67cb1689
commit 45f2ef7fef
37 changed files with 1199 additions and 82 deletions
+403 -18
View File
@@ -3,31 +3,84 @@ name: Make Packages
on:
push:
tags: [ "*" ]
workflow_dispatch: {}
# Called by release-please.yml once it has cut a release. A tag pushed by
# release-please carries the default GITHUB_TOKEN, and GitHub deliberately
# refuses to start a workflow from an event that token created -- so the
# `push: tags` trigger above never fires for a release-please tag. Being
# callable means the release build runs inside release-please's own run
# instead, with no personal access token to store on a public repo.
workflow_call:
inputs:
release_tag:
description: >-
Tag release-please just created. Supplies the package version and
names the release to upload to, both of which would otherwise come
from github.ref_name.
type: string
required: true
jobs:
build-monocoque-debs:
# Previously this matrix used `runs-on: ${{ matrix.os }}` with
# debian-latest/debian-stable as runner *labels*, which only resolve to
# self-hosted runners. With none online those two legs sat queued
# indefinitely (observed: four runs stuck 17-60min, only the
# ubuntu-latest leg ever completing) until cancelled by hand. Building
# each distro in a container on ordinary GitHub-hosted runners removes
# the self-hosted dependency entirely.
#
# matrix.os stays the distro *name* because it's load-bearing: it picks
# the per-distro control file under tools/distro/debian/dpkg/<os>/ and
# names the released .deb. matrix.image is what it actually builds in.
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, debian-latest, debian-stable]
runs-on: ${{ matrix.os }}
include:
- os: ubuntu-latest
image: ubuntu:latest
- os: debian-latest
image: debian:testing
- os: debian-stable
image: debian:stable-slim
runs-on: ubuntu-latest
container:
image: ${{ matrix.image }}
permissions:
contents: write
steps:
- uses: actions/checkout@v1
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Update apt
run: sudo apt update
- name: Install Dependencies
run: sudo apt install -y libgtk-3-dev libuv1-dev libargtable2-dev libserialport-dev libconfig-dev libhidapi-dev liblua5.4-dev libxdg-basedir-dev libxml2-dev libpulse-dev libproc2-dev libcurl4-openssl-dev libglu1-mesa-dev
# Must come before actions/checkout: these images are minimal and ship
# no git, so checkout would fall back to a tarball download and silently
# skip submodules -- simapi and nappgui_src are both required to build.
# No sudo either; container jobs already run as root.
- name: Install build dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
ca-certificates curl git \
build-essential cmake pkg-config \
libgtk-3-dev libuv1-dev libargtable2-dev libserialport-dev \
libconfig-dev libhidapi-dev liblua5.4-dev libxdg-basedir-dev \
libxml2-dev libpulse-dev libproc2-dev libcurl4-openssl-dev \
libglu1-mesa-dev
- uses: actions/checkout@v4
with:
submodules: recursive
# $GITHUB_WORKSPACE, not ${{ github.workspace }}: in a container job the
# expression still renders the *host* path (/home/runner/work/...) while
# the repo is actually mounted at /__w/... inside the container. Using
# the expression made cmake fail with `The source directory
# "/home/runner/work/monocoque/monocoque" does not exist`. The env var is
# set to the container-side path, so it's correct either way.
- name: Set build dir
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
echo "build-output-dir=$GITHUB_WORKSPACE/build" >> "$GITHUB_OUTPUT"
github_sha_hash=${{ github.sha }}
echo "github-sha-short=${github_sha_hash:0:7}" >> $GITHUB_OUTPUT
@@ -38,7 +91,7 @@ jobs:
-DCMAKE_CXX_COMPILER=g++
-DCMAKE_C_COMPILER=gcc
-DCMAKE_BUILD_TYPE=Release
-S ${{ github.workspace }}
-S "$GITHUB_WORKSPACE"
- name: Build
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config Release
@@ -51,48 +104,380 @@ jobs:
mkdir -p PKG_SOURCE/usr/share/applications
mkdir -p PKG_SOURCE/usr/share/pixmaps
mkdir -p PKG_SOURCE/usr/share/icons/hicolor/scalable/apps
mkdir -p PKG_SOURCE/usr/share/monocoque
- name: Download xpm icon
run: |
curl -sSL https://repo.spacefreak18.xyz/monocoque/icons/monocoque.xpm -o PKG_SOURCE/usr/share/pixmaps/monocoque.xpm
- name: Download svg icon
run: |
curl -sSL https://repo.spacefreak18.xyz/monocoque/icons/monocoque.svg -o PKG_SOURCE/usr/share/icons/hicolor/scalable/apps/monocoque.svg
- name: Determine package version
id: pkgver
shell: bash
env:
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
# The control files carry a hardcoded `Version: 1` that nobody
# maintains, so every .deb ever released claims version 1 regardless
# of its tag. Take the version from the tag instead.
#
# Guarded rather than used blindly: a Debian version must start with a
# digit, so a branch build (workflow_dispatch) or a non-release tag
# like `pkgtest-5` would make dpkg-deb fail outright. Anything that
# doesn't look like a version falls back to 0.0.0.
v=""
# RELEASE_TAG is set only when release-please calls this workflow;
# its tag exists but the run itself is on a branch, so GITHUB_REF_*
# would report master and fall through to 0.0.0.
v="${RELEASE_TAG#v}"
[ -z "$v" ] && [ "$GITHUB_REF_TYPE" = tag ] && v="${GITHUB_REF_NAME#v}"
case "$v" in
[0-9]*) ;;
*) v="0.0.0" ;;
esac
echo "version=$v" >> "$GITHUB_OUTPUT"
echo "packaging as version $v"
- name: Copy script files around to stop .github from being added to the package then build the package
run: |
cp ./tools/distro/debian/dpkg/${{ matrix.os }}/control ./PKG_SOURCE/DEBIAN/control
sed -i "s/^Version:.*/Version: ${{ steps.pkgver.outputs.version }}/" ./PKG_SOURCE/DEBIAN/control
cp ./tools/distro/debian/dpkg/copyright ./PKG_SOURCE/DEBIAN/copyright
cp ./build/monocoque ./PKG_SOURCE/usr/bin/monocoque
cp ./build/gmonocoque ./PKG_SOURCE/usr/bin/gmonocoque
cp ./tools/monocoque.desktop ./PKG_SOURCE/usr/share/applications/monocoque.desktop
dpkg-deb --build PKG_SOURCE monocoque-${{ matrix.os }}.deb
echo "--- control as packaged ---"
dpkg-deb --field monocoque-${{ matrix.os }}.deb Package Version
- name: Release the Package
# Only a tag can publish a release; without this a workflow_dispatch run
# builds everything correctly and then reports failure on a step that
# cannot work, which makes a green build look broken.
if: github.ref_type == 'tag' || inputs.release_tag != ''
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ inputs.release_tag || github.ref_name }}
files: monocoque-${{ matrix.os }}.deb
# release-please writes the release body from the changelog it just
# generated. Letting this action generate its own notes as well would
# overwrite them, so it only does so for a hand-pushed tag.
generate_release_notes: ${{ inputs.release_tag == '' }}
build-monocoque-rpms:
# Same self-hosted-label problem as the deb jobs above (fedora-43 was a
# runner label with nothing online to claim it); now a container on an
# ordinary GitHub-hosted runner, with fedora-44 added alongside 43.
strategy:
fail-fast: false
matrix:
os: [fedora-43]
runs-on: ${{ matrix.os }}
include:
- os: fedora-43
image: fedora:43
- os: fedora-44
image: fedora:44
runs-on: ubuntu-latest
container:
image: ${{ matrix.image }}
permissions:
contents: write
steps:
# The -devel list is the one fedora.spec's own header comment documents,
# plus gtk3/libcurl/mesa-libGLU to match its `Requires:` line -- the spec
# configures with -DBUILD_GUI=on, so the GUI's deps are build deps too.
#
# Retried because this pulls openh264 from Fedora's third-party Cisco
# repo (ciscobinary.openh264.org), which is a single-mirror CDN outside
# Fedora's own infrastructure and has proven flaky: the fedora-43 leg of
# the first run died on `Curl error (7): Could not connect to server`
# for it while fedora-44 downloaded the very same package fine in the
# same run -- i.e. transient, not a dependency or package-name problem.
# Not disabling that repo outright: openh264 is still pulled in even
# with weak deps off, so something here requires it outright (which
# package wasn't traced) and dropping the repo would likely break
# dependency resolution rather than fix anything.
- name: Install build dependencies
run: |
for attempt in 1 2 3; do
dnf install -y --setopt=install_weak_deps=False \
rpm-build cmake gcc gcc-c++ make git curl \
pulseaudio-libs-devel argtable-devel libconfig-devel hidapi-devel \
libserialport-devel lua-devel libuv-devel libxdg-basedir-devel \
libxml2-devel procps-ng-devel gtk3-devel libcurl-devel \
mesa-libGLU-devel && exit 0
echo "dnf install failed (attempt $attempt), retrying in 15s..."
sleep 15
done
echo "dnf install failed after 3 attempts" >&2
exit 1
# submodules: recursive is new here. It didn't matter while %prep cloned
# upstream and ran `git submodule update` itself; now that the staged
# checkout is what gets built, an empty nappgui_src fails configure with
# "does not contain a CMakeLists.txt file". Missed by the local fedora:44
# rehearsal, which mounted a working tree that already had its submodules.
- uses: actions/checkout@v4
with:
submodules: recursive
- name: create rpmbuild dirs
run: mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
- name: get spec file
run: curl -o ~/fedora.spec https://raw.githubusercontent.com/Spacefreak18/monocoque/refs/heads/master/tools/distro/fedora/rpm/fedora.spec
# The spec's %prep used to `git clone` upstream master, so the rpm's
# contents tracked master rather than the tag being built -- an rpm built
# from a tag would quietly ship master's code. Staged here and copied by
# %prep instead, so a package's contents are the commit it was built from.
- name: Stage the checked-out tree as the rpm source
run: |
rm -rf ~/rpmbuild/SOURCES/monocoque
cp -r "$GITHUB_WORKSPACE" ~/rpmbuild/SOURCES/monocoque
rm -rf ~/rpmbuild/SOURCES/monocoque/.github
# Uses the spec from the checked-out tree instead of curl'ing it from
# upstream's master branch, so a tag builds the spec that tag contains.
#
# The spec's `Version: 0.0.5` is stale and hand-maintained -- real tags are
# well past it, so released rpms have been installing as monocoque-0.0.5.
# Stamped from the tag here rather than edited in the spec, so the file
# stays a working default for local rpmbuild while CI releases carry the
# real version. Same digit guard as the deb job: rpm versions can't start
# with a non-digit, and scratch tags / branch builds would break it.
#
# NOTE (pre-existing, deliberately not fixed here): the spec's own %prep
# still does a fresh `git clone` of upstream master for the *sources*,
# so the rpm's contents track master rather than the tag being built.
# Worth fixing separately -- it needs the spec parameterised, which is a
# bigger change than getting these jobs running again.
- name: run spec file
run: rpmbuild -ba ~/fedora.spec
shell: bash
env:
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
v=""
# RELEASE_TAG is set only when release-please calls this workflow;
# its tag exists but the run itself is on a branch, so GITHUB_REF_*
# would report master and fall through to 0.0.0.
v="${RELEASE_TAG#v}"
[ -z "$v" ] && [ "$GITHUB_REF_TYPE" = tag ] && v="${GITHUB_REF_NAME#v}"
case "$v" in
[0-9]*) ;;
*) v="0.0.0" ;;
esac
echo "packaging as version $v"
sed -i "s/^Version:.*/Version: $v/" tools/distro/fedora/rpm/fedora.spec
rpmbuild -ba tools/distro/fedora/rpm/fedora.spec
# Glob rather than a hardcoded monocoque-0.0.5-1.x86_64.rpm: the filename
# tracks the spec's Version/Release, which is now stamped per-tag above.
- name: rename file
run: cp ~/rpmbuild/RPMS/x86_64/monocoque-0.0.5-1.x86_64.rpm $GITHUB_WORKSPACE/monocoque-${{ matrix.os }}.rpm
run: |
cp ~/rpmbuild/RPMS/x86_64/monocoque-*.rpm "$GITHUB_WORKSPACE/monocoque-${{ matrix.os }}.rpm"
echo "--- rpm identity as built ---"
rpm -qp --qf '%{NAME} %{VERSION}-%{RELEASE}\n' "$GITHUB_WORKSPACE/monocoque-${{ matrix.os }}.rpm"
- name: Release the Package
# Only a tag can publish a release; without this a workflow_dispatch run
# builds everything correctly and then reports failure on a step that
# cannot work, which makes a green build look broken.
if: github.ref_type == 'tag' || inputs.release_tag != ''
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ inputs.release_tag || github.ref_name }}
files: monocoque-${{ matrix.os }}.rpm
# release-please writes the release body from the changelog it just
# generated. Letting this action generate its own notes as well would
# overwrite them, so it only does so for a hand-pushed tag.
generate_release_notes: ${{ inputs.release_tag == '' }}
build-monocoque-appimage:
# An AppImage only runs where glibc is at least as new as the one it
# linked against, so it wants the OLDEST base that can build the code --
# building on current Ubuntu silently excludes older distros and defeats
# the point of shipping one.
#
# That floor is set by the compiler, not by choice: simapi's F1 2018
# headers use C23 enum-with-fixed-underlying-type (`enum TrackID :
# uint8_t`), which GCC only implements from 13 onwards. ubuntu-22.04
# ships GCC 11 and fails outright with `expected identifier or '(' before
# ':' token` -- confirmed by a real run, and no -std= value rescues it
# (verified separately: the construct is gated on compiler version, not
# on the standard flag). ubuntu-24.04 / GCC 13 is therefore the oldest
# usable base, giving a glibc 2.39 floor.
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
# librsvg2-common and libgtk-3-bin are for linuxdeploy's gtk plugin, not
# the build itself -- it needs an svg pixbuf loader and
# gtk-update-icon-cache to assemble a self-contained GTK runtime.
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential cmake pkg-config \
libgtk-3-dev libuv1-dev libargtable2-dev libserialport-dev \
libconfig-dev libhidapi-dev liblua5.4-dev libxdg-basedir-dev \
libxml2-dev libpulse-dev libproc2-dev libcurl4-openssl-dev \
libglu1-mesa-dev \
desktop-file-utils file patchelf wget \
librsvg2-common libgtk-3-bin
# -std=gnu2x for the C23 enum syntax above: GCC 13 implements it but
# still defaults to gnu17, unlike GCC 15+ (which the container-based
# deb/rpm legs get, and which accept it without the flag). gnu2x rather
# than c2x so GNU extensions stay on -- simapi also relies on asprintf.
- name: Build
run: |
cmake -B build -DBUILD_GUI=on -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_FLAGS=-std=gnu2x -S .
cmake --build build --config Release
# Uses the install() rules rather than hand-copying binaries the way the
# deb job does -- that's what they were added for.
- name: Populate AppDir
run: |
DESTDIR="$PWD/AppDir" cmake --install build --prefix /usr
# Icon basename must match the desktop file's `Icon=monocoque`.
# tools/monocoque.svg is the square copy shared with the Flatpak
# build; the published 100x50 artwork is rejected by icon tooling.
install -Dm644 tools/monocoque.svg \
AppDir/usr/share/icons/hicolor/scalable/apps/monocoque.svg
# APPIMAGE_EXTRACT_AND_RUN=1 because these tools are themselves
# AppImages and there is no FUSE on the runner to mount them with.
- name: Build AppImage
env:
APPIMAGE_EXTRACT_AND_RUN: 1
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
# An AppImage carries no package metadata, so its filename is the only
# place a version can live -- hence versioning the output name here
# rather than stamping a field as the deb/rpm jobs do. Same digit
# guard, so scratch tags and branch builds still produce a valid name.
v=""
# RELEASE_TAG is set only when release-please calls this workflow;
# its tag exists but the run itself is on a branch, so GITHUB_REF_*
# would report master and fall through to 0.0.0.
v="${RELEASE_TAG#v}"
[ -z "$v" ] && [ "$GITHUB_REF_TYPE" = tag ] && v="${GITHUB_REF_NAME#v}"
case "$v" in
[0-9]*) ;;
*) v="0.0.0" ;;
esac
export OUTPUT="monocoque-${v}-x86_64.AppImage"
echo "packaging as $OUTPUT"
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-gtk/raw/master/linuxdeploy-plugin-gtk.sh
chmod +x linuxdeploy-x86_64.AppImage linuxdeploy-plugin-gtk.sh
# Deploy dependencies first, without packaging, so there is a populated
# AppDir to take licences from -- an AppImage distributes every library
# it bundles, so their copyright files have to travel with it. A .deb
# needs none of this because its dependencies stay separate packages.
PATH="$PWD:$PATH" ./linuxdeploy-x86_64.AppImage \
--appdir AppDir \
--plugin gtk \
--desktop-file AppDir/usr/share/applications/monocoque.desktop \
--icon-file tools/monocoque.svg
tools/appimage-collect-licenses.sh AppDir
# monocoque itself and its vendored components are built here rather
# than installed from packages, so dpkg cannot account for them.
install -Dm644 LICENSE.rst AppDir/usr/share/doc/monocoque/LICENSE.rst
install -Dm644 tools/distro/debian/dpkg/copyright AppDir/usr/share/doc/monocoque/copyright
install -Dm644 src/monocoque/mgui/nappgui_src/LICENSE AppDir/usr/share/doc/nappgui/LICENSE
# Now package the AppDir, licences included.
PATH="$PWD:$PATH" ./linuxdeploy-x86_64.AppImage \
--appdir AppDir \
--output appimage
ls -la monocoque*.AppImage
echo "--- licence files in the image ---"
find AppDir/usr/share/doc -name copyright | wc -l
- name: Upload the AppImage as a build artifact
uses: actions/upload-artifact@v4
with:
name: monocoque-x86_64.AppImage
path: monocoque*.AppImage
- name: Release the Package
# Only a tag can publish a release; without this a workflow_dispatch run
# builds everything correctly and then reports failure on a step that
# cannot work, which makes a green build look broken.
if: github.ref_type == 'tag' || inputs.release_tag != ''
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ inputs.release_tag || github.ref_name }}
files: monocoque*.AppImage
# release-please writes the release body from the changelog it just
# generated. Letting this action generate its own notes as well would
# overwrite them, so it only does so for a hand-pushed tag.
generate_release_notes: ${{ inputs.release_tag == '' }}
build-monocoque-flatpak:
# Folded in from the standalone flatpak.yml so every artifact lands on
# one release. Kept as continue-on-error because it is the newest and
# least battle-tested leg: a Flatpak failure must never turn a release
# red or block the deb/rpm/AppImage artifacts, which are independent
# jobs and upload regardless.
runs-on: ubuntu-22.04
continue-on-error: true
permissions:
contents: write
steps:
# No submodules: recursive here -- the manifest fetches simapi and
# nappgui_src itself as explicit `type: git` sources (pinned commits,
# reproducible regardless of what's checked out on disk). Confirmed
# via a failed CI run: recursive submodule checkout populates those
# paths with real .git files first, which then collides with
# flatpak-builder's own git source trying to clone into the same spot
# ("cannot overwrite non-directory .git with directory").
- uses: actions/checkout@v4
# ppa:flatpak/stable, not Ubuntu's own package: 22.04's flatpak-builder
# predates freedesktop Sdk 25.08 dropping the legacy appstream-compose
# binary in favour of `appstreamcli compose`, and fails at the finish
# stage without that fallback.
- name: Install flatpak-builder + freedesktop runtime/SDK
run: |
sudo add-apt-repository -y ppa:flatpak/stable
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y --noninteractive flathub org.freedesktop.Platform//25.08 org.freedesktop.Sdk//25.08
- name: Build .flatpak
working-directory: flatpak
run: |
flatpak-builder --force-clean --repo=repo build-dir io.github.spacefreak18.monocoque.yml
flatpak build-bundle repo monocoque.flatpak io.github.spacefreak18.monocoque
- name: Upload .flatpak as a build artifact
uses: actions/upload-artifact@v4
with:
name: monocoque.flatpak
path: flatpak/monocoque.flatpak
- name: Release the Package
if: github.ref_type == 'tag' || inputs.release_tag != ''
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ inputs.release_tag || github.ref_name }}
files: flatpak/monocoque.flatpak
# release-please writes the release body from the changelog it just
# generated. Letting this action generate its own notes as well would
# overwrite them, so it only does so for a hand-pushed tag.
generate_release_notes: ${{ inputs.release_tag == '' }}
#arch-build:
# runs-on: ubuntu-latest
+27
View File
@@ -0,0 +1,27 @@
name: PR Build & Test
on:
pull_request:
push:
branches: [ "master" ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Checkout submodules
run: git submodule update --init --recursive
- name: Update apt
run: sudo apt update
- name: Install dependencies
# Same list as ci.yaml's ubuntu-latest leg, minus the GUI-only deps
# (libgtk-3-dev, libglu1-mesa-dev) and libcurl4-openssl-dev — this
# workflow builds the CLI + test suite only, not the GUI.
run: sudo apt install -y libuv1-dev libargtable2-dev libserialport-dev libconfig-dev libhidapi-dev liblua5.4-dev libxdg-basedir-dev libxml2-dev libpulse-dev libproc2-dev
- name: Configure CMake
run: cmake -B build -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build --config Debug
- name: Run tests
run: ctest --test-dir build --output-on-failure
+38
View File
@@ -0,0 +1,38 @@
name: release-please
on:
push:
branches: [ master ]
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
# Builds and uploads the packages for the release that was just cut.
#
# This calls ci.yaml rather than relying on its `push: tags` trigger,
# because a tag pushed with the default GITHUB_TOKEN does not start a new
# workflow -- GitHub blocks that deliberately, to stop workflows triggering
# each other in a loop. Calling it keeps the whole release inside one run
# and avoids storing a personal access token on a public repository.
build-release:
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
uses: ./.github/workflows/ci.yaml
with:
release_tag: ${{ needs.release-please.outputs.tag_name }}
permissions:
contents: write
+9
View File
@@ -3,3 +3,12 @@
/src/monocoque/simulatorapi/simapi
.vscode
# flatpak-builder outputs from local builds -- CI regenerates these.
# flatpak/repo in particular is an OSTree store: ~1000 binary objects.
/flatpak/repo/
/flatpak/build-dir/
/flatpak/.flatpak-builder/
# The bundle itself. Missing from this list once already, and a `git add -A`
# duly committed a 6MB build artifact.
*.flatpak
+1
View File
@@ -0,0 +1 @@
{ ".": "0.3.6" }
+17 -55
View File
@@ -12,6 +12,7 @@ SET_SOURCE_FILES_PROPERTIES( src/monocoque.c PROPERTIES LANGUAGE C)
option(BUILD_GUI "Build GUI support" OFF)
option(BUILD_SHARED "Build monocoque shared library" OFF)
option(ENABLE_TESTS "Build test suite" OFF)
project(monocoque)
@@ -72,9 +73,15 @@ pkg_check_modules(LIBPROC2 libproc2)
if (LIBPROCPS_FOUND)
#add_compile_definitions(USE_OLD_PID_VAL=0)
elseif (LIBPROC2_FOUND)
if (LIBPROC2_VERSION VERSION_GREATER_EQUAL "4.0.5")
#add_compile_definitions(USE_OLD_PID_VAL=0)
else()
# Some distro packagings (e.g. the freedesktop Flatpak SDK) ship a
# libproc2.pc with `Version: UNKNOWN` rather than a real version
# string. VERSION_GREATER_EQUAL against that always evaluates false,
# silently falling through to the old (pre-4.0.5) PIDS_VAL API and
# failing to compile against an actually-current libproc2 whose real
# header has already moved to the new 3-argument macro. Only take the
# old-API branch when the version string is genuinely parseable and
# actually old.
if (LIBPROC2_VERSION MATCHES "^[0-9]" AND LIBPROC2_VERSION VERSION_LESS "4.0.5")
add_compile_definitions(USE_OLD_PID_VAL=1)
endif()
else()
@@ -107,57 +114,6 @@ endif()
#add_executable(listusb tests/testlibusb.c)
#target_include_directories(listusb PUBLIC)
#target_link_libraries(listusb portaudio hidapi-hidraw)
#add_test(listusb list-usb-devices listusb)
#add_executable(testrevburner tests/testrevburner.c)
#target_include_directories(testrevburner PUBLIC)
#target_link_libraries(testrevburner hidapi-hidraw)
#add_test(testrevburner testrevburner)
#add_executable(listsound tests/pa_devs.c)
#target_include_directories(listsound PUBLIC)
#target_link_libraries(listsound m portaudio)
#add_test(list-sound-devices listsound)
#
#add_executable(longsine tests/patest_longsine.c)
#target_include_directories(longsine PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(longsine m portaudio)
#add_test(longsine longsine)
#
#add_executable(parserevburnerxml tests/revburnerparsetest.c)
#target_include_directories(parserevburnerxml PUBLIC ${LIBXML_INCLUDE_DIR})
#target_link_libraries(parserevburnerxml portaudio xml2)
#add_test(parserevburnerxml parserevburnerxml)
#
add_executable(setmem tests/setmem.c)
target_include_directories(setmem PUBLIC)
target_link_libraries(setmem)
add_test(setmem setmem)
add_executable(getmem tests/getmem.c)
target_include_directories(getmem PUBLIC)
target_link_libraries(getmem)
add_test(getmem getmem)
#
#add_executable(setsimdata tests/setsimdata.c)
#target_include_directories(setsimdata PUBLIC)
#target_link_libraries(setsimdata)
#add_test(setsimdata setsimdata)
#
#add_executable(hidtest tests/hidtest.c)
#target_include_directories(hidtest PUBLIC)
#target_link_libraries(hidtest hidapi-hidraw)
#add_test(hidtest hidtest)
#
add_executable(simlighttest tests/simlighttest.c)
target_include_directories(simlighttest PUBLIC)
target_link_libraries(simlighttest serialport)
add_test(simlighttest simlighttest)
# used for enabling additional compiler options if supported
include(CheckCXXCompilerFlag)
@@ -221,6 +177,12 @@ endif()
# unit tests --only enable if requested AND we're not building as a sub-project
if(ENABLE_TESTS AND NOT MONOCOQUE_SUBPROJECT)
message(STATUS "[monocoque] Unit Tests Enabled")
add_subdirectory(tests)
enable_testing()
add_subdirectory(tests)
endif()
install(TARGETS monocoque-cli RUNTIME DESTINATION bin)
if(BUILD_GUI)
install(TARGETS monocoque-gui RUNTIME DESTINATION bin)
endif()
install(FILES tools/monocoque.desktop DESTINATION share/applications)
@@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=Monocoque
Comment=Device manager for racing sims
Exec=gmonocoque
Icon=io.github.spacefreak18.monocoque
Terminal=false
Categories=Game;Development;
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.spacefreak18.monocoque</id>
<name>Monocoque</name>
<summary>Device manager for racing sims</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-only</project_license>
<description>
<p>
Monocoque bridges telemetry from supported racing simulators to
peripheral devices such as haptic shakers, LED strips, shift lights,
and sim wind fans, and exposes a local API for third-party dashboard
and configuration tools.
</p>
</description>
<launchable type="desktop-id">io.github.spacefreak18.monocoque.desktop</launchable>
<provides>
<binary>monocoque</binary>
<binary>gmonocoque</binary>
</provides>
<url type="homepage">https://spacefreak18.github.io/simapi/monocoque.html</url>
<url type="vcs-browser">https://github.com/Spacefreak18/monocoque</url>
<content_rating type="oars-1.1" />
<releases>
<release version="0.3.6" date="2026-08-21" />
</releases>
</component>
@@ -0,0 +1,320 @@
# Flatpak manifest for monocoque -- NOT submitted anywhere (Flathub or
# otherwise) yet. Built 2026-08-30 on the patterns proven working for the
# sibling typiql-tauri/typiql project's own Flatpak pipeline (see this
# repo's .github/workflows/flatpak.yml header for the full list of bugs
# found and fixed here, monocoque-specific beyond what that sibling project
# already covered). VERIFIED LOCALLY end-to-end: built, installed, and ran
# both `monocoque --help` and `gmonocoque` from the resulting bundle. Not
# yet verified against real CI or real hardware (HID/serial/USB device
# access under the sandbox).
#
# org.freedesktop.Platform, not org.gnome.Platform: monocoque's GUI
# (gmonocoque) only needs GTK3, which freedesktop.Platform//25.08 already
# ships -- no need for the heavier GNOME runtime typiql needs for WebKitGTK.
# simd is NOT bundled. It is a separate daemon with its own packaging, and
# monocoque does not need it inside the sandbox to use it: simapi_get_sim()
# checks /dev/shm/SIMAPI.DAT before it ever scans /proc, so a simd running on
# the host -- however it was installed -- publishes telemetry this sandbox
# reads directly. That is what --device=shm below is for, and it is the only
# thing this manifest needs in order to work with simd.
#
# simapi itself is still present, but only as monocoque's own statically
# linked submodule, exactly as upstream's CMakeLists builds it. There is no
# separate simapi module here.
app-id: io.github.spacefreak18.monocoque
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
command: gmonocoque
finish-args:
# --socket=x11, not fallback-x11: nappgui (the GUI toolkit gmonocoque uses)
# goes to X11 even when a Wayland display is available. fallback-x11 is
# deliberately inactive whenever Wayland works, so under a Wayland session
# DISPLAY stayed empty and gmonocoque died with `cannot open display` --
# confirmed on a real launch, with WAYLAND_DISPLAY=wayland-0 present and the
# socket visible inside the sandbox. Granting real X11 routes it through
# XWayland instead. --socket=wayland is kept so the toolkit can use it
# directly if that ever changes.
- --socket=x11
- --socket=wayland
# Standard companion to X11 access: without it MIT-SHM is unavailable and
# some toolkits fall over.
- --share=ipc
- --socket=pulseaudio
# HID/serial/USB access for wheels, pedals, shifters, and shaker/LED
# devices -- known risk area, Flatpak's sandboxing of raw device nodes is
# not always well-behaved; needs real hardware testing, not just a
# successful build.
- --device=all
# Retained, but not for the reason first written here: the GraphQL API on
# port 9000 is served by typiql's own Rust backend, not by monocoque --
# monocoque has no network code of its own, and the only libcurl in the
# binary is vendored nappgui's HTTP module, which nothing here calls. The
# two programs talk through ~/.config/monocoque and the process table, not
# a socket. This flag can probably be dropped.
- --share=network
# monocoque builds its paths from $HOME directly (e.g.
# "%s/.config/monocoque/diameters.config" in monocoque-cli.c), not from
# XDG_CONFIG_HOME, so it reads and writes the host's real directories.
# Without these grants a real launch failed with
# Failed to read config file '/home/david/.config/monocoque/monocoque.config'
# slog_open_file: Failed to open file: /home/david/.cache/monocoque/...log
# -- the manifest previously granted no filesystem access at all. Sharing
# the real config directory is also what makes a Flatpak monocoque and a
# native one agree, and what lets typiql configure it.
- --filesystem=xdg-config/monocoque:create
- --filesystem=xdg-cache/monocoque:create
# Host /dev/shm, where a host simd publishes telemetry as POSIX shared memory
# (/dev/shm/SIMAPI.DAT, mapped in simapi's simmapper.c). This is the flag
# that makes a Flatpak monocoque work with a simd installed on the host, so
# it matters more now that simd is not bundled, not less.
#
# shm is its own device option and is NOT implied by --device=all above --
# measured, with simd running: `ls /dev/shm` inside this sandbox returned 0
# entries against 18 on the host. The failure it caused is silent rather
# than loud: `monocoque play` started, read its config, connected
# pulseaudio, and then sat at "setting initial app state" forever, never
# logging "Opening universal shared memory api", because simd looked absent.
# The identical run with this flag reached that line one second in.
- --device=shm
modules:
- name: libconfig
buildsystem: cmake-ninja
config-opts:
- -DBUILD_TESTS=OFF
# libconfig 1.7.3's CMakeLists.txt predates CMake 3.5's minimum
# version policy; confirmed via a failed local build.
- -DCMAKE_POLICY_VERSION_MINIMUM=3.5
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/libconfig/$(basename "$f"); else echo "WARNING: no licence file found for libconfig"; fi'
sources:
- type: archive
url: https://github.com/hyperrealm/libconfig/archive/refs/tags/v1.7.3.tar.gz
sha256: 68757e37c567fd026330c8a8449aa5f9cac08a642f213f2687186b903bd7e94e
- name: argtable2
buildsystem: cmake-ninja
config-opts:
# Same CMake-minimum-version issue as libconfig -- this one's
# CMakeLists.txt is even older (2011).
- -DCMAKE_POLICY_VERSION_MINIMUM=3.5
# 2011-era code missing <ctype.h>/<strings.h> includes for
# isspace/toupper/bzero; GCC 14+ made implicit-function-declaration a
# hard error by default where it used to just warn. Confirmed via a
# failed local build.
- -DCMAKE_C_FLAGS=-Wno-error=implicit-function-declaration
# add_library(argtable2 ...) has no explicit STATIC/SHARED, so it
# defaults to CMake's global BUILD_SHARED_LIBS (off by default -> a
# static .a). monocoque's own target_link_libraries() lists argtable2
# before helper (which needs its symbols, e.g. arg_end/arg_parse in
# parameters.c) -- fine for a shared library (all symbols always
# available regardless of link-line position, which is what real
# distro packages of this ship), but a static archive only pulls
# symbols already needed by things linked *before* it, so helper's
# later reference to argtable2's symbols never resolves. Confirmed
# via a failed local build ("undefined reference to arg_end" etc.
# from helper's parameters.c, even though libargtable2.a genuinely
# contained those symbols). Building shared instead matches how this
# dependency normally ships and avoids the link-order sensitivity
# entirely, rather than reordering every target_link_libraries() call
# in CMakeLists.txt.
- -DBUILD_SHARED_LIBS=ON
# This CMake port has no install() rules at all (confirmed: no
# CMakeLists.txt in the tree calls install()), so the default
# cmake-ninja `ninja install` step silently does nothing -- monocoque's
# own build then fails on a missing argtable2.h. build-commands here
# replace the default install step: `ninja` still does the real
# compile, then copy the header and whatever library form actually got
# built (glob rather than a fixed versioned filename, since the exact
# .so version suffix isn't predictable without a build).
build-commands:
- ninja
- install -Dm644 src/argtable2.h /app/include/argtable2.h
- |
for f in src/libargtable2.so* src/libargtable2.a; do
if [ -e "$f" ]; then cp -P "$f" /app/lib/; fi
done
true
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/argtable2/$(basename "$f"); else echo "WARNING: no licence file found for argtable2"; fi'
sources:
- type: archive
url: https://sourceforge.net/projects/argtable/files/argtable/argtable-2.13/argtable2-13.tar.gz/download
sha256: 8f77e8a7ced5301af6e22f47302fdbc3b1ff41f2b83c43c77ae5ca041771ddbf
dest-filename: argtable2-13.tar.gz
- name: lua5.4
# Lua's own Makefile, not CMake/autotools. `posix` (not `linux`) avoids
# a readline dependency only needed for the interactive REPL binary,
# which monocoque doesn't use -- only the library.
buildsystem: simple
build-commands:
- make posix MYCFLAGS=-fPIC
- make install INSTALL_TOP=/app
sources:
- type: archive
url: https://www.lua.org/ftp/lua-5.4.7.tar.gz
sha256: 9fbf5e28ef86c69858f6d3d34eccc32e911c1a28b4120ff3e84aaa70cfbf1e30
- name: libserialport
buildsystem: autotools
# No pre-generated configure script in the git-archive tarball, only
# autogen.sh.
build-commands:
- ./autogen.sh
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/libserialport/$(basename "$f"); else echo "WARNING: no licence file found for libserialport"; fi'
sources:
- type: archive
url: https://github.com/sigrokproject/libserialport/archive/refs/tags/libserialport-0.1.2.tar.gz
sha256: cbb1192a09ff31d34e7efdb17a2f50d9d1974461c0b81c29bb449515d78d8950
- name: libxdg-basedir
buildsystem: autotools
build-commands:
- ./autogen.sh
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/libxdg-basedir/$(basename "$f"); else echo "WARNING: no licence file found for libxdg-basedir"; fi'
sources:
- type: archive
url: https://github.com/devnev/libxdg-basedir/archive/refs/tags/libxdg-basedir-1.2.3.tar.gz
sha256: ff30c60161f7043df4dcc6e7cdea8e064e382aa06c73dcc3d1885c7d2c77451d
- name: hidapi
buildsystem: cmake-ninja
config-opts:
# Same CMake-minimum-version issue as libconfig/argtable2, despite
# this otherwise being a current, actively maintained release.
- -DCMAKE_POLICY_VERSION_MINIMUM=3.5
# monocoque links hidapi-hidraw specifically -- no need for the
# libusb-backed variant, which would pull in an extra dependency.
- -DHIDAPI_WITH_LIBUSB=OFF
- -DHIDAPI_WITH_HIDRAW=ON
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/hidapi/$(basename "$f"); else echo "WARNING: no licence file found for hidapi"; fi'
sources:
- type: archive
url: https://github.com/libusb/hidapi/archive/refs/tags/hidapi-0.14.0.tar.gz
sha256: a5714234abe6e1f53647dd8cba7d69f65f71c558b7896ed218864ffcf405bcbd
- name: glu
buildsystem: meson
sources:
- type: archive
url: https://gitlab.freedesktop.org/mesa/glu/-/archive/glu-9.0.3/glu-glu-9.0.3.tar.gz
sha256: 7e919cbc1b2677b01d65fc28fd36a19d1f3e23d76663020e0f3b82b991475e8b
- name: libuv
buildsystem: cmake-ninja
config-opts:
- -DBUILD_TESTING=OFF
post-install:
- sh -c 'f=$(ls -1 COPYING COPYING.txt COPYING.LIB LICENSE LICENSE.txt LICENSE.md LICENCE licence.txt 2>/dev/null | head -1); if [ -n "$f" ]; then install -Dm644 "$f" /app/share/licenses/libuv/$(basename "$f"); else echo "WARNING: no licence file found for libuv"; fi'
sources:
- type: archive
url: https://github.com/libuv/libuv/archive/refs/tags/v1.49.2.tar.gz
sha256: 388ffcf3370d4cf7c4b3a3205504eea06c4be5f9e80d2ab32d19f8235accc1cf
- name: monocoque
buildsystem: cmake-ninja
config-opts:
- -DBUILD_GUI=on
- -DCMAKE_BUILD_TYPE=Release
# CMakeLists.txt links most of the dependencies built as separate
# flatpak modules above (hidapi-hidraw, serialport, argtable2, config,
# uv, xdg-basedir) by bare library name with no explicit -L, relying on
# the linker's default search path -- fine on a real system where these
# install to /usr/lib, but /app/lib isn't in that default path.
# -DCMAKE_EXE_LINKER_FLAGS=-L/app/lib didn't work: CMake appends
# EXE_LINKER_FLAGS at the *end* of the link command, after the -l
# flags that need it, and ld resolves -l against -L directories seen
# so far, left to right -- confirmed via a failed local build showing
# the exact same missing-library set with that flag present but
# useless. LIBRARY_PATH is a GCC driver environment variable, applied
# to its search regardless of where in the command line things land.
build-options:
env:
LIBRARY_PATH: /app/lib
sources:
# One level up from flatpak/manifest.yml is the repo root -- unlike
# typiql-tauri/typiql's dual-checkout ($GITHUB_WORKSPACE containing
# two separate repos side by side, needing an extra level), monocoque
# is checked out on its own with the standard single-repo layout, so
# this doesn't need the same `../..`/`../../..` juggling that session
# got wrong twice before finding the right depth for that project.
- type: dir
path: ..
# Skip the submodule paths. If the tree being built has them checked
# out, the copy brings along a real `.git` *file* at each path, and the
# git sources below then fail to clone into the same spot: "cannot
# overwrite non-directory .git with directory". Without this the
# manifest only builds from a checkout that deliberately omits
# submodules -- which is why CI's flatpak job checks out without them,
# and why a local build right after `git submodule update --init`
# breaks. Skipping makes it work either way.
skip:
- src/monocoque/simulatorapi/simapi
- src/monocoque/mgui/nappgui_src
# Two git submodules, each pinned to the exact commit .gitmodules/the
# tree tracks -- confirmed via a failed local build that the `dir`
# source above doesn't pull submodule content in (same class of issue
# as typiql-tauri/typiql's own submodules, src/lib/per-form etc.).
- type: git
url: https://github.com/spacefreak18/simapi
commit: 50fd181681862256780b2a0f74ef4bc459ed631a
dest: src/monocoque/simulatorapi/simapi
# nappgui_src is add_subdirectory()'d directly into monocoque's own
# CMake tree (src/monocoque/mgui/CMakeLists.txt), not a separately
# installed library -- so it's a source here, not its own flatpak
# module.
- type: git
url: https://github.com/frang75/nappgui_src
commit: 29c7bd3e0243eb38aa9a7e2eafe6cf74830c4ee8
dest: src/monocoque/mgui/nappgui_src
- type: file
path: io.github.spacefreak18.monocoque.desktop
- type: file
path: io.github.spacefreak18.monocoque.metainfo.xml
# Icon comes from tools/monocoque.svg via the `dir` source above (no
# separate file source needed). That file is a square 100x100 copy of
# the upstream artwork -- the published monocoque.svg the deb job
# downloads is 100x50, which Flatpak's export rejects outright, while
# appstreamcli separately hard-requires any desktop-application to
# have an icon at all (both confirmed via failed real CI runs). It is
# padded via a <g transform="translate(0,25)">, not stretched. Shared
# with the AppImage job, which has the same square-icon need.
post-install:
# This package's own licence, the vendored nappgui's (a source rather
# than a module, so the per-module collection above misses it), and the
# notices file naming every bundled dependency's origin.
- install -Dm644 LICENSE.rst /app/share/licenses/monocoque/LICENSE.rst
# The Debian copyright file is upstream's own account of what is in this
# source tree and under what terms -- slog (MIT), nappgui (MIT), simapi
# (LGPL) -- which a bundle has to carry because it distributes all of
# them, unlike a .deb whose dependencies are separate packages. Shipped
# verbatim rather than restated.
- install -Dm644 tools/distro/debian/dpkg/copyright /app/share/licenses/monocoque/copyright
# lua and glu ship no licence file in their tarballs -- Lua's MIT text
# lives in doc/readme.html, glu's SGI Free B only in source headers -- so
# checked-in copies are installed from here, where the repo is the build
# directory. (Doing it in their own modules fails: those build
# out-of-tree, so their source directory is not the working directory.)
- install -Dm644 packaging/licenses/lua-5.4-LICENSE.txt /app/share/licenses/lua5.4/LICENSE
- install -Dm644 packaging/licenses/glu-LICENSE.txt /app/share/licenses/glu/LICENSE
- install -Dm644 src/monocoque/mgui/nappgui_src/LICENSE /app/share/licenses/nappgui/LICENSE
- sh -c 'python3 tools/generate-third-party-notices.py flatpak/io.github.spacefreak18.monocoque.yml > /tmp/notices.md && install -Dm644 /tmp/notices.md /app/share/licenses/THIRD-PARTY-NOTICES.md'
# Confirmed via a failed local build that flatpak-builder's cmake-ninja
# buildsystem runs the automatic build+install step regardless of
# whether build-commands are also given -- these run in *addition*,
# not instead. So the fix for simlighttest (a stray, always-on scratch
# test executable that failed to link -lserialport, a pre-existing
# CMakeLists.txt bug unrelated to Flatpak) had to be commenting it out
# at the source, not overriding the build here. With that gone, the
# automatic build+install (using this repo's own new install() rules)
# already installs monocoque/gmonocoque correctly; these build-commands
# only need to add the extra files CMake doesn't know about.
build-commands:
- install -Dm644 io.github.spacefreak18.monocoque.desktop /app/share/applications/io.github.spacefreak18.monocoque.desktop
- install -Dm644 io.github.spacefreak18.monocoque.metainfo.xml /app/share/metainfo/io.github.spacefreak18.monocoque.metainfo.xml
- install -Dm644 tools/monocoque.svg /app/share/icons/hicolor/scalable/apps/io.github.spacefreak18.monocoque.svg
+40
View File
@@ -0,0 +1,40 @@
SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice including the dates of first publication and
either this permission notice or a reference to
http://oss.sgi.com/projects/FreeB/
shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Except as contained in this notice, the name of Silicon Graphics, Inc.
shall not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization from
Silicon Graphics, Inc.
/
Pixel storage modes */
typedef struct {
GLint pack_alignment;
GLint pack_row_length;
GLint pack_skip_rows;
GLint pack_skip_pixels;
GLint pack_lsb_first;
GLint pack_swap_bytes;
GLint pack_skip_images;
GLint pack_image_height;
+19
View File
@@ -0,0 +1,19 @@
Copyright © 1994–2026 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+31
View File
@@ -0,0 +1,31 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "simple",
"package-name": "monocoque",
"//": "The 79 existing tags are bare semver (0.3.6), not v0.3.6, and there is only one package here. Both flags keep release-please tagging in that same series instead of starting a parallel one.",
"include-component-in-tag": false,
"include-v-in-tag": false,
"//bump": "While the major version is 0, a breaking change bumps the minor (0.3.6 -> 0.4.0) rather than declaring 1.0.0. Reaching 1.0.0 stays a deliberate act.",
"bump-minor-pre-major": true,
"draft": false,
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements", "hidden": true },
{ "type": "revert", "section": "Reverts", "hidden": true },
{ "type": "docs", "section": "Documentation", "hidden": true },
{ "type": "style", "section": "Styles", "hidden": true },
{ "type": "chore", "section": "Miscellaneous Chores", "hidden": true },
{ "type": "refactor", "section": "Code Refactoring", "hidden": true },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "build", "section": "Build System", "hidden": true },
{ "type": "ci", "section": "Continuous Integration", "hidden": true }
]
}
}
}
+2
View File
@@ -245,6 +245,8 @@ DeviceSettings;
int strtogame(const char* game, MonocoqueSettings* ms);
int strtodevsubsubtype(const char* device_subsubtype, DeviceSettings* ds);
int devsetup(const char* device_type, const char* device_subtype, const char* config_files, MonocoqueSettings* ms, DeviceSettings* ds, config_setting_t* device_settings);
int settingsfree(DeviceSettings ds);
+11
View File
@@ -0,0 +1,11 @@
# Automated CI test suite — only built/run when ENABLE_TESTS is on (see
# root CMakeLists.txt). Manual, interactive, and hardware-dependent scratch
# tools live in tests/manual/ instead and are never built by this file.
add_executable(confighelper_test confighelper_test.c)
# helper (confighelper.c specifically) references slog/xml2/simulatorapi
# symbols elsewhere in the same translation unit — static libs resolve per
# object file, so all of these are needed even though this test only
# exercises strtodevsubsubtype.
target_link_libraries(confighelper_test helper config slog xml2 simulatorapi m proc2)
add_test(NAME confighelper_test COMMAND confighelper_test)
+45
View File
@@ -0,0 +1,45 @@
// Proof-of-plumbing test for the new CTest wiring — not an attempt at
// comprehensive coverage. Exercises strtodevsubsubtype (helper/confighelper.c),
// a pure string->enum mapping with no I/O/hardware, including the R8/R3
// aliasing onto SIMDEVSUBTYPE_MOZAR5 and the fallback for unrecognized input.
#include <stdio.h>
#include <string.h>
#include "../src/monocoque/helper/confighelper.h"
static int failures = 0;
static void check(const char* input, DeviceSubSubType expected)
{
DeviceSettings ds = {0};
strtodevsubsubtype(input, &ds);
if (ds.dev_subsubtype != expected)
{
fprintf(stderr, "FAIL: strtodevsubsubtype(\"%s\") = %d, expected %d\n",
input, ds.dev_subsubtype, expected);
failures++;
}
}
int main(void)
{
check("MozaR5", SIMDEVSUBTYPE_MOZAR5);
check("MozaR8", SIMDEVSUBTYPE_MOZAR5); // aliased onto the same protocol as R5
check("MozaR3", SIMDEVSUBTYPE_MOZAR5); // same
check("MozaNew", SIMDEVSUBTYPE_MOZA_NEW);
check("MozaKSProWheel", SIMDEVSUBTYPE_MOZA_KS_PRO_WHEEL);
check("CammusC5", SIMDEVSUBTYPE_CAMMUSC5);
check("CammusC12", SIMDEVSUBTYPE_CAMMUSC12);
check("LogitechG29", SIMDEVSUBTYPE_LOGITECH_G29);
check("not-a-real-subtype", SIMDEVSUBTYPE_UNKNOWN);
check("", SIMDEVSUBTYPE_UNKNOWN);
if (failures > 0)
{
fprintf(stderr, "%d check(s) failed\n", failures);
return 1;
}
printf("confighelper_test: all checks passed\n");
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Collect licence and copyright information for everything an AppImage bundles.
#
# usage: tools/appimage-collect-licenses.sh <AppDir>
#
# A .deb declares only what it ships, because its dependencies remain separate
# packages carrying their own copyright files. An AppImage carries those
# libraries inside it, so their notices have to travel with it -- and most of
# them here are LGPL (GTK, glib, pango and friends), where the obligation also
# covers saying where the corresponding source can be had.
#
# The mapping is mechanical rather than researched: every bundled library came
# from a Debian/Ubuntu package on the build host, so dpkg can name it, and the
# archive already holds a copyright file for each. Run this after linuxdeploy
# has populated the AppDir and before it packages the image.
set -euo pipefail
APPDIR="${1:?AppDir path}"
DOCDIR="$APPDIR/usr/share/doc"
MANIFEST="$DOCDIR/BUNDLED-LIBRARIES.txt"
mkdir -p "$DOCDIR"
{
echo "Libraries bundled in this AppImage"
echo "=================================="
echo
echo "Each library below was taken from the Debian/Ubuntu package named"
echo "beside it on the build host. That package's copyright file is included"
echo "under usr/share/doc/<package>/copyright in this image."
echo
echo "The corresponding source for any of them can be obtained with:"
echo " apt-get source <package>=<version>"
echo "from the distribution and release recorded below."
echo
echo "Build host: $( (. /etc/os-release && echo "$PRETTY_NAME") 2>/dev/null || echo unknown)"
echo
printf '%-44s %-34s %s\n' "LIBRARY" "PACKAGE" "VERSION"
} > "$MANIFEST"
found=0
unowned=0
while IFS= read -r so; do
base="$(basename "$so")"
pkg=""
# Try the usual multiarch location first, then fall back to a name search.
for candidate in "/usr/lib/x86_64-linux-gnu/$base" "/lib/x86_64-linux-gnu/$base" "/usr/lib/$base"; do
pkg="$(dpkg -S "$candidate" 2>/dev/null | head -1 | cut -d: -f1 || true)"
[ -n "$pkg" ] && break
done
if [ -z "$pkg" ]; then
pkg="$(dpkg -S "$base" 2>/dev/null | head -1 | cut -d: -f1 || true)"
fi
if [ -n "$pkg" ]; then
ver="$(dpkg-query -W -f='${Version}' "$pkg" 2>/dev/null || echo unknown)"
printf '%-44s %-34s %s\n' "$base" "$pkg" "$ver" >> "$MANIFEST"
if [ -f "/usr/share/doc/$pkg/copyright" ] && [ ! -f "$DOCDIR/$pkg/copyright" ]; then
install -Dm644 "/usr/share/doc/$pkg/copyright" "$DOCDIR/$pkg/copyright"
fi
found=$((found + 1))
else
# Built by this job rather than installed from a package -- its licence is
# collected separately, from its own source tree.
printf '%-44s %-34s %s\n' "$base" "(built from source in this job)" "-" >> "$MANIFEST"
unowned=$((unowned + 1))
fi
done < <(find "$APPDIR" -name '*.so*' -type f | sort)
echo >> "$MANIFEST"
echo "$found libraries from distribution packages, $unowned built in this job." >> "$MANIFEST"
echo "collected copyright for $found bundled libraries ($unowned built here)"
echo "manifest: $MANIFEST"
@@ -5,4 +5,4 @@ Priority: optional
Architecture: amd64
Maintainer: Paul Jones <paul@spacefreak18.xyz>
Description: Racing Simulator Device Manager
Depends: libpulse0,libconfig11,libargtable2-0,liblua5.4-0,libuv1t64,libserialport0,libxml2,libxdg-basedir1,libhidapi-hidraw0,libgtk-3-0t64,libcurl4t64,libglu1-mesa
Depends: libpulse0,libconfig11,libargtable2-0,liblua5.4-0,libuv1t64,libserialport0,libxml2-16,libxdg-basedir1,libhidapi-hidraw0,libgtk-3-0t64,libcurl4t64,libglu1-mesa
@@ -5,4 +5,4 @@ Priority: optional
Architecture: amd64
Maintainer: Paul Jones <paul@spacefreak18.xyz>
Description: Racing Simulator Device Manager
Depends: libpulse0,libconfig9,libargtable2-0,liblua5.4-0,libuv1,libserialport0,libxml2,libxdg-basedir1,libhidapi-hidraw0,libglu1-mesa,libcurl4,libgtk-3-0
Depends: libpulse0,libconfig11,libargtable2-0,liblua5.4-0,libuv1t64,libserialport0,libxml2-16,libxdg-basedir1,libhidapi-hidraw0,libglu1-mesa,libcurl4t64,libgtk-3-0t64
+13 -6
View File
@@ -15,14 +15,21 @@ Requires: pulseaudio-libs argtable libconfig hidapi libserialport libuv libxdg-b
%description
A device manager for Racing sims
# Builds whatever tree has been staged at %{_sourcedir}/monocoque, cloning it
# from upstream master only if nothing is staged. The unconditional clone this
# replaced meant an rpm's contents tracked master rather than the tag being
# built -- so a fix on the branch being released was absent from its own
# release. CI stages the checked-out tree; a bare `rpmbuild -ba` on a
# workstation still works exactly as before.
%prep
rm -rf $RPM_BUILD_DIR/monocoque
rm -rf $RPM_SOURCE_DIR/monocoque
cd $RPM_SOURCE_DIR
git clone https://github.com/spacefreak18/monocoque
cd monocoque
git submodule update --init --recursive
cd ..
if [ ! -d $RPM_SOURCE_DIR/monocoque ]; then
cd $RPM_SOURCE_DIR
git clone https://github.com/spacefreak18/monocoque
cd monocoque
git submodule update --init --recursive
cd ..
fi
cp -r $RPM_SOURCE_DIR/monocoque $RPM_BUILD_DIR/
%build
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
"""Generate a third-party notices file from the Flatpak manifest.
A .deb lists only what it actually ships, because its dependencies are separate
packages carrying their own copyright files. A Flatpak or AppImage distributes
those libraries itself, so the notices have to travel with the artifact -- and
for the LGPL ones (libconfig, argtable2, libserialport, orcania, yder) that
includes saying where the corresponding source can be obtained.
The manifest already pins every dependency by URL and sha256, which is exactly
that information, so this is generated from it rather than maintained by hand
where it would drift.
"""
import re
import sys
from pathlib import Path
manifest = Path(sys.argv[1] if len(sys.argv) > 1
else "flatpak/io.github.spacefreak18.monocoque.yml")
text = manifest.read_text()
entries, name = [], None
for line in text.splitlines():
m = re.match(r"^ - name: (\S+)", line)
if m:
name = m.group(1)
entries.append({"name": name, "url": None, "sha256": None, "commit": None, "tag": None})
elif entries:
for key in ("url", "sha256", "commit", "tag"):
k = re.match(rf"^\s+{key}: (\S+)", line)
if k and entries[-1][key] is None:
entries[-1][key] = k.group(1)
out = [
"# Third-party notices",
"",
"This package bundles the libraries below. Each one's own licence text is",
"installed alongside it under `/app/share/licenses/<name>/`.",
"",
"Where a bundled library is under the LGPL, the corresponding source is the",
"exact archive listed here, identified by URL and SHA-256; the same version",
"can be rebuilt from it, and the Flatpak links these libraries dynamically.",
"",
"| Component | Source | Checksum / revision |",
"|---|---|---|",
]
for e in entries:
if not e["url"]:
continue
rev = e["sha256"] or e["commit"] or e["tag"] or ""
out.append(f"| {e['name']} | {e['url']} | `{rev[:16]}{'…' if len(rev) > 16 else ''}` |")
out += [
"",
"Generated by tools/generate-third-party-notices.py from the Flatpak",
"manifest -- do not edit by hand.",
"",
]
print("\n".join(out))
+1 -1
View File
@@ -3,7 +3,7 @@ Version=1.0
Type=Application
Name=Monocoque
Comment=Launch Monocoque
Exec=/usr/bin/gmonocoque
Exec=gmonocoque
Icon=monocoque
Terminal=false
Categories=Game;Development;
+49
View File
@@ -0,0 +1,49 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100%" height="100%">
<!-- Square Flatpak icon canvas wrapping the real monocoque.svg artwork
(fetched from https://repo.spacefreak18.xyz/monocoque/icons/monocoque.svg,
viewBox 0 0 100 50), vertically centered via translate(0,25) rather
than stretched. Flatpak's export step requires square icons and
appstreamcli additionally requires any desktop-application to have
one at all, confirmed via two failed real CI runs. -->
<g transform="translate(0,25)">
<!-- Main Body / Chassis -->
<path d="M 25 28 C 35 28, 40 22, 55 22 L 72 24 C 76 24, 80 28, 85 28 L 85 34 L 25 34 Z" fill="#E10600" />
<!-- Nose Cone -->
<path d="M 25 28 L 12 30 C 10 30.5, 10 32.5, 12 33 L 25 34 Z" fill="#C00500" />
<!-- Front Wing -->
<rect x="5" y="31" width="10" height="4" rx="1" fill="#1A1A1A" />
<path d="M 12 31 L 12 35" stroke="#FFFFFF" stroke-width="1" />
<!-- Rear Wing -->
<path d="M 82 28 L 84 15 L 92 15 L 90 28 Z" fill="#1A1A1A" />
<rect x="80" y="13" width="14" height="4" rx="0.5" fill="#1A1A1A" />
<!-- Engine Cover / Airbox Intake -->
<path d="M 58 22 C 58 16, 64 16, 66 16 L 70 24 Z" fill="#E10600" />
<ellipse cx="61" cy="19" rx="2" ry="1.5" fill="#1A1A1A" />
<!-- Cockpit / Driver Helmet -->
<path d="M 48 23 C 48 20, 54 20, 54 23 Z" fill="#1A1A1A" />
<circle cx="52" cy="19" r="2.5" fill="#FFFFFF" />
<path d="M 51.5 17.5 L 54.5 18.5 L 53.5 20.5 L 51.5 19.5 Z" fill="#1A1A1A" /> <!-- Visor -->
<!-- Bargeboard / Sidepod Detail -->
<path d="M 38 27 L 55 25 L 58 34 L 36 34 Z" fill="#B00400" />
<!-- Wheels (Tires & Rims) -->
<!-- Rear Wheel -->
<circle cx="78" cy="32" r="11" fill="#1A1A1A" />
<circle cx="78" cy="32" r="5" fill="#4A4A4A" />
<circle cx="78" cy="32" r="2" fill="#D4AF37" />
<!-- Front Wheel -->
<circle cx="22" cy="33" r="9" fill="#1A1A1A" />
<circle cx="22" cy="33" r="4.2" fill="#4A4A4A" />
<circle cx="22" cy="33" r="1.8" fill="#D4AF37" />
<!-- Ground Shadow -->
<ellipse cx="50" cy="44" rx="42" ry="2" fill="#000000" fill-opacity="0.2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
0.3.6