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