-
-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathflake.nix
More file actions
405 lines (375 loc) · 14.2 KB
/
flake.nix
File metadata and controls
405 lines (375 loc) · 14.2 KB
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
{
description = "Neomacs - GPU-accelerated Emacs written in Rust with a modern, multithreaded architecture";
nixConfig = {
extra-substituters = [ "https://nix-wpe-webkit.cachix.org" ];
extra-trusted-public-keys = [ "nix-wpe-webkit.cachix.org-1:ItCjHkz1Y5QcwqI9cTGNWHzcox4EqcXqKvOygxpwYHE=" ];
};
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
# Rust toolchain
rust-overlay = {
url = "github:oxalica/rust-overlay";
};
# Crane for incremental Rust builds (caches deps separately from source)
crane.url = "github:ipetkov/crane";
# WPE WebKit standalone flake with Cachix binary cache
# Do NOT use `inputs.nixpkgs.follows` here — the Cachix binary was built
# with nix-wpe-webkit's own pinned nixpkgs, so follows would change the
# derivation hash and cause a cache miss (rebuilding from source ~1 hour).
nix-wpe-webkit = {
url = "github:eval-exec/nix-wpe-webkit";
};
};
outputs = { self, nixpkgs, rust-overlay, crane, nix-wpe-webkit }:
let
lib = nixpkgs.lib;
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
forAllSystems = lib.genAttrs supportedSystems;
# Create pkgs with overlays for each system
pkgsFor = system: import nixpkgs {
inherit system;
overlays = [
rust-overlay.overlays.default
self.overlays.default
];
};
commonBuildInputsFor = pkgs: with pkgs; [
ncurses
gnutls
zlib
libxml2
fontconfig
freetype
harfbuzz
libotf
cairo
glib
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
gst_all_1.gst-plugins-good
gst_all_1.gst-plugins-bad
gst_all_1.gst-plugins-ugly
gst_all_1.gst-libav
gst_all_1.gst-plugins-rs
libsoup_3
glib-networking
libjpeg
libtiff
giflib
libpng
librsvg
libwebp
poppler
dbus
sqlite
tree-sitter
gmp
] ++ lib.optionals pkgs.stdenv.isLinux (with pkgs; [
gst_all_1.gst-vaapi
libva
libselinux
libgccjit
libGL
vulkan-loader
libxkbcommon
mesa
libdrm
libgbm
wayland
wayland-protocols
wpewebkit
libwpe
libwpe-fdo
weston
xdg-dbus-proxy
libx11
libxcursor
libxrandr
libxi
libxinerama
]);
commonNativeBuildInputsFor = pkgs: [
pkgs.rust-neomacs
pkgs.rust-cbindgen
pkgs.pkg-config
pkgs.autoconf
pkgs.automake
pkgs.texinfo
pkgs.llvmPackages.clang
pkgs.makeWrapper
];
mkNeomacsPackage = system:
let
pkgs = pkgsFor system;
craneLib = (crane.mkLib pkgs).overrideToolchain pkgs.rust-neomacs;
cargoSrc = craneLib.cleanCargoSource ./.;
packageSrc = builtins.path {
path = ./.;
name = "neomacs-source";
filter = path: _type:
let
base = builtins.baseNameOf path;
in
!(builtins.elem base [ ".git" ".direnv" "target" "result" ]);
};
pname = "neomacs";
version = self.shortRev or self.dirtyShortRev or self.lastModifiedDate or "0.0.1";
runtimeLibs = commonBuildInputsFor pkgs;
commonArgs = {
inherit pname version;
src = cargoSrc;
strictDeps = true;
cargoExtraArgs = "-p neomacs-bin";
nativeBuildInputs = commonNativeBuildInputsFor pkgs;
buildInputs = runtimeLibs;
doCheck = false;
};
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
linuxWrapArgs = lib.optionals pkgs.stdenv.isLinux [
"--set-default" "VK_DRIVER_FILES" "$(echo ${pkgs.mesa}/share/vulkan/icd.d/*.json | tr ' ' ':')"
"--set-default" "WPE_BACKEND_LIBRARY" "${pkgs.libwpe-fdo}/lib/libWPEBackend-fdo-1.0.so"
"--set-default" "GIO_MODULE_DIR" "${pkgs.glib-networking}/lib/gio/modules"
"--set-default" "WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS" "1"
"--set-default" "WEBKIT_USE_SINGLE_WEB_PROCESS" "1"
"--prefix" "PATH" ":" "${pkgs.wpewebkit}/libexec/wpe-webkit-2.0"
];
in
craneLib.buildPackage (commonArgs
// {
src = packageSrc;
inherit cargoArtifacts;
postInstall = ''
mkdir -p "$out/share/neomacs"
cp -r lisp "$out/share/neomacs/"
cp -r etc "$out/share/neomacs/"
chmod -R u+w "$out/share/neomacs"
wrapProgram "$out/bin/neomacs" \
--prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath runtimeLibs}" \
--set-default RUST_LOG info \
--set-default NEOMACS_RUNTIME_ROOT "$out/share/neomacs" \
${lib.concatStringsSep " \\\n " linuxWrapArgs}
'';
});
in {
# Overlay that provides wpewebkit (Linux only) and rust toolchain
overlays.default = final: prev: {
# Rust toolchain from rust-toolchain.toml (with extra extensions)
rust-neomacs = (final.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override {
extensions = [ "rust-src" "rust-analyzer" ];
};
} // (lib.optionalAttrs prev.stdenv.isLinux {
# WPE WebKit from nix-wpe-webkit flake (with Cachix binary cache)
# Only available on Linux — WPE WebKit does not support macOS.
wpewebkit = nix-wpe-webkit.packages.${final.stdenv.hostPlatform.system}.wpewebkit;
});
# Development shell
devShells = forAllSystems (system:
let
pkgs = pkgsFor system;
isLinux = pkgs.stdenv.isLinux;
isDarwin = pkgs.stdenv.isDarwin;
in {
default = pkgs.mkShell {
name = "neomacs-dev";
nativeBuildInputs = [
# Rust toolchain
pkgs.rust-neomacs
pkgs.rust-cbindgen
# Build tools
pkgs.pkg-config
pkgs.autoconf
pkgs.automake
pkgs.texinfo
# For bindgen (generates Rust bindings from C headers)
pkgs.llvmPackages.clang
];
buildInputs = commonBuildInputsFor pkgs
++ lib.optionals isLinux (with pkgs; [ gcc ]);
# pkg-config paths for dev headers
PKG_CONFIG_PATH = pkgs.lib.makeSearchPath "lib/pkgconfig" (with pkgs; [
glib.dev
cairo.dev
gst_all_1.gstreamer.dev
gst_all_1.gst-plugins-base.dev
fontconfig.dev
freetype.dev
harfbuzz.dev
libxml2.dev
gnutls.dev
zlib.dev
ncurses.dev
dbus.dev
sqlite.dev
tree-sitter
gmp.dev
libsoup_3.dev
poppler.dev
]
++ lib.optionals isLinux [
libva
libselinux.dev
libGL.dev
libxkbcommon.dev
libdrm.dev
mesa
wayland.dev
wpewebkit
libwpe
libwpe-fdo
]);
# For bindgen to find libclang
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
shellHook = ''
export RUST_BACKTRACE=1
echo "=== Neomacs Development Environment ==="
echo ""
echo "Rust: $(rustc --version)"
echo "Cargo: $(cargo --version)"
echo "GStreamer: $(pkg-config --modversion gstreamer-1.0 2>/dev/null || echo 'not found')"
''
# Linux-specific shell hook
+ lib.optionalString isLinux ''
echo "xkbcommon: $(pkg-config --modversion xkbcommon 2>/dev/null || echo 'not found')"
echo "WPE WebKit: $(pkg-config --modversion wpe-webkit-2.0 2>/dev/null || echo 'not found')"
echo ""
# Library path for runtime — DO NOT include ncurses here,
# it causes glibc version contamination with system shell.
# The linker adds RPATH for ncurses during compilation.
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath (with pkgs; [
glib
cairo
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
fontconfig
freetype
harfbuzz
libotf
libxml2
gnutls
libjpeg
libtiff
giflib
libpng
librsvg
libwebp
dbus
sqlite
gmp
libgccjit
libsoup_3
libGL
vulkan-loader
mesa
libdrm
libxkbcommon
libgbm
# X11 libs dynamically loaded by winit
libx11
libxcursor
libxrandr
libxi
libxinerama
wpewebkit
libwpe
libwpe-fdo
])}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
# Vulkan ICD discovery — tell the Vulkan loader where Mesa's
# driver JSON files are (e.g. intel_icd.x86_64.json for anv).
# Without this, wgpu can't find Vulkan drivers and falls back to OpenGL.
export VK_DRIVER_FILES="$(echo ${pkgs.mesa}/share/vulkan/icd.d/*.json | tr ' ' ':')"
# WPE WebKit environment
export WPE_BACKEND_LIBRARY="${pkgs.libwpe-fdo}/lib/libWPEBackend-fdo-1.0.so"
export GIO_MODULE_DIR="${pkgs.glib-networking}/lib/gio/modules"
export WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS=1
export WEBKIT_USE_SINGLE_WEB_PROCESS=1
export PATH="${pkgs.wpewebkit}/libexec/wpe-webkit-2.0:$PATH"
# X11/Wayland display — preserve from parent env or detect from running session.
# nix develop sanitizes env, so DISPLAY/XAUTHORITY may be lost.
# Detect them from a running desktop session via /proc/<pid>/environ.
_detect_display_env() {
local _pid
# NixOS wraps binaries, so process names may be e.g. ".kwin_x11-wrapp";
# use substring match (no -x flag) to handle this.
_pid=$(pgrep -u "$USER" kwin_x11 2>/dev/null | head -1)
[ -z "$_pid" ] && _pid=$(pgrep -u "$USER" gnome-shell 2>/dev/null | head -1)
[ -z "$_pid" ] && _pid=$(pgrep -u "$USER" Xorg 2>/dev/null | head -1)
[ -z "$_pid" ] && _pid=$(pgrep -u "$USER" sway 2>/dev/null | head -1)
[ -z "$_pid" ] && _pid=$(pgrep -u "$USER" Hyprland 2>/dev/null | head -1)
if [ -n "$_pid" ] && [ -r "/proc/$_pid/environ" ]; then
if [ -z "$DISPLAY" ]; then
DISPLAY=$(tr '\0' '\n' < /proc/$_pid/environ | grep '^DISPLAY=' | head -1 | cut -d= -f2-)
[ -n "$DISPLAY" ] && export DISPLAY
fi
if [ -z "$XAUTHORITY" ] && [ -n "$DISPLAY" ]; then
XAUTHORITY=$(tr '\0' '\n' < /proc/$_pid/environ | grep '^XAUTHORITY=' | head -1 | cut -d= -f2-)
if [ -n "$XAUTHORITY" ] && [ -f "$XAUTHORITY" ]; then
export XAUTHORITY
elif [ -f "$HOME/.Xauthority" ]; then
export XAUTHORITY="$HOME/.Xauthority"
fi
fi
if [ -z "$WAYLAND_DISPLAY" ]; then
WAYLAND_DISPLAY=$(tr '\0' '\n' < /proc/$_pid/environ | grep '^WAYLAND_DISPLAY=' | head -1 | cut -d= -f2-)
[ -n "$WAYLAND_DISPLAY" ] && export WAYLAND_DISPLAY
fi
fi
}
_detect_display_env
unset -f _detect_display_env
if [ -n "$DISPLAY" ]; then
echo "Display: DISPLAY=$DISPLAY XAUTHORITY=''${XAUTHORITY:-(unset)}"
if ! timeout 2s ${pkgs.xdpyinfo}/bin/xdpyinfo >/dev/null 2>&1; then
export NEOMACS_X11_UNUSABLE=1
echo "Warning: X11 display handshake failed for DISPLAY=$DISPLAY."
echo " GUI clients like winit/Neomacs may hang before the first window appears."
echo " Run from a working desktop terminal, set a valid DISPLAY/XAUTHORITY,"
echo " or use a private X server like Xvfb for automated probes."
fi
else
echo "Display: (no X11/Wayland display detected)"
fi
''
# Darwin-specific shell hook
+ lib.optionalString isDarwin ''
echo ""
echo "Note: WPE WebKit is not available on macOS."
echo " WebKit-based features will be disabled."
''
# Common shell hook (both platforms)
+ ''
# Set default log levels (can be overridden before entering nix develop)
export RUST_LOG="''${RUST_LOG:-debug}"
echo ""
echo "Build commands:"
echo " 1. cargo build --release -p neomacs-bin"
echo " 2. ./target/release/neomacs"
echo ""
echo "Logging (set before entering nix develop to override):"
echo " RUST_LOG=$RUST_LOG (trace|debug|info|warn|error)"
echo ""
'';
};
}
);
packages = forAllSystems (system:
let
neomacs = mkNeomacsPackage system;
in {
default = neomacs;
neomacs = neomacs;
});
apps = forAllSystems (system:
let
pkg = self.packages.${system}.default;
in {
default = {
type = "app";
program = "${pkg}/bin/neomacs";
};
neomacs = {
type = "app";
program = "${pkg}/bin/neomacs";
};
});
};
}