nandi/frqpublic Fork 0
8a86eb395d5f8ac215916c6f849042aa1b481c03
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 · 397 lines · 16.6 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";
24 # Jolt's own flake declares `self.submodules`, which this Nix rejects when
25 # the flake is fetched through the github scheme — so take the source and
26 # build it here. `vendor/` is a submodule and the build needs it.
27 jolt-src = {
28 url = "git+https://github.com/jolt-lang/jolt?submodules=1";
29 flake = false;
30 };
31
Pin the native half to the release the rest of the tree names cb7f9f1 nandi 17d ago32 # v0.1.3, which is the rev deps.edn and the scripts/*.dotslash pins both
33 # name. Pinned, and pinned to that: this input carries both halves of
34 # glimmer-vidya — libvidya, and the Jolt side that binds it — so an
35 # unpinned `main` is a build whose native half is free to sit at a
36 # different commit from the tree that talks to it. It did, and what the
37 # drift cost was silence: the Jolt half sent a reaction pill's hover card
38 # to a libvidya with no handler for one, and the pill said nothing.
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago39 jolt-native = {
Pin the native half to the release the rest of the tree names cb7f9f1 nandi 17d ago40 url = "git+https://gitlab.com/nandithebull/jolt-native?rev=fd0e21a6c5d745ff9d134f92f909665454a7a1c9";
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago41 flake = false;
42 };
43
Paint the same screens into a terminal ab83b42 nandi 17d ago44 # The terminal backend, which v0.1.3 has not got: crates/jolt-tui (the tree
45 # ABI over a grid of cells) and jolt/glimmer-tui (the jolt side that binds
Pin the terminal backend at the fix its chats list needed d6bf5a7 nandi 17d ago46 # it). On a branch rather than a tag because the backend is still being
47 # fixed against this client — the last bump was a box that painted its
48 # first child and dropped the rest, which is what the chats list here was
49 # showing. Its own input rather than a bump of the one above, deliberately —
Paint the same screens into a terminal ab83b42 nandi 17d ago50 # the window half stays pinned to the release the rest of the tree names,
51 # and only `tui` evaluates this. When the backend ships in a release the
52 # two become one pin again.
53 jolt-native-tui = {
Fit a conversation on the screen, not two messages of one 8a86eb3 nandi 17d ago54 url = "git+https://gitlab.com/nandithebull/jolt-native?rev=c4f56b0a96ecb29336e2cf16c522b794ae62ad3f";
Paint the same screens into a terminal ab83b42 nandi 17d ago55 flake = false;
56 };
57
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago58 # Chez itself, because the APK needs a cross target nixpkgs does not
59 # build: frq's Scheme is compiled to an arm64 boot image, and that wants
60 # Chez's own `tarm64le` workarea — boot files, xpatch and libkernel.a.
61 # The version is the one the hand-built tree under ~/.cache used, and the
62 # submodules are not optional (zuo builds it, lz4 and zlib link into it).
63 # The fork jolt's own Android pin names, built here rather than fetched as
64 # a release binary: upstream reads the socket address out of `struct
65 # addrinfo` at glibc's offset, which on Bionic is `ai_canonname`, so an APK
66 # built with upstream cannot open a TLS connection at all. Only the boot
67 # image uses it; the desktop package still builds jolt-src.
68 jolt-android-src = {
69 url = "git+https://gitlab.com/nandithebull/jolt?rev=2b80d68d1f7a31ba92b208b3957e5fb555617ada&submodules=1";
70 flake = false;
71 };
72
73 chez-src = {
74 url = "git+https://github.com/cisco/ChezScheme?ref=refs/tags/v10.4.1&submodules=1";
75 flake = false;
76 };
77
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago78 # The sha deps.edn pins, on the fork with the reconciler fixes.
79 glimmer = {
80 url = "git+https://gitlab.com/nandithebull/glimmer?rev=399df371c790d690fb6e4560c3d4d7f838502857";
81 flake = false;
82 };
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago83
84 # Only ever used off NixOS, to put the host GL driver on the loader path.
85 nixgl = {
86 url = "github:nix-community/nixGL";
87 inputs.nixpkgs.follows = "nixpkgs";
88 };
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 18d ago89
90 # Wraps a closure into a single self-extracting file. Only the `appimage`
91 # output evaluates it.
92 nix-appimage = {
93 url = "github:ralismark/nix-appimage";
94 inputs.nixpkgs.follows = "nixpkgs";
95 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago96 };
97
Paint the same screens into a terminal ab83b42 nandi 17d ago98 outputs = { self, nixpkgs, jolt-src, jolt-native, jolt-native-tui, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago99 let
100 systems = [ "x86_64-linux" "aarch64-linux" ];
101 forEachSystem = f:
102 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
103 in
104 {
105 packages = forEachSystem (pkgs:
106 let
107 inherit (pkgs) lib;
108
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago109 # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
110 # wrappers are the ones that need --impure (they read the host kernel
111 # module's version), which is why this only ever reaches for Intel.
112 nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel;
113
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago114 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
115 # libjoltmoq (the AV media plane). One workspace, two cdylibs.
116 native = pkgs.rustPlatform.buildRustPackage {
117 pname = "jolt-native";
118 version = "0.1.0";
119 src = jolt-native;
120
121 cargoLock = {
122 lockFile = "${jolt-native}/Cargo.lock";
123 allowBuiltinFetchGit = true;
124 };
125
126 nativeBuildInputs = with pkgs; [
127 pkg-config
128 cmake
129 rustPlatform.bindgenHook
130 ];
131
132 buildInputs = with pkgs; [
133 alsa-lib
134 pipewire
135 openssl
136 libxkbcommon
137 wayland
138 libGL
139 ];
140
141 # Upstream's .cargo/config.toml drives the whole build through
142 # DotSlash: a pinned rustc, sccache, and zig as the C/C++ compiler
143 # and linker, each fetched from the network on first use. None of
144 # that survives a build sandbox, and none of it is needed when the
145 # toolchain comes from the store — so drop it and let stdenv's cc
146 # link (openh264 is C++, which stdenv covers too).
147 postPatch = ''
148 rm -f .cargo/config.toml
149 '';
150
151 # bindgen reads linux/videodev2.h directly; upstream points it at
152 # zig's bundled headers, which under Nix is just the kernel headers.
153 V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
154
155 doCheck = false;
156
157 installPhase = ''
158 runHook preInstall
159 mkdir -p "$out/lib"
160 install -m644 target/*/release/*.so "$out/lib/"
161 runHook postInstall
162 '';
163 };
164
Paint the same screens into a terminal ab83b42 nandi 17d ago165 # libjolttui alone, out of the tui input's workspace. One crate
166 # rather than the whole of it: the terminal backend's dependencies
167 # are crossterm and a width table, where libvidya's and libjoltmoq's
168 # are egui, openh264 and v4l — none of which a terminal needs, and
169 # all of which this would otherwise build a second time at a second
170 # rev.
171 nativeTui = pkgs.rustPlatform.buildRustPackage {
172 pname = "jolt-tui";
173 version = "0.1.0";
174 src = jolt-native-tui;
175
176 cargoLock = {
177 lockFile = "${jolt-native-tui}/Cargo.lock";
178 allowBuiltinFetchGit = true;
179 };
180
181 nativeBuildInputs = with pkgs; [ pkg-config cmake rustPlatform.bindgenHook ];
182 buildInputs = with pkgs; [ alsa-lib pipewire openssl libxkbcommon wayland libGL ];
183
184 cargoBuildFlags = [ "-p" "jolt-tui" ];
185
186 # As above: upstream's .cargo/config.toml drives the build through
187 # DotSlash, which a sandbox has no network for.
188 postPatch = ''
189 rm -f .cargo/config.toml
190 '';
191
192 V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
193 doCheck = false;
194
195 installPhase = ''
196 runHook preInstall
197 mkdir -p "$out/lib"
198 install -m644 target/*/release/libjolttui.so "$out/lib/"
199 runHook postInstall
200 '';
201 };
202
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago203 # 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 ago204 # A function, because there are two of them — upstream for the
205 # desktop, and the Bionic-addrinfo fork for the boot image the APK
206 # carries. Nothing else about the build differs.
207 joltFrom = src: pkgs.stdenv.mkDerivation {
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago208 pname = "jolt";
209 version = "dev";
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago210 inherit src;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago211
212 strictDeps = true;
213 nativeBuildInputs = with pkgs; [ chez makeWrapper pkg-config xxd ];
214 buildInputs = with pkgs; [ lz4 zlib ncurses openssl libuuid ];
215
216 JOLT_VERSION = "dev";
217 dontConfigure = true;
218
219 buildPhase = ''
220 runHook preBuild
221 scheme --script host/chez/build-jolt.ss release target/release/jolt
222 runHook postBuild
223 '';
224
225 installPhase = ''
226 runHook preInstall
227 mkdir -p "$out/bin"
228 install -m755 target/release/jolt "$out/bin/jolt"
229 runHook postInstall
230 '';
231
232 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
233 # OpenSSL through the JOLT_OPENSSL_LIBDIR seam.
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 18d ago234 #
235 # TZDIR so a zone *name* resolves wherever this runs: frq.clock
236 # hands one to tzset, and glibc then looks for the tzfile under
237 # /usr/share/zoneinfo unless told otherwise — which a NixOS host
238 # does not have. The store's own tzdata is there on both kinds of
239 # 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 ago240 postFixup = ''
241 wrapProgram "$out/bin/jolt" \
242 --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \
243 --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 ago244 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago245 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
246 '';
247 };
248
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago249 joltRuntime = joltFrom jolt-src;
250 joltAndroid = joltFrom jolt-android-src;
251
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago252 # glimmer-vidya lives inside the jolt-native checkout, and its own
253 # deps.edn asks for glimmer by git — the top-level override below
254 # answers for both.
255 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
Paint the same screens into a terminal ab83b42 nandi 17d ago256 glimmerTui = "${jolt-native-tui}/jolt/glimmer-tui";
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago257
258 # egui reaches for these with dlopen rather than linking them, so
259 # being in the cdylib's buildInputs is not enough — the launcher has
260 # to put them on the loader path itself. Without libX11 here, vidya
261 # reports "X11 unavailable", falls back to Wayland, and winit refuses
262 # to build a second event loop after the failed first one.
263 runtimeLibs = with pkgs; [
264 libGL
265 libxkbcommon
266 wayland
267 xorg.libX11
268 xorg.libXcursor
269 xorg.libXi
270 xorg.libXrandr
271 vulkan-loader
272 ];
273
274 # The project as jolt sees it: source, deps.edn, nothing else.
275 frqSource = pkgs.runCommand "frq-source" { } ''
276 mkdir -p "$out"
277 cp -r ${self}/src ${self}/deps.edn "$out/"
278 '';
279
280 # Jolt resolves deps.edn from the working directory, so the launcher
281 # runs from the store copy. Its .jolt/cpcache write lands on a
282 # read-only directory and jolt treats that as a quiet cache miss, so
283 # the only cost is re-resolving the (already local) graph per start.
284 frqScript = pkgs.writeShellScript "frq" ''
285 export LD_LIBRARY_PATH="${native}/lib:${lib.makeLibraryPath runtimeLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
286 cd ${frqSource}
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago287
288 # On NixOS the store's Mesa is the system's and the window opens.
289 # Anywhere else the real driver is the host's, so defer to nixGL
290 # it prepends the host driver, which has to win over ours.
291 runner=""
292 [ -e /run/current-system ] || runner="${nixGL}/bin/nixGLIntel"
293
294 exec ''${runner} ${joltRuntime}/bin/jolt \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago295 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-vidya {:local/root "${glimmerVidya}"}}}' \
296 -M:frq "$@"
297 '';
298
Paint the same screens into a terminal ab83b42 nandi 17d ago299 # The same source, the other backend. No GL, no nixGL and no X11 —
300 # a terminal is the one surface that needs nothing from the host but
301 # a terminal, which is the reason this output exists.
302 tuiScript = pkgs.writeShellScript "frq-tui" ''
303 export LD_LIBRARY_PATH="${nativeTui}/lib:${native}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
304 cd ${frqSource}
305
306 exec ${joltRuntime}/bin/jolt \
307 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-vidya {:local/root "${glimmerVidya}"} nandi/glimmer-tui {:local/root "${glimmerTui}"}}}' \
308 -m frq.tui "$@"
309 '';
310
311 tui = pkgs.runCommand "frq-tui-0.1.0"
312 {
313 meta = {
314 description = "frq's screens in a terminal";
315 mainProgram = "frq-tui";
316 platforms = systems;
317 };
318 }
319 ''
320 mkdir -p "$out/bin"
321 ln -s ${tuiScript} "$out/bin/frq-tui"
322 '';
323
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago324 frq = pkgs.runCommand "frq-0.1.0"
325 {
326 meta = {
327 description = "A freeq client in jolt";
328 mainProgram = "frq";
329 platforms = systems;
330 };
331 }
332 ''
333 mkdir -p "$out/bin"
334 ln -s ${frqScript} "$out/bin/frq"
335 '';
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago336 # --- Android ------------------------------------------------------
337 # The SDK and the NDK are Google's, which means unfree and a licence
338 # to accept — so this is its own import of nixpkgs rather than the
339 # `legacyPackages` everything above uses. Confined to the Android
340 # outputs: `nix build` of frq itself never evaluates it.
341 #
342 # The NDK here is r29, which is the version scripts/android-ndk.dotslash
343 # pins and the one the pinned libvidya was built with.
344 androidPkgs = import nixpkgs {
345 inherit (pkgs.stdenv.hostPlatform) system;
346 config = {
347 allowUnfree = true;
348 android_sdk.accept_license = true;
349 };
350 };
351
352 androidComposition = androidPkgs.androidenv.composeAndroidPackages {
353 buildToolsVersions = [ "36.0.0" ];
354 platformVersions = [ "36" ];
355 includeNDK = true;
356 };
357
358 android = import ./nix/android.nix {
359 inherit pkgs self chez-src jolt-native glimmer joltAndroid;
360 inherit (pkgs) lib;
361 androidSdk = androidComposition.androidsdk;
362 ndk = androidComposition.ndk-bundle;
363 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago364 in
365 {
366 inherit native frq;
Paint the same screens into a terminal ab83b42 nandi 17d ago367 inherit nativeTui tui;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago368 jolt = joltRuntime;
369 default = frq;
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 18d ago370
371 # frq and everything it loads, squashed into one runnable file for
372 # hosts without Nix. The whole closure rides along — Mesa included,
373 # which is not waste: off NixOS the launcher goes through nixGL, and
374 # nixGL needs a store Mesa to put the host's driver in front of.
375 appimage =
376 nix-appimage.bundlers.${pkgs.stdenv.hostPlatform.system}.default frq;
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago377 }
378 # An APK is built by a linux-x86_64 NDK and a linux-x86_64 jolt, and
379 # Google ships no other; on aarch64 the Android outputs are simply
380 # absent rather than present and broken.
381 // lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "x86_64-linux") {
382 inherit (android) apk chezAndroid joltBoot libjoltapp;
383 apk-unsigned = android.apk-unsigned;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago384 });
385
386 apps = forEachSystem (pkgs: {
387 default = {
388 type = "app";
389 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.frq}/bin/frq";
390 };
Paint the same screens into a terminal ab83b42 nandi 17d ago391 tui = {
392 type = "app";
393 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.tui}/bin/frq-tui";
394 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago395 });
396 };
397}