nandi/frqpublic Fork 0
cb7f9f124f4046a2ff7e58ebaaf74b2f99be2f1d
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 · 314 lines · 13.0 KBNix Blame HistoryRaw
Build the client with Nix, not just a shell for it ca3afbe nandi 20d 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 20d 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 20d 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 18d 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 20d ago39 jolt-native = {
Pin the native half to the release the rest of the tree names cb7f9f1 nandi 18d ago40 url = "git+https://gitlab.com/nandithebull/jolt-native?rev=fd0e21a6c5d745ff9d134f92f909665454a7a1c9";
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago41 flake = false;
42 };
43
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago44 # Chez itself, because the APK needs a cross target nixpkgs does not
45 # build: frq's Scheme is compiled to an arm64 boot image, and that wants
46 # Chez's own `tarm64le` workarea — boot files, xpatch and libkernel.a.
47 # The version is the one the hand-built tree under ~/.cache used, and the
48 # submodules are not optional (zuo builds it, lz4 and zlib link into it).
49 # The fork jolt's own Android pin names, built here rather than fetched as
50 # a release binary: upstream reads the socket address out of `struct
51 # addrinfo` at glibc's offset, which on Bionic is `ai_canonname`, so an APK
52 # built with upstream cannot open a TLS connection at all. Only the boot
53 # image uses it; the desktop package still builds jolt-src.
54 jolt-android-src = {
55 url = "git+https://gitlab.com/nandithebull/jolt?rev=2b80d68d1f7a31ba92b208b3957e5fb555617ada&submodules=1";
56 flake = false;
57 };
58
59 chez-src = {
60 url = "git+https://github.com/cisco/ChezScheme?ref=refs/tags/v10.4.1&submodules=1";
61 flake = false;
62 };
63
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago64 # The sha deps.edn pins, on the fork with the reconciler fixes.
65 glimmer = {
66 url = "git+https://gitlab.com/nandithebull/glimmer?rev=399df371c790d690fb6e4560c3d4d7f838502857";
67 flake = false;
68 };
Find the host's GL driver when the store's is not the system's 633faad nandi 20d ago69
70 # Only ever used off NixOS, to put the host GL driver on the loader path.
71 nixgl = {
72 url = "github:nix-community/nixGL";
73 inputs.nixpkgs.follows = "nixpkgs";
74 };
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 19d ago75
76 # Wraps a closure into a single self-extracting file. Only the `appimage`
77 # output evaluates it.
78 nix-appimage = {
79 url = "github:ralismark/nix-appimage";
80 inputs.nixpkgs.follows = "nixpkgs";
81 };
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago82 };
83
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 19d ago84 outputs = { self, nixpkgs, jolt-src, jolt-native, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago85 let
86 systems = [ "x86_64-linux" "aarch64-linux" ];
87 forEachSystem = f:
88 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
89 in
90 {
91 packages = forEachSystem (pkgs:
92 let
93 inherit (pkgs) lib;
94
Find the host's GL driver when the store's is not the system's 633faad nandi 20d ago95 # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
96 # wrappers are the ones that need --impure (they read the host kernel
97 # module's version), which is why this only ever reaches for Intel.
98 nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel;
99
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago100 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
101 # libjoltmoq (the AV media plane). One workspace, two cdylibs.
102 native = pkgs.rustPlatform.buildRustPackage {
103 pname = "jolt-native";
104 version = "0.1.0";
105 src = jolt-native;
106
107 cargoLock = {
108 lockFile = "${jolt-native}/Cargo.lock";
109 allowBuiltinFetchGit = true;
110 };
111
112 nativeBuildInputs = with pkgs; [
113 pkg-config
114 cmake
115 rustPlatform.bindgenHook
116 ];
117
118 buildInputs = with pkgs; [
119 alsa-lib
120 pipewire
121 openssl
122 libxkbcommon
123 wayland
124 libGL
125 ];
126
127 # Upstream's .cargo/config.toml drives the whole build through
128 # DotSlash: a pinned rustc, sccache, and zig as the C/C++ compiler
129 # and linker, each fetched from the network on first use. None of
130 # that survives a build sandbox, and none of it is needed when the
131 # toolchain comes from the store — so drop it and let stdenv's cc
132 # link (openh264 is C++, which stdenv covers too).
133 postPatch = ''
134 rm -f .cargo/config.toml
135 '';
136
137 # bindgen reads linux/videodev2.h directly; upstream points it at
138 # zig's bundled headers, which under Nix is just the kernel headers.
139 V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
140
141 doCheck = false;
142
143 installPhase = ''
144 runHook preInstall
145 mkdir -p "$out/lib"
146 install -m644 target/*/release/*.so "$out/lib/"
147 runHook postInstall
148 '';
149 };
150
151 # Jolt itself: Clojure on Chez, built the way its own flake builds it.
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago152 # A function, because there are two of them — upstream for the
153 # desktop, and the Bionic-addrinfo fork for the boot image the APK
154 # carries. Nothing else about the build differs.
155 joltFrom = src: pkgs.stdenv.mkDerivation {
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago156 pname = "jolt";
157 version = "dev";
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago158 inherit src;
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago159
160 strictDeps = true;
161 nativeBuildInputs = with pkgs; [ chez makeWrapper pkg-config xxd ];
162 buildInputs = with pkgs; [ lz4 zlib ncurses openssl libuuid ];
163
164 JOLT_VERSION = "dev";
165 dontConfigure = true;
166
167 buildPhase = ''
168 runHook preBuild
169 scheme --script host/chez/build-jolt.ss release target/release/jolt
170 runHook postBuild
171 '';
172
173 installPhase = ''
174 runHook preInstall
175 mkdir -p "$out/bin"
176 install -m755 target/release/jolt "$out/bin/jolt"
177 runHook postInstall
178 '';
179
180 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
181 # OpenSSL through the JOLT_OPENSSL_LIBDIR seam.
Read the clock in the reader's zone when /etc/localtime is a file bffe879 nandi 19d ago182 #
183 # TZDIR so a zone *name* resolves wherever this runs: frq.clock
184 # hands one to tzset, and glibc then looks for the tzfile under
185 # /usr/share/zoneinfo unless told otherwise — which a NixOS host
186 # does not have. The store's own tzdata is there on both kinds of
187 # machine. --set-default, so a TZDIR the user set still wins.
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago188 postFixup = ''
189 wrapProgram "$out/bin/jolt" \
190 --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \
191 --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 19d ago192 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago193 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
194 '';
195 };
196
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago197 joltRuntime = joltFrom jolt-src;
198 joltAndroid = joltFrom jolt-android-src;
199
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago200 # glimmer-vidya lives inside the jolt-native checkout, and its own
201 # deps.edn asks for glimmer by git — the top-level override below
202 # answers for both.
203 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
204
205 # egui reaches for these with dlopen rather than linking them, so
206 # being in the cdylib's buildInputs is not enough — the launcher has
207 # to put them on the loader path itself. Without libX11 here, vidya
208 # reports "X11 unavailable", falls back to Wayland, and winit refuses
209 # to build a second event loop after the failed first one.
210 runtimeLibs = with pkgs; [
211 libGL
212 libxkbcommon
213 wayland
214 xorg.libX11
215 xorg.libXcursor
216 xorg.libXi
217 xorg.libXrandr
218 vulkan-loader
219 ];
220
221 # The project as jolt sees it: source, deps.edn, nothing else.
222 frqSource = pkgs.runCommand "frq-source" { } ''
223 mkdir -p "$out"
224 cp -r ${self}/src ${self}/deps.edn "$out/"
225 '';
226
227 # Jolt resolves deps.edn from the working directory, so the launcher
228 # runs from the store copy. Its .jolt/cpcache write lands on a
229 # read-only directory and jolt treats that as a quiet cache miss, so
230 # the only cost is re-resolving the (already local) graph per start.
231 frqScript = pkgs.writeShellScript "frq" ''
232 export LD_LIBRARY_PATH="${native}/lib:${lib.makeLibraryPath runtimeLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
233 cd ${frqSource}
Find the host's GL driver when the store's is not the system's 633faad nandi 20d ago234
235 # On NixOS the store's Mesa is the system's and the window opens.
236 # Anywhere else the real driver is the host's, so defer to nixGL
237 # it prepends the host driver, which has to win over ours.
238 runner=""
239 [ -e /run/current-system ] || runner="${nixGL}/bin/nixGLIntel"
240
241 exec ''${runner} ${joltRuntime}/bin/jolt \
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago242 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-vidya {:local/root "${glimmerVidya}"}}}' \
243 -M:frq "$@"
244 '';
245
246 frq = pkgs.runCommand "frq-0.1.0"
247 {
248 meta = {
249 description = "A freeq client in jolt";
250 mainProgram = "frq";
251 platforms = systems;
252 };
253 }
254 ''
255 mkdir -p "$out/bin"
256 ln -s ${frqScript} "$out/bin/frq"
257 '';
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago258 # --- Android ------------------------------------------------------
259 # The SDK and the NDK are Google's, which means unfree and a licence
260 # to accept — so this is its own import of nixpkgs rather than the
261 # `legacyPackages` everything above uses. Confined to the Android
262 # outputs: `nix build` of frq itself never evaluates it.
263 #
264 # The NDK here is r29, which is the version scripts/android-ndk.dotslash
265 # pins and the one the pinned libvidya was built with.
266 androidPkgs = import nixpkgs {
267 inherit (pkgs.stdenv.hostPlatform) system;
268 config = {
269 allowUnfree = true;
270 android_sdk.accept_license = true;
271 };
272 };
273
274 androidComposition = androidPkgs.androidenv.composeAndroidPackages {
275 buildToolsVersions = [ "36.0.0" ];
276 platformVersions = [ "36" ];
277 includeNDK = true;
278 };
279
280 android = import ./nix/android.nix {
281 inherit pkgs self chez-src jolt-native glimmer joltAndroid;
282 inherit (pkgs) lib;
283 androidSdk = androidComposition.androidsdk;
284 ndk = androidComposition.ndk-bundle;
285 };
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago286 in
287 {
288 inherit native frq;
289 jolt = joltRuntime;
290 default = frq;
Bundle the closure into one file the AppImage runtime mounts f82b93f nandi 19d ago291
292 # frq and everything it loads, squashed into one runnable file for
293 # hosts without Nix. The whole closure rides along — Mesa included,
294 # which is not waste: off NixOS the launcher goes through nixGL, and
295 # nixGL needs a store Mesa to put the host's driver in front of.
296 appimage =
297 nix-appimage.bundlers.${pkgs.stdenv.hostPlatform.system}.default frq;
Build the APK from the flake, and from nothing 6aa2a6b nandi 19d ago298 }
299 # An APK is built by a linux-x86_64 NDK and a linux-x86_64 jolt, and
300 # Google ships no other; on aarch64 the Android outputs are simply
301 # absent rather than present and broken.
302 // lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "x86_64-linux") {
303 inherit (android) apk chezAndroid joltBoot libjoltapp;
304 apk-unsigned = android.apk-unsigned;
Build the client with Nix, not just a shell for it ca3afbe nandi 20d ago305 });
306
307 apps = forEachSystem (pkgs: {
308 default = {
309 type = "app";
310 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.frq}/bin/frq";
311 };
312 });
313 };
314}