nandi/frqpublic Fork 0
9db383cd55e49cc0c9fc80cf49e2e10c2fd034a9
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

build-desktop.sh · 145 lines · 6.4 KBBash Blame HistoryRaw
A Mesa nobody needed, and the AppImage that carried it 9db383c nandi 21h ago1#!/usr/bin/env bash
2# The cosmic desktop build: stage a runtime, its objects and the source next
3# to each other, and write a launcher that starts them.
4#
5# There is no compilation here of anything written in Jolt — jolt reads
6# deps.edn and the source at startup, which is what `nix build .#frq` was also
7# doing behind a wrapper script. What that flake output added was a closure:
8# a Mesa, a nixGL to put the host's driver in front of it, and a store path
9# per dependency. `.#appimage` then squashed the lot into one file so a
10# machine without nix could run it.
11#
12# This builds the same program without any of that. The pieces arrive pinned
13# from `tools/desktop-toolchain.sh`, the one thing that IS compiled is a
14# single .c file, and what comes out is a directory that runs from wherever
15# it is unpacked.
16#
17# tools/build-desktop.sh build build/desktop
18# tools/build-desktop.sh tar ...and tar it up beside itself
19# tools/build-desktop.sh run ...and start it
20#
21# The container in `.modal/frq/` runs this same file, the way
22# `.modal/flutter-web/` runs tools/build-web.sh.
23set -euo pipefail
24
25root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
26action="${1:-build}"
27
28case "$action" in build|tar|run) ;; *)
29 echo "usage: build-desktop.sh [build|tar|run]" >&2; exit 1 ;;
30esac
31
32eval "$("$root/tools/desktop-toolchain.sh" env)"
33
34out="${FRQ_DESKTOP_OUT:-$root/build/desktop}"
35rm -rf "$out"
36mkdir -p "$out/bin" "$out/lib" "$out/src"
37
38# The runtime.
39install -m 0755 "$FRQ_DESKTOP_TOOLCHAIN/jolt/jolt" "$out/bin/jolt"
40
41# Every object in one directory, because JOLT_NATIVE_LIB is one directory:
42# jolt resolves each `:jolt/native` name against it. They arrive from two
43# places — the portable tarball and the moq-ffi release — which is exactly
44# what `nativeAll` was a symlinkJoin for.
45cp -a "$FRQ_DESKTOP_TOOLCHAIN/jolt-native/lib/." "$out/lib/"
46install -m 0755 "$FRQ_DESKTOP_TOOLCHAIN/moq-ffi/lib/libmoq_ffi.so" "$out/lib/"
47
48# The calling-convention adapter, compiled here because it is one translation
49# unit and because openh264's C API cannot be called from Jolt directly:
50# `ISVCEncoder` is a `const ISVCEncoderVtbl*`, so `c/frq_h264.c` walks the
51# vtable and exports five plain symbols. See src/frq/codec/h264.clj.
52#
53# This is the one place the build machine's own libraries get in, and the
54# reason it is acceptable is the reason the portable tarball works at all:
55# openh264, opus and alsa-lib are plain C libraries against glibc, and the
56# copy below takes the .so the link actually resolved rather than trusting the
57# runner to have the same one.
58echo "desktop: compiling the h264 adapter" >&2
59cc -O2 -fPIC -shared "$root/c/frq_h264.c" -o "$out/lib/libfrqh264.so" \
60 $(pkg-config --cflags --libs openh264)
61
62# openh264 itself, opus, and ALSA's client library, beside it. `ldd` on what
63# was just linked names the file the loader chose, which is the one to take —
64# a guess at a soname is a guess at the distro.
65for soname in libopenh264 libopus libasound; do
66 lib=$(ldd "$out/lib/libfrqh264.so" 2>/dev/null | awk -v n="$soname" '$1 ~ "^"n"\\." {print $3; exit}')
67 # opus and alsa are opened by jolt rather than NEEDED by the adapter, so
68 # they are not in that ldd and have to be looked up.
69 [ -n "${lib:-}" ] || lib=$(ldconfig -p | awk -v n="$soname" '$1 ~ "^"n"\\.so" {print $NF; exit}')
70 if [ -z "${lib:-}" ]; then
71 echo "desktop: no $soname on this machine — the AV plane will not load" >&2
72 continue
73 fi
74 install -m 0755 -T "$lib" "$out/lib/$(basename "$lib")"
75done
76
77# $ORIGIN for everything staged here, for the reason jolt-native's
78# libsPortable sets it: the consumer decides where this unpacks and only the
79# loader knows where that turned out to be. The objects out of the portable
80# tarball already have it; the ones added above do not.
81if command -v patchelf >/dev/null 2>&1; then
82 for f in "$out/lib"/*.so*; do patchelf --set-rpath '$ORIGIN' "$f" 2>/dev/null || true; done
83else
84 echo "desktop: no patchelf; the launcher's LD_LIBRARY_PATH covers this" >&2
85fi
86
87# The project as jolt sees it: source, deps.edn, nothing else — the same three
88# things `frqSource` copied in the flake.
89cp -a "$root/common" "$root/src" "$root/deps.edn" "$out/src/"
90
91# The two Jolt libraries the launcher names in -Sdeps. Copied in rather than
92# referenced out of the toolchain, so the bundle is self-contained: a tarball
93# that needs a directory from the machine that made it is not a bundle.
94cp -a "$FRQ_GLIMMER" "$out/glimmer"
95cp -a "$FRQ_GLIMMER_COSMIC" "$out/glimmer-cosmic"
96rm -rf "$out/glimmer/.git" "$out/glimmer-cosmic/.git"
97
98# The launcher. `frqScript` from the flake, with the store paths replaced by
99# $ORIGIN-relative ones and the nixGL branch deleted — off NixOS that existed
100# to put the host's GL driver ahead of the closure's Mesa, and there is no
101# Mesa in here to get ahead of. The driver is simply the host's.
102cat > "$out/bin/frq" <<'LAUNCH'
103#!/usr/bin/env bash
104set -euo pipefail
105here="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/.." && pwd)"
106
107export JOLT_NATIVE_LIB="$here/lib"
108export LD_LIBRARY_PATH="$here/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
109
110# ALSA finds its plugins by directory rather than by soname, and `default`
111# resolves to nothing without the PipeWire one. Unlike the flake, which named
112# a store path, this defers to the host: every machine frq targets runs
113# PipeWire and ships that plugin in the usual place.
114for d in /usr/lib/x86_64-linux-gnu/alsa-lib /usr/lib/alsa-lib /usr/lib64/alsa-lib; do
115 [ -d "$d" ] && export ALSA_PLUGIN_DIR="$d" && break
116done
117
118# jolt resolves deps.edn from the working directory.
119cd "$here/src"
120
121exec "$here/bin/jolt" \
122 -Sdeps "{:deps {jolt-lang/glimmer {:local/root \"$here/glimmer\"}
123 nandi/glimmer-cosmic {:local/root \"$here/glimmer-cosmic\"}}}" \
124 -m frq.cosmic "$@"
125LAUNCH
126chmod +x "$out/bin/frq"
127
128echo "desktop: built $out" >&2
129du -sh "$out" >&2
130
131case "$action" in
132 tar)
133 tarball="${FRQ_DESKTOP_TAR:-$root/build/frq-desktop-x86_64-linux.tar.gz}"
134 mkdir -p "$(dirname "$tarball")"
135 # Rooted at a directory of its own, because a tarball that unpacks
136 # `bin/` and `lib/` into the current directory is a tarball someone
137 # will one day unpack into their home.
138 tar czf "$tarball" -C "$(dirname "$out")" "$(basename "$out")"
139 echo "desktop: $tarball" >&2
140 ls -la "$tarball" >&2
141 ;;
142 run)
143 exec "$out/bin/frq"
144 ;;
145esac