nandi/frqpublic Fork 0
03d5a6b415596ef67c4a9f68cfd4476e3ebd0afb
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 · 286 lines · 11.4 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 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago68 };
69
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago70 outputs = { self, nixpkgs, jolt-src, jolt-native, glimmer, chez-src, jolt-android-src, nixgl }:
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago71 let
72 systems = [ "x86_64-linux" "aarch64-linux" ];
73 forEachSystem = f:
74 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
75 in
76 {
77 packages = forEachSystem (pkgs:
78 let
79 inherit (pkgs) lib;
80
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago81 # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
82 # wrappers are the ones that need --impure (they read the host kernel
83 # module's version), which is why this only ever reaches for Intel.
84 nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel;
85
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago86 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
87 # libjoltmoq (the AV media plane). One workspace, two cdylibs.
88 native = pkgs.rustPlatform.buildRustPackage {
89 pname = "jolt-native";
90 version = "0.1.0";
91 src = jolt-native;
92
93 cargoLock = {
94 lockFile = "${jolt-native}/Cargo.lock";
95 allowBuiltinFetchGit = true;
96 };
97
98 nativeBuildInputs = with pkgs; [
99 pkg-config
100 cmake
101 rustPlatform.bindgenHook
102 ];
103
104 buildInputs = with pkgs; [
105 alsa-lib
106 pipewire
107 openssl
108 libxkbcommon
109 wayland
110 libGL
111 ];
112
113 # Upstream's .cargo/config.toml drives the whole build through
114 # DotSlash: a pinned rustc, sccache, and zig as the C/C++ compiler
115 # and linker, each fetched from the network on first use. None of
116 # that survives a build sandbox, and none of it is needed when the
117 # toolchain comes from the store — so drop it and let stdenv's cc
118 # link (openh264 is C++, which stdenv covers too).
119 postPatch = ''
120 rm -f .cargo/config.toml
121 '';
122
123 # bindgen reads linux/videodev2.h directly; upstream points it at
124 # zig's bundled headers, which under Nix is just the kernel headers.
125 V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
126
127 doCheck = false;
128
129 installPhase = ''
130 runHook preInstall
131 mkdir -p "$out/lib"
132 install -m644 target/*/release/*.so "$out/lib/"
133 runHook postInstall
134 '';
135 };
136
137 # 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 ago138 # A function, because there are two of them — upstream for the
139 # desktop, and the Bionic-addrinfo fork for the boot image the APK
140 # carries. Nothing else about the build differs.
141 joltFrom = src: pkgs.stdenv.mkDerivation {
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago142 pname = "jolt";
143 version = "dev";
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago144 inherit src;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago145
146 strictDeps = true;
147 nativeBuildInputs = with pkgs; [ chez makeWrapper pkg-config xxd ];
148 buildInputs = with pkgs; [ lz4 zlib ncurses openssl libuuid ];
149
150 JOLT_VERSION = "dev";
151 dontConfigure = true;
152
153 buildPhase = ''
154 runHook preBuild
155 scheme --script host/chez/build-jolt.ss release target/release/jolt
156 runHook postBuild
157 '';
158
159 installPhase = ''
160 runHook preInstall
161 mkdir -p "$out/bin"
162 install -m755 target/release/jolt "$out/bin/jolt"
163 runHook postInstall
164 '';
165
166 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
167 # OpenSSL through the JOLT_OPENSSL_LIBDIR seam.
168 postFixup = ''
169 wrapProgram "$out/bin/jolt" \
170 --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \
171 --set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \
172 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
173 '';
174 };
175
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago176 joltRuntime = joltFrom jolt-src;
177 joltAndroid = joltFrom jolt-android-src;
178
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago179 # glimmer-vidya lives inside the jolt-native checkout, and its own
180 # deps.edn asks for glimmer by git — the top-level override below
181 # answers for both.
182 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
183
184 # egui reaches for these with dlopen rather than linking them, so
185 # being in the cdylib's buildInputs is not enough — the launcher has
186 # to put them on the loader path itself. Without libX11 here, vidya
187 # reports "X11 unavailable", falls back to Wayland, and winit refuses
188 # to build a second event loop after the failed first one.
189 runtimeLibs = with pkgs; [
190 libGL
191 libxkbcommon
192 wayland
193 xorg.libX11
194 xorg.libXcursor
195 xorg.libXi
196 xorg.libXrandr
197 vulkan-loader
198 ];
199
200 # The project as jolt sees it: source, deps.edn, nothing else.
201 frqSource = pkgs.runCommand "frq-source" { } ''
202 mkdir -p "$out"
203 cp -r ${self}/src ${self}/deps.edn "$out/"
204 '';
205
206 # Jolt resolves deps.edn from the working directory, so the launcher
207 # runs from the store copy. Its .jolt/cpcache write lands on a
208 # read-only directory and jolt treats that as a quiet cache miss, so
209 # the only cost is re-resolving the (already local) graph per start.
210 frqScript = pkgs.writeShellScript "frq" ''
211 export LD_LIBRARY_PATH="${native}/lib:${lib.makeLibraryPath runtimeLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
212 cd ${frqSource}
Find the host's GL driver when the store's is not the system's 633faad nandi 19d ago213
214 # On NixOS the store's Mesa is the system's and the window opens.
215 # Anywhere else the real driver is the host's, so defer to nixGL
216 # it prepends the host driver, which has to win over ours.
217 runner=""
218 [ -e /run/current-system ] || runner="${nixGL}/bin/nixGLIntel"
219
220 exec ''${runner} ${joltRuntime}/bin/jolt \
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago221 -Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-vidya {:local/root "${glimmerVidya}"}}}' \
222 -M:frq "$@"
223 '';
224
225 frq = pkgs.runCommand "frq-0.1.0"
226 {
227 meta = {
228 description = "A freeq client in jolt";
229 mainProgram = "frq";
230 platforms = systems;
231 };
232 }
233 ''
234 mkdir -p "$out/bin"
235 ln -s ${frqScript} "$out/bin/frq"
236 '';
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago237 # --- Android ------------------------------------------------------
238 # The SDK and the NDK are Google's, which means unfree and a licence
239 # to accept — so this is its own import of nixpkgs rather than the
240 # `legacyPackages` everything above uses. Confined to the Android
241 # outputs: `nix build` of frq itself never evaluates it.
242 #
243 # The NDK here is r29, which is the version scripts/android-ndk.dotslash
244 # pins and the one the pinned libvidya was built with.
245 androidPkgs = import nixpkgs {
246 inherit (pkgs.stdenv.hostPlatform) system;
247 config = {
248 allowUnfree = true;
249 android_sdk.accept_license = true;
250 };
251 };
252
253 androidComposition = androidPkgs.androidenv.composeAndroidPackages {
254 buildToolsVersions = [ "36.0.0" ];
255 platformVersions = [ "36" ];
256 includeNDK = true;
257 };
258
259 android = import ./nix/android.nix {
260 inherit pkgs self chez-src jolt-native glimmer joltAndroid;
261 inherit (pkgs) lib;
262 androidSdk = androidComposition.androidsdk;
263 ndk = androidComposition.ndk-bundle;
264 };
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago265 in
266 {
267 inherit native frq;
268 jolt = joltRuntime;
269 default = frq;
Build the APK from the flake, and from nothing 6aa2a6b nandi 18d ago270 }
271 # An APK is built by a linux-x86_64 NDK and a linux-x86_64 jolt, and
272 # Google ships no other; on aarch64 the Android outputs are simply
273 # absent rather than present and broken.
274 // lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "x86_64-linux") {
275 inherit (android) apk chezAndroid joltBoot libjoltapp;
276 apk-unsigned = android.apk-unsigned;
Build the client with Nix, not just a shell for it ca3afbe nandi 19d ago277 });
278
279 apps = forEachSystem (pkgs: {
280 default = {
281 type = "app";
282 program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.frq}/bin/frq";
283 };
284 });
285 };
286}