1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
{
# frq is Jolt source, so "building" it is three things, not one:
#
# jolt the runtime that reads it (github:jolt-lang/jolt)
# jolt-native libvidya and libjoltmoq, in Rust (gitlab:nandithebull/jolt-native)
# frq this tree, with its deps resolved to store paths
#
# Jolt resolves deps.edn by running git at startup, which a build sandbox has
# no network for — so every dep is fetched by Nix instead and handed back as
# a :local/root through -Sdeps.
#
# nix build .#frq && ./result/bin/frq
#
# On a machine that is not NixOS the GL driver is the host's and the loader
# will not find it, so the window never opens ("GL display: argument does not
# name a valid config"). Launch through nixGL there:
#
# nix run --impure "git+https://github.com/nix-community/nixGL#nixGLIntel" -- ./result/bin/frq
description = "frq — a freeq client in jolt";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# Jolt's own flake declares `self.submodules`, which this Nix rejects when
# the flake is fetched through the github scheme — so take the source and
# build it here. `vendor/` is a submodule and the build needs it.
jolt-src = {
url = "git+https://github.com/jolt-lang/jolt?submodules=1";
flake = false;
};
jolt-native = {
url = "git+https://gitlab.com/nandithebull/jolt-native";
flake = false;
};
# The sha deps.edn pins, on the fork with the reconciler fixes.
glimmer = {
url = "git+https://gitlab.com/nandithebull/glimmer?rev=399df371c790d690fb6e4560c3d4d7f838502857";
flake = false;
};
};
outputs = { self, nixpkgs, jolt-src, jolt-native, glimmer }:
let
systems = [ "x86_64-linux" "aarch64-linux" ];
forEachSystem = f:
nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
in
{
packages = forEachSystem (pkgs:
let
inherit (pkgs) lib;
# libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
# libjoltmoq (the AV media plane). One workspace, two cdylibs.
native = pkgs.rustPlatform.buildRustPackage {
pname = "jolt-native";
version = "0.1.0";
src = jolt-native;
cargoLock = {
lockFile = "${jolt-native}/Cargo.lock";
allowBuiltinFetchGit = true;
};
nativeBuildInputs = with pkgs; [
pkg-config
cmake
rustPlatform.bindgenHook
];
buildInputs = with pkgs; [
alsa-lib
pipewire
openssl
libxkbcommon
wayland
libGL
];
# Upstream's .cargo/config.toml drives the whole build through
# DotSlash: a pinned rustc, sccache, and zig as the C/C++ compiler
# and linker, each fetched from the network on first use. None of
# that survives a build sandbox, and none of it is needed when the
# toolchain comes from the store — so drop it and let stdenv's cc
# link (openh264 is C++, which stdenv covers too).
postPatch = ''
rm -f .cargo/config.toml
'';
# bindgen reads linux/videodev2.h directly; upstream points it at
# zig's bundled headers, which under Nix is just the kernel headers.
V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
doCheck = false;
installPhase = ''
runHook preInstall
mkdir -p "$out/lib"
install -m644 target/*/release/*.so "$out/lib/"
runHook postInstall
'';
};
# Jolt itself: Clojure on Chez, built the way its own flake builds it.
joltRuntime = pkgs.stdenv.mkDerivation {
pname = "jolt";
version = "dev";
src = jolt-src;
strictDeps = true;
nativeBuildInputs = with pkgs; [ chez makeWrapper pkg-config xxd ];
buildInputs = with pkgs; [ lz4 zlib ncurses openssl libuuid ];
JOLT_VERSION = "dev";
dontConfigure = true;
buildPhase = ''
runHook preBuild
scheme --script host/chez/build-jolt.ss release target/release/jolt
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p "$out/bin"
install -m755 target/release/jolt "$out/bin/jolt"
runHook postInstall
'';
# jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
# OpenSSL through the JOLT_OPENSSL_LIBDIR seam.
postFixup = ''
wrapProgram "$out/bin/jolt" \
--prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \
--set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \
--set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
'';
};
# glimmer-vidya lives inside the jolt-native checkout, and its own
# deps.edn asks for glimmer by git — the top-level override below
# answers for both.
glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
# egui reaches for these with dlopen rather than linking them, so
# being in the cdylib's buildInputs is not enough — the launcher has
# to put them on the loader path itself. Without libX11 here, vidya
# reports "X11 unavailable", falls back to Wayland, and winit refuses
# to build a second event loop after the failed first one.
runtimeLibs = with pkgs; [
libGL
libxkbcommon
wayland
xorg.libX11
xorg.libXcursor
xorg.libXi
xorg.libXrandr
vulkan-loader
];
# The project as jolt sees it: source, deps.edn, nothing else.
frqSource = pkgs.runCommand "frq-source" { } ''
mkdir -p "$out"
cp -r ${self}/src ${self}/deps.edn "$out/"
'';
# Jolt resolves deps.edn from the working directory, so the launcher
# runs from the store copy. Its .jolt/cpcache write lands on a
# read-only directory and jolt treats that as a quiet cache miss, so
# the only cost is re-resolving the (already local) graph per start.
frqScript = pkgs.writeShellScript "frq" ''
export LD_LIBRARY_PATH="${native}/lib:${lib.makeLibraryPath runtimeLibs}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
cd ${frqSource}
exec ${joltRuntime}/bin/jolt \
-Sdeps '{:deps {jolt-lang/glimmer {:local/root "${glimmer}"} nandi/glimmer-vidya {:local/root "${glimmerVidya}"}}}' \
-M:frq "$@"
'';
frq = pkgs.runCommand "frq-0.1.0"
{
meta = {
description = "A freeq client in jolt";
mainProgram = "frq";
platforms = systems;
};
}
''
mkdir -p "$out/bin"
ln -s ${frqScript} "$out/bin/frq"
'';
in
{
inherit native frq;
jolt = joltRuntime;
default = frq;
});
apps = forEachSystem (pkgs: {
default = {
type = "app";
program = "${self.packages.${pkgs.stdenv.hostPlatform.system}.frq}/bin/frq";
};
});
};
}
|