nandi/frqpublic Fork 0
91302db00783c8e3a1e2ac5927b0f4de1fb204da
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.

flake.nix · 610 lines · 30.1 KBNix Blame HistoryRaw
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago1{
2 # frq is Jolt source, so "building" it is three things, not one:
3 #
4 # jolt the runtime that reads it (github:jolt-lang/jolt)
5 # jolt-native libvidya and libjoltmoq, in Rust (gitlab:nandithebull/jolt-native)
6 # frq this tree, with its deps resolved to store paths
7 #
8 # Jolt resolves deps.edn by running git at startup, which a build sandbox has
9 # no network for — so every dep is fetched by Nix instead and handed back as
10 # a :local/root through -Sdeps.
11 #
12 # nix build .#frq && ./result/bin/frq
13 #
14 # On a machine that is not NixOS the GL driver is the host's and the loader
15 # will not find it, so the window never opens ("GL display: argument does not
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago16 # name a valid config"). The launcher handles that itself: off NixOS it hands
17 # the process to nixGL, which puts the host's driver ahead of the store's.
18 # Nothing extra to type, and a distrobox/container Arch is the same case as
19 # a bare one.
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago20 description = "frq a freeq client in jolt";
21
22 inputs = {
23 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago24 # `git+https` with `?submodules=1` rather than the github scheme: Jolt's
25 # own flake declares `self.submodules`, which this Nix rejects when the
26 # flake is fetched as `github:`. Its outputs are not what we take — the
27 # runtime is built here, by joltFrom — but it is a flake all the same, so
28 # its own inputs are locked with ours rather than left to float, and
29 # `vendor/` comes along as the submodule the build needs.
30 #
31 # The fork rather than jolt-lang/jolt: it is what jolt-android-src already
32 # pins for the boot image, and a desktop runtime built from a different
33 # tree than the APK's is the same drift the jolt-native comment warns
34 # about. Unpinned here — the desktop follows the fork's main, while the
35 # APK stays on the rev below.
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago36 jolt-src = {
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago37 url = "git+https://gitlab.com/nandithebull/jolt?submodules=1";
38 inputs.nixpkgs.follows = "nixpkgs";
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago39 };
40
Take the Android objects from jolt-native's CI, always the latest 472e179 nandi 11d ago41 # The source half of jolt-native: the Jolt code under glimmer-backends/ that
42 # binds the native objects, and the flake that builds the desktop ones. The
43 # Android objects no longer come from here — jolt-native-android below
44 # fetches those prebuilt — so this input is what `just run` builds against
45 # and what an APK's Clojure side is read from, both at this rev.
Take the jolt-native ahead of the release, since a run can build it 36f6c77 nandi 17d ago46 #
47 # Pinned all the same, and pinned to a rev: this input carries both halves of
Pin the native half to the release the rest of the tree names cb7f9f1 nandi 17d ago48 # glimmer-vidya — libvidya, and the Jolt side that binds it — so an
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago49 # Pinned to `jvui-for-frq`: it
50 # carries jvui and glimmer-jvui — the toolkit the window is painted with
51 # now — and, merged in from no-moq-deps, the dependency split and the
52 # JOLT_WITHOUT_MOQ guard on the Android glue. It is
Stop building the media plane frq no longer loads 231b9d3 nandi 9d ago53 # branched from the rev this used to name rather than taken off main,
54 # because main has moved on to the Zig/dvui backend and a UI change is
55 # not what this pin is for.
56 #
Pin the native half to the release the rest of the tree names cb7f9f1 nandi 17d ago57 # unpinned `main` is a build whose native half is free to sit at a
58 # different commit from the tree that talks to it. It did, and what the
59 # drift cost was silence: the Jolt half sent a reaction pill's hover card
60 # to a libvidya with no handler for one, and the pill said nothing.
Merge origin/main, and let one jolt-native answer for both backends 1e8b590 nandi 16d ago61 # It also carries the terminal backend — crates/jolt-tui, the same tree ABI
62 # over a grid of cells, and jolt/glimmer-tui beside glimmer-vidya. That was
63 # a second input at a second rev while it lived on a branch, which is the
64 # drift this comment warns about wearing a different hat: one input, and
65 # the window and the terminal are the same library either way.
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago66 jolt-native = {
Ship the faces jvui draws with 91302db nandi 9d ago67 url = "git+file:///tmp/claude-1000/-home-nandi-code-frq--claude-worktrees-moq-jolt-lang-port-dd3165/477edbd0-1739-4107-b542-c23b5bbd9430/scratchpad/jv?ref=jvui-for-frq";
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago68 inputs.nixpkgs.follows = "nixpkgs";
Paint the same screens into a terminal ab83b42 nandi 17d ago69 };
70
Take the Android objects from jolt-native's CI, always the latest 472e179 nandi 11d ago71 # The Android objects, prebuilt by jolt-native's CI rather than compiled
72 # here: an APK needs libvidya and libjoltmoq for arm64, and building them
73 # locally means an NDK, a Rust cross toolchain and the whole crane graph
74 # for two files that upstream already built and published.
75 #
76 # "latest" is the version its CI overwrites on every default-branch build,
77 # so this input finds a new one on `nix flake update` -- but flake.lock
78 # still records exactly which bytes an APK was built from, which is the
79 # pin that matters. `just bump` decides when to move; this only decides
80 # where to look. The archive is rooted at include/ and lib/arm64-v8a/, so
81 # nothing here has to unpack it.
82 jolt-native-android = {
83 url = "https://gitlab.com/api/v4/projects/nandithebull%2Fjolt-native/packages/generic/jolt-native/latest/android-arm64-v8a.tar.gz";
84 flake = false;
85 };
86
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago87 # Chez itself, because the APK needs a cross target nixpkgs does not
88 # build: frq's Scheme is compiled to an arm64 boot image, and that wants
89 # Chez's own `tarm64le` workarea — boot files, xpatch and libkernel.a.
90 # The version is the one the hand-built tree under ~/.cache used, and the
91 # submodules are not optional (zuo builds it, lz4 and zlib link into it).
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago92 # The same fork jolt-src takes, built here rather than fetched as a
93 # release binary: upstream reads the socket address out of `struct
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago94 # addrinfo` at glibc's offset, which on Bionic is `ai_canonname`, so an APK
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago95 # built with upstream cannot open a TLS connection at all. Pinned to a rev
96 # where jolt-src is not: the APK is a release artefact, so its runtime
97 # moves when `just bump` says so rather than when the fork does.
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago98 jolt-android-src = {
99 url = "git+https://gitlab.com/nandithebull/jolt?rev=2b80d68d1f7a31ba92b208b3957e5fb555617ada&submodules=1";
Take jolt and jolt-native as flakes, off my own fork aaa560d nandi 13d ago100 inputs.nixpkgs.follows = "nixpkgs";
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago101 };
102
103 chez-src = {
104 url = "git+https://github.com/cisco/ChezScheme?ref=refs/tags/v10.4.1&submodules=1";
105 flake = false;
106 };
107
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago108 # The sha deps.edn pins, on the fork with the reconciler fixes.
109 glimmer = {
110 url = "git+https://gitlab.com/nandithebull/glimmer?rev=399df371c790d690fb6e4560c3d4d7f838502857";
111 flake = false;
112 };
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago113
114 # Only ever used off NixOS, to put the host GL driver on the loader path.
115 nixgl = {
116 url = "github:nix-community/nixGL";
117 inputs.nixpkgs.follows = "nixpkgs";
118 };
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 18d ago119
120 # Wraps a closure into a single self-extracting file. Only the `appimage`
121 # output evaluates it.
122 nix-appimage = {
123 url = "github:ralismark/nix-appimage";
124 inputs.nixpkgs.follows = "nixpkgs";
125 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago126 };
127
Fetch libmoq_ffi again, and keep the codecs out of Rust f518938 nandi 9d ago128 outputs = { self, nixpkgs, jolt-src, jolt-native, jolt-native-android, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago129 let
130 systems = [ "x86_64-linux" "aarch64-linux" ];
131 forEachSystem = f:
132 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
Run this tree on a native half the builders made a32699e nandi 17d ago133
134 # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
135 # wrappers are the ones that need --impure (they read the host kernel
136 # module's version), which is why this only ever reaches for Intel.
Stop carrying the 32-bit GL stack and half of git 040f2c1 nandi 16d ago137 #
138 # Built from nixGL's default.nix rather than taken from its flake
139 # outputs, for the one argument the flake hardcodes on: `enable32bits`,
140 # which on x86_64 puts a second, i686 copy of mesa, its LLVM, and
141 # intel-media-driver into the wrapper. frq is 64-bit on both halves —
142 # the Rust cdylibs and the Chez runtime — so nothing here ever opens the
143 # 32-bit driver, and carrying it is most of the dev shell's closure.
144 nixGLFor = pkgs: (import nixgl {
145 inherit pkgs;
146 enable32bits = false;
147 }).nixGLIntel;
Run this tree on a native half the builders made a32699e nandi 17d ago148
149 # egui reaches for these with dlopen rather than linking them, so being
150 # in the cdylib's buildInputs is not enough — whatever starts frq has to
Follow the xorg renames, and stop wrapping nix in distrobox a400a00 nandi 16d ago151 # put them on the loader path itself. Without libx11 here, vidya reports
Run this tree on a native half the builders made a32699e nandi 17d ago152 # "X11 unavailable", falls back to Wayland, and winit refuses to build a
153 # second event loop after the failed first one.
154 #
155 # Out here rather than beside the package that first needed them: the
156 # dev shell starts frq too, on this tree's source rather than the store's
157 # copy of it, and a second copy of this list is a second chance for the
158 # two ways of running to disagree about what the window needs.
159 runtimeLibsFor = pkgs: with pkgs; [
160 libGL
161 libxkbcommon
162 wayland
Follow the xorg renames, and stop wrapping nix in distrobox a400a00 nandi 16d ago163 libx11
164 libxcursor
165 libxi
166 libxrandr
Run this tree on a native half the builders made a32699e nandi 17d ago167 vulkan-loader
168 ];
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago169 in
170 {
171 packages = forEachSystem (pkgs:
172 let
173 inherit (pkgs) lib;
174
Run this tree on a native half the builders made a32699e nandi 17d ago175 nixGL = nixGLFor pkgs;
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago176
Take the native objects from their own flake rather than rebuilding them 0ee8bba nandi 13d ago177 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui),
178 # libjolttui (the same tree over a grid of cells) and libjoltmoq (the
179 # AV media plane) — one workspace, three cdylibs, taken from
180 # jolt-native's own flake rather than rebuilt here.
181 #
182 # This used to be a rustPlatform.buildRustPackage over the same
183 # source, which meant restating upstream's build: the seven git deps
184 # hashed by hand in `cargoLock.outputHashes` and re-hashed whenever
185 # its Cargo.lock moved, the linuxHeaders path v4l2r's bindgen wants,
186 # and a postPatch dropping the .cargo/config.toml that pointed the
187 # build at DotSlash. Upstream's flake says all of that itself now,
188 # and says it once. It also builds cpal with the `pipewire` feature,
189 # which the restatement did not — so device names in a call are
190 # PipeWire's rather than raw ALSA PCMs.
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago191 # libjolttui only. Not libjoltmoq, whose job `frq.av.plane` does
192 # now, and no longer libvidya either: the window is jvui on SDL,
193 # so the only object left out of that Cargo workspace is the
194 # terminal backend, and only `just tui` loads it.
Switch frq.av onto the jolt media plane, and stop shipping libjoltmoq b33f288 nandi 9d ago195 #
196 # This makes the closure smaller and the APK smaller. It does NOT
197 # make the build shorter, and it is worth being exact about why:
198 # jolt-native compiles its external crates ONCE, in a
199 # `buildDepsOnly` derivation shared by all three objects, so
200 # asking for two of them still builds every dependency the third
201 # has — the 440 crates that are jolt-moq's alone. Getting those
202 # out of the build is a change in jolt-native, not here: either
203 # jolt-moq leaves that workspace, or its deps artifact stops
204 # being workspace-wide.
205 native =
206 let np = jolt-native.packages.${pkgs.stdenv.hostPlatform.system};
207 in pkgs.symlinkJoin {
208 name = "jolt-native-ui";
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago209 paths = [ np.libjolttui ];
Switch frq.av onto the jolt media plane, and stop shipping libjoltmoq b33f288 nandi 9d ago210 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago211
Fetch libmoq_ffi again, and keep the codecs out of Rust f518938 nandi 9d ago212 # libmoq_ffi — MoQ over QUIC behind UniFFI's C ABI, FETCHED rather
213 # than built. This is the object `frq.moq.raw` is generated from.
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago214 #
Fetch libmoq_ffi again, and keep the codecs out of Rust f518938 nandi 9d ago215 # Fetched because building it is the thing this whole exercise is
216 # about: moq-ffi pulls moq-native, iroh, quinn, rustls and aws-lc-sys
217 # behind it, which is 440 crates that nothing else in this tree
218 # needs. Upstream already publishes the object for both Linux
219 # architectures, so we take those bytes.
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago220 #
Fetch libmoq_ffi again, and keep the codecs out of Rust f518938 nandi 9d ago221 # Pinned to a release and to a hash, and the hashes below are
222 # upstream's own published .sha256 files rather than ones observed
223 # here — a `nix-prefetch` of whatever the URL serves today would
224 # record that it downloaded something, not that it downloaded the
225 # right thing.
226 #
227 # WHAT THIS BUILD IS NOT: moq-ffi's `audio` and `video` features are
228 # on by default upstream and are OFF in these artifacts, so there is
229 # no publish_audio/publish_video and no moqaudio*/moqvideo* here —
230 # 206 functions where the Apple artifact has 230. That is why the
231 # bindings are generated from the object (`just gen-moq`) and not
232 # from the C header the release ships, which describes the Apple one.
233 moqFfi =
234 let
235 version = "0.3.17";
236 target = {
237 "x86_64-linux" = "x86_64-unknown-linux-gnu";
238 "aarch64-linux" = "aarch64-unknown-linux-gnu";
239 }.${pkgs.stdenv.hostPlatform.system};
240 hash = {
241 "x86_64-linux" = "sha256-dzQXpV4JgdtD+g33WX51FFAQdfCUXkNsx1xPbobPfUI=";
242 "aarch64-linux" = "sha256-PdzRwbJFqOZWRgI0HHX2XUH+Ljh4V3jvQ9asfvCuIPA=";
243 }.${pkgs.stdenv.hostPlatform.system};
244 in
245 pkgs.stdenv.mkDerivation {
246 pname = "libmoq-ffi";
247 inherit version;
248 src = pkgs.fetchurl {
249 url = "https://github.com/kixelated/moq/releases/download/moq-ffi-v${version}/moq-ffi-${version}-${target}-libmoq_ffi.so";
250 inherit hash;
251 };
252 dontUnpack = true;
253 # It carries no RUNPATH and needs libgcc_s, libm and libc — the
254 # host's on an ordinary distro, and nothing at all on NixOS
255 # unless they are bound here.
256 nativeBuildInputs = [ pkgs.autoPatchelfHook ];
257 buildInputs = [ pkgs.stdenv.cc.cc.lib ];
258 installPhase = ''
259 mkdir -p $out/lib
260 cp $src $out/lib/libmoq_ffi.so
261 chmod +w $out/lib/libmoq_ffi.so
262 '';
263 };
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago264
265 # One directory for the loader to look in. jolt resolves every
266 # :jolt/native name against JOLT_NATIVE_LIB, and the objects now come
267 # from two places — jolt-native's flake, and the moq-ffi release — so
268 # they are joined rather than the path being made a list, which the
269 # loader does not take.
Bind the C libraries a call actually needs 87e5be9 nandi 9d ago270 # The C codecs, from nixpkgs. libmoq_ffi carries the transport and
271 # nothing else — moq-ffi's `audio` and `video` features would have
272 # brought Opus and H.264 with them, at the price of compiling a
273 # 1062-crate workspace — so the codecs are linked here instead,
274 # where they have always lived.
275 #
276 # Named in :jolt/native, so the loader resolves them the same way it
277 # resolves libvidya: by name, out of one directory.
278 # A flat C face for openh264, because openh264 has none. Its
279 # `ISVCEncoder` is `const ISVCEncoderVtbl*` — every method is a
280 # function pointer in a vtable — and jolt.ffi cannot call one: Chez
281 # fixes a foreign procedure's types when it compiles it, and the
282 # target must be a literal C symbol name. So the vtable is walked in
283 # c/frq_h264.c and jolt binds the five plain symbols it exports.
284 #
285 # One translation unit against a library nixpkgs already has. It is
286 # a calling convention adapter, not a second media plane, and the
287 # distinction from the moq-ffi build it replaces is the whole point:
288 # this compiles one .c file, not a 1062-crate workspace.
289 frqH264 = pkgs.stdenv.mkDerivation {
290 pname = "frq-h264";
291 version = "0.1";
292 src = ./c;
293 nativeBuildInputs = [ pkgs.pkg-config ];
294 buildInputs = [ pkgs.openh264 ];
295 buildPhase = ''
296 $CC -O2 -fPIC -shared frq_h264.c -o libfrqh264.so \
297 $(pkg-config --cflags --libs openh264)
298 '';
299 installPhase = ''
300 mkdir -p $out/lib && cp libfrqh264.so $out/lib/
301 '';
302 };
303
304 # openh264 is here for frqH264's DT_NEEDED; alsa-lib for capture
305 # and playback. V4L2 needs nothing: it is ioctls against libc and
306 # the kernel, so there is no library to name.
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago307 # SDL is what the UI is now: jvui declares SDL3, SDL3_ttf and
308 # SDL3_image in its own :jolt/native and dlopens them by soname,
309 # so they have to be somewhere the loader looks. sdl3-image keeps
310 # its library in a separate `lib` output — the default one holds
311 # only share/, which is an afternoon nobody needs to repeat.
312 sdl = [ pkgs.sdl3 pkgs.sdl3-ttf (pkgs.sdl3-image.lib or pkgs.sdl3-image) ];
313
314 codecs = [ pkgs.libopus pkgs.openh264 frqH264 pkgs.alsa-lib ] ++ sdl;
Bind the C libraries a call actually needs 87e5be9 nandi 9d ago315
Let the plane take real devices, not only test thunks 596dc29 nandi 9d ago316 # ALSA's PipeWire plugin, which is how `default` resolves to
317 # anything on a machine running PipeWire — and every machine frq
318 # targets does. Without it alsa-lib fails to dlopen
319 # libasound_module_pcm_pipewire.so and the only devices that open
320 # are raw hardware ones, which PipeWire is already holding.
321 #
322 # An environment variable rather than a library in the join:
323 # alsa-lib looks plugins up by directory, not by soname.
324 alsaPluginDir = "${pkgs.pipewire}/lib/alsa-lib";
325
Ship the faces jvui draws with 91302db nandi 9d ago326 # The faces jvui draws with, from here rather than from whatever
327 # the host happens to have installed. jvui hunts a list of the
328 # usual system paths and, failing that, draws the missing-glyph
329 # box — which is what "the glyphs are broke" has been every time
330 # it has come up. An Arch container has NotoColorEmoji and no
331 # monochrome Noto Emoji, and NotoColorEmoji is a bitmap face with
332 # one 128-pixel strike that jvui rejects on purpose, so the chips
333 # in a message row had nothing left to be drawn from.
334 #
335 # NotoEmoji is the outline companion to NotoColorEmoji: scalable,
336 # monochrome, and full coverage of the emoji the chrome uses.
337 # Symbols2 behind it for the arrows and technical marks that are
338 # not emoji at all.
339 uiFont = "${pkgs.noto-fonts}/share/fonts/noto/NotoSans.ttf";
340 fallbackFonts = lib.concatStringsSep ":" [
341 "${pkgs.noto-fonts-monochrome-emoji}/share/fonts/noto/NotoEmoji.ttf"
342 "${pkgs.noto-fonts}/share/fonts/noto/NotoSansSymbols2-Regular.otf"
343 "${pkgs.noto-fonts}/share/fonts/noto/NotoSansSymbols.ttf"
344 ];
345
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago346 nativeAll = pkgs.symlinkJoin {
347 name = "frq-native";
Bind the C libraries a call actually needs 87e5be9 nandi 9d ago348 paths = [ native moqFfi ] ++ codecs;
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago349 };
350
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago351 # Jolt itself: Clojure on Chez, built the way its own flake builds it.
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago352 # A function, because there are two of them — upstream for the
353 # desktop, and the Bionic-addrinfo fork for the boot image the APK
354 # carries. Nothing else about the build differs.
355 joltFrom = src: pkgs.stdenv.mkDerivation {
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago356 pname = "jolt";
357 version = "dev";
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago358 inherit src;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago359
360 strictDeps = true;
361 nativeBuildInputs = with pkgs; [ chez makeWrapper pkg-config xxd ];
362 buildInputs = with pkgs; [ lz4 zlib ncurses openssl libuuid ];
363
364 JOLT_VERSION = "dev";
365 dontConfigure = true;
366
367 buildPhase = ''
368 runHook preBuild
369 scheme --script host/chez/build-jolt.ss release target/release/jolt
370 runHook postBuild
371 '';
372
373 installPhase = ''
374 runHook preInstall
375 mkdir -p "$out/bin"
376 install -m755 target/release/jolt "$out/bin/jolt"
377 runHook postInstall
378 '';
379
380 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
Stop carrying the 32-bit GL stack and half of git 040f2c1 nandi 16d ago381 # OpenSSL through the JOLT_OPENSSL_LIBDIR seam. gitMinimal rather
382 # than git: all jolt.deps asks for is clone/fetch/rev-parse, and
383 # the full package carries Perl and Python for the subcommands
384 # written in them — a quarter of a gigabyte for git-send-email.
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago385 #
386 # TZDIR so a zone *name* resolves wherever this runs: frq.clock
387 # hands one to tzset, and glibc then looks for the tzfile under
388 # /usr/share/zoneinfo unless told otherwise — which a NixOS host
389 # does not have. The store's own tzdata is there on both kinds of
390 # machine. --set-default, so a TZDIR the user set still wins.
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago391 postFixup = ''
392 wrapProgram "$out/bin/jolt" \
Stop carrying the 32-bit GL stack and half of git 040f2c1 nandi 16d ago393 --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.gitMinimal pkgs.unzip ]}" \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago394 --set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago395 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago396 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
397 '';
398 };
399
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago400 joltRuntime = joltFrom jolt-src;
401 joltAndroid = joltFrom jolt-android-src;
402
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago403 # glimmer-vidya lives inside the jolt-native checkout, and its own
404 # deps.edn asks for glimmer by git — the top-level override below
405 # answers for both.
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago406 # glimmer-jvui and the toolkit it is a backend for. TWO paths and
407 # not one: glimmer-jvui's own deps.edn names jvui by :local/root,
408 # a relative path that means nothing once nix has copied the
409 # subtree, so the -Sdeps below has to name both.
410 glimmerJvui = "${jolt-native}/glimmer-backends/glimmer-jvui";
411 jvui = "${jolt-native}/jvui";
Take the Android objects from jolt-native's CI, always the latest 472e179 nandi 11d ago412 glimmerTui = "${jolt-native}/glimmer-backends/glimmer-tui";
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago413
Run this tree on a native half the builders made a32699e nandi 17d ago414 runtimeLibs = runtimeLibsFor pkgs;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago415
416 # The project as jolt sees it: source, deps.edn, nothing else.
417 frqSource = pkgs.runCommand "frq-source" { } ''
418 mkdir -p "$out"
419 cp -r ${self}/src ${self}/deps.edn "$out/"
420 '';
421
422 # Jolt resolves deps.edn from the working directory, so the launcher
423 # runs from the store copy. Its .jolt/cpcache write lands on a
424 # read-only directory and jolt treats that as a quiet cache miss, so
425 # the only cost is re-resolving the (already local) graph per start.
426 frqScript = pkgs.writeShellScript "frq" ''
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago427 export LD_LIBRARY_PATH="${nativeAll}/lib:${lib.makeLibraryPath runtimeLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
Let the plane take real devices, not only test thunks 596dc29 nandi 9d ago428 export ALSA_PLUGIN_DIR="${alsaPluginDir}"
Ship the faces jvui draws with 91302db nandi 9d ago429 export JVUI_FONT="${uiFont}"
430 export JVUI_FALLBACK_FONTS="${fallbackFonts}"
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago431 cd ${frqSource}
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago432
433 # On NixOS the store's Mesa is the system's and the window opens.
434 # Anywhere else the real driver is the host's, so defer to nixGL
435 # it prepends the host driver, which has to win over ours.
436 runner=""
437 [ -e /run/current-system ] || runner="${nixGL}/bin/nixGLIntel"
438
439 exec ''${runner} ${joltRuntime}/bin/jolt \
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago440 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-jvui {:local/root "${glimmerJvui}"} jvui/jvui {:local/root "${jvui}"}}}' \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago441 -M:frq "$@"
442 '';
443
Paint the same screens into a terminal ab83b42 nandi 17d ago444 # The same source, the other backend. No GL, no nixGL and no X11 —
445 # a terminal is the one surface that needs nothing from the host but
446 # a terminal, which is the reason this output exists.
447 tuiScript = pkgs.writeShellScript "frq-tui" ''
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago448 export LD_LIBRARY_PATH="${nativeAll}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
Let the plane take real devices, not only test thunks 596dc29 nandi 9d ago449 export ALSA_PLUGIN_DIR="${alsaPluginDir}"
Paint the same screens into a terminal ab83b42 nandi 17d ago450 cd ${frqSource}
451
452 exec ${joltRuntime}/bin/jolt \
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago453 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-jvui {:local/root "${glimmerJvui}"} jvui/jvui {:local/root "${jvui}"} nandi/glimmer-tui {:local/root "${glimmerTui}"}}}' \
Paint the same screens into a terminal ab83b42 nandi 17d ago454 -m frq.tui "$@"
455 '';
456
457 tui = pkgs.runCommand "frq-tui-0.1.0"
458 {
459 meta = {
460 description = "frq's screens in a terminal";
461 mainProgram = "frq-tui";
462 platforms = systems;
463 };
464 }
465 ''
466 mkdir -p "$out/bin"
467 ln -s ${tuiScript} "$out/bin/frq-tui"
468 '';
469
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago470 frq = pkgs.runCommand "frq-0.1.0"
471 {
472 meta = {
473 description = "A freeq client in jolt";
474 mainProgram = "frq";
475 platforms = systems;
476 };
477 }
478 ''
479 mkdir -p "$out/bin"
480 ln -s ${frqScript} "$out/bin/frq"
481 '';
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago482 # --- Android ------------------------------------------------------
483 # The SDK and the NDK are Google's, which means unfree and a licence
484 # to accept — so this is its own import of nixpkgs rather than the
485 # `legacyPackages` everything above uses. Confined to the Android
486 # outputs: `nix build` of frq itself never evaluates it.
487 #
Build the APK as derivations only, and retire the buck2 graph 3bc3aaa nandi 16d ago488 # The NDK here is r29, which is the one the pinned libvidya was
489 # built with.
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago490 androidPkgs = import nixpkgs {
491 inherit (pkgs.stdenv.hostPlatform) system;
492 config = {
493 allowUnfree = true;
494 android_sdk.accept_license = true;
495 };
496 };
497
498 androidComposition = androidPkgs.androidenv.composeAndroidPackages {
499 buildToolsVersions = [ "36.0.0" ];
500 platformVersions = [ "36" ];
501 includeNDK = true;
502 };
503
504 android = import ./nix/android.nix {
Take the Android objects from jolt-native's CI, always the latest 472e179 nandi 11d ago505 inherit pkgs self chez-src jolt-native jolt-native-android glimmer joltAndroid;
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago506 inherit (pkgs) lib;
507 androidSdk = androidComposition.androidsdk;
508 ndk = androidComposition.ndk-bundle;
509 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago510 in
511 {
Bind the C libraries a call actually needs 87e5be9 nandi 9d ago512 inherit native moqFfi frqH264 nativeAll frq;
Let the plane take real devices, not only test thunks 596dc29 nandi 9d ago513 inherit (pkgs) pipewire;
Merge origin/main, and let one jolt-native answer for both backends 1e8b590 nandi 16d ago514 inherit tui;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago515 jolt = joltRuntime;
516 default = frq;
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 18d ago517
518 # frq and everything it loads, squashed into one runnable file for
519 # hosts without Nix. The whole closure rides along — Mesa included,
520 # which is not waste: off NixOS the launcher goes through nixGL, and
521 # nixGL needs a store Mesa to put the host's driver in front of.
522 appimage =
523 nix-appimage.bundlers.${pkgs.stdenv.hostPlatform.system}.default frq;
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago524 }
525 # An APK is built by a linux-x86_64 NDK and a linux-x86_64 jolt, and
526 # Google ships no other; on aarch64 the Android outputs are simply
527 # absent rather than present and broken.
528 // lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "x86_64-linux") {
529 inherit (android) apk chezAndroid joltBoot libjoltapp;
530 apk-unsigned = android.apk-unsigned;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago531 });
532
Run this tree on a native half the builders made a32699e nandi 17d ago533 # Where `just run` runs, and — because entering it realises what it
534 # names — what builds the half of frq that is not this working tree.
535 #
536 # The two halves, and the split is the whole point of the shell. The frq
537 # source is the files on disk, uncommitted edits and all. Everything
538 # under it — jolt, glimmer, glimmer-vidya, both native objects — is the
539 # flake's, at the revs flake.lock names, so a run says what it ran
540 # against and both halves of glimmer-vidya move together. That is the
541 # drift the `jolt-native` input's comment is about, and a pin frq can
542 # answer for is worth more here than the convenience of a checkout.
543 #
Take the native objects from their own flake rather than rebuilding them 0ee8bba nandi 13d ago544 # `native` is jolt-native's own flake output. It was a buck2 graph when
545 # this comment was first written and a cargo build restated here when it
546 # was second: buck2 fetches its rustc, zig and every third-party crate as
547 # it goes and writes buck-out into the tree it builds, so a sandbox with
548 # no network and a read-only store was the one place it could not run.
549 # Upstream builds with nix now, so the thing its CI runs and the thing
550 # this shell hands a builder are the same derivation.
Run this tree on a native half the builders made a32699e nandi 17d ago551 #
552 # Nothing here says "nixbuild", though: it is a plain derivation, and
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago553 # where it gets built is the machine's business. The `run` recipe asks for
Run this tree on a native half the builders made a32699e nandi 17d ago554 # the shell with --max-jobs 0, which is what sends it to the `builders`
555 # entry rather than compiling egui on a laptop.
556 devShells = forEachSystem (pkgs:
557 let
558 inherit (pkgs) lib;
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago559 inherit (self.packages.${pkgs.stdenv.hostPlatform.system}) jolt native nativeAll;
Run this tree on a native half the builders made a32699e nandi 17d ago560 in
561 {
562 default = pkgs.mkShellNoCC {
563 name = "frq";
564
565 # jolt, because the runtime frq is run by should be the flake's
566 # too. nixGL for the same reason the launcher reaches for it — see
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago567 # frqScript. just so the recipe runner comes from here too rather
568 # than the host — `nix develop` and then `just run` is the whole of
569 # what a machine with nix needs.
570 packages = [ jolt pkgs.just (nixGLFor pkgs) ];
571
572 # Read by the recipes rather than baked into a wrapper: the frq
Run this tree on a native half the builders made a32699e nandi 17d ago573 # source `just run` runs is the working tree, so the launcher has
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago574 # to live in that tree and the shell has to hand it its answers.
575 # Naming these is also what makes the shell build them.
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago576 JOLT_NATIVE_LIB = "${nativeAll}/lib";
Let the plane take real devices, not only test thunks 596dc29 nandi 9d ago577 # Spelled out rather than shared with the packages block, which
578 # is a different `let`. See `alsaPluginDir` there for why.
579 ALSA_PLUGIN_DIR = "${pkgs.pipewire}/lib/alsa-lib";
Run this tree on a native half the builders made a32699e nandi 17d ago580 GLIMMER_SRC = glimmer;
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago581 GLIMMER_JVUI_SRC = "${jolt-native}/glimmer-backends/glimmer-jvui";
582 JVUI_SRC = "${jolt-native}/jvui";
Take the Android objects from jolt-native's CI, always the latest 472e179 nandi 11d ago583 GLIMMER_TUI_SRC = "${jolt-native}/glimmer-backends/glimmer-tui";
Ship the faces jvui draws with 91302db nandi 9d ago584 # See `uiFont` in the packages block for why these are named
585 # here rather than left to whatever the host has installed.
586 # Spelled out again for the same reason ALSA_PLUGIN_DIR is: a
587 # different `let`.
588 JVUI_FONT = "${pkgs.noto-fonts}/share/fonts/noto/NotoSans.ttf";
589 JVUI_FALLBACK_FONTS = lib.concatStringsSep ":" [
590 "${pkgs.noto-fonts-monochrome-emoji}/share/fonts/noto/NotoEmoji.ttf"
591 "${pkgs.noto-fonts}/share/fonts/noto/NotoSansSymbols2-Regular.otf"
592 "${pkgs.noto-fonts}/share/fonts/noto/NotoSansSymbols.ttf"
593 ];
Run this tree on a native half the builders made a32699e nandi 17d ago594 FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs);
595 NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel";
596 };
597 });
598
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago599 apps = forEachSystem (pkgs: {
600 default = {
601 type = "app";
602 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.frq}/bin/frq";
603 };
Paint the same screens into a terminal ab83b42 nandi 17d ago604 tui = {
605 type = "app";
606 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.tui}/bin/frq-tui";
607 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago608 });
609 };
610}