Skip to content

Fix NixOS build: nativeBuildInputs, wrapGAppsHook3, libayatana-appindicator runtime closure#1063

Open
Aypex wants to merge 1 commit intoRightNow-AI:mainfrom
Aypex:nixos-fixes
Open

Fix NixOS build: nativeBuildInputs, wrapGAppsHook3, libayatana-appindicator runtime closure#1063
Aypex wants to merge 1 commit intoRightNow-AI:mainfrom
Aypex:nixos-fixes

Conversation

@Aypex
Copy link
Copy Markdown

@Aypex Aypex commented Apr 16, 2026

Summary

Four independent fixes to flake.nix that together make a clean nix build .#openfang-cli and nix build .#openfang-desktop work on NixOS. Each is a real upstream bug, not a NixOS-only quirk — NixOS just surfaces them because it doesn't have system-wide /usr/lib as a fallback.

Tested on:

  • NixOS 26.05 (nixos-unstable channel)
  • AMD RX 7900 XTX / gfx1100 / Mesa
  • Hyprland 0.53+, webkitgtk_4_1, gtk3
  • openfang main @ current HEAD

The desktop window renders cleanly on first launch without any WEBKIT_* fallback env vars. Kernel boots, 61 skills load, 9 hands register, embedded server binds, default assistant agent spawns, tray initializes.

The Four Fixes

1. perl / clang / pkg-confignativeBuildInputs

Before:

rust-project.defaults.perCrate.crane.args.buildInputs = with pkgs; [
  clang openssl perl pkg-config
];

Symptom on NixOS:

openssl-src: failed to build OpenSSL from source
Command 'perl' not found. Is perl installed?

Why: These are build-time tools that openssl-src's build.rs invokes during cargo compilation. Nix distinguishes buildInputs (target/runtime deps, linked into the binary) from nativeBuildInputs (host-side tools available during the build). Other distros merge these, which is why the bug is invisible on macOS / Debian / Arch — perl just happens to be on $PATH. The fix is adding a sibling nativeBuildInputs declaration.

2. Desktop crate needs pkg-config + wrapGAppsHook3 in nativeBuildInputs

Symptom on NixOS: No package 'webkit2gtk-4.1' found during desktop compile; also missing GTK runtime env vars (XDG_DATA_DIRS, GIO_MODULE_DIR, etc.) so file dialogs and icons break at runtime.

Why: wrapGAppsHook3 is the standard NixOS pattern for GTK apps — it auto-wraps the resulting binaries with the right env vars. Note it's wrapGAppsHook3, not wrapGAppsHook (renamed in current nixpkgs because GTK4 now has its own wrapGAppsHook4). Plus pkg-config explicitly, since the per-crate buildInputs isn't enough to surface .pc files during the webkitgtk discovery step.

3. libayatana-appindicator in desktop buildInputs

Symptom on NixOS:

thread 'main' panicked at libappindicator-sys-0.9.0/src/lib.rs:41:5:
Failed to load ayatana-appindicator3 or appindicator3 dynamic library
libayatana-appindicator3.so.1: cannot open shared object file: No such file or directory

Why: The tray.rs module loads this library via runtime dlopen(), not link-time linking. On other distros it's in /usr/lib. On NixOS there's no system-wide /usr/lib, so it must be in the build closure.

4. preFixup hook injecting LD_LIBRARY_PATH for appindicator

Symptom: Same panic as #3, even after adding libayatana-appindicator to buildInputs.

Why (this one is subtle): A library only ends up in the Nix runtime closure if the binary actually links against it. libappindicator-sys uses pure runtime dlopen() with no compile-time link step, so Nix's reference scanner finds zero mentions of the lib in the compiled binary → lib gets dropped from the closure despite being in buildInputs.

The fix is a preFixup hook that appends --prefix LD_LIBRARY_PATH : ${libayatana-appindicator}/lib to the gappsWrapperArgs bash array. Two birds one stone: (a) the Nix string interpolation forces the store path into the output wrapper, so the reference scanner pulls it into the closure, and (b) wrapGAppsHook3 then bakes that LD_LIBRARY_PATH prefix into the runtime wrapper so dlopen() actually finds the lib.

This is the canonical pattern for Tauri-on-NixOS tray apps; most Nix packagers hit this exact wall once and then memorize the idiom.

Files changed

Just flake.nix — 15 additions, 0 deletions.

Commit

fix(flake): make NixOS build work end-to-end

[same content as above, condensed]

Notes for non-NixOS maintainers

If you don't run NixOS yourself and want to validate this without installing it, the fastest path is to use nix on your existing Linux box via curl -L https://nixos.org/nix/install | sh (unprivileged single-user install), then clone this branch and run nix build .#openfang-cli. Nix will handle all the dependencies in isolation — it won't touch your system package manager.

If CI would help, I'm happy to add a simple .github/workflows/nix-build.yml that runs nix build .#openfang-cli && nix build .#openfang-desktop on a NixOS runner to catch future regressions. Happy to do that in a follow-up PR if you're open to it.

Four issues prevented a clean nixos-rebuild on NixOS 26.05+ unstable:

1. perl/clang/pkg-config were in buildInputs but openssl-src's build.rs
   needs them on PATH at compile time → move to nativeBuildInputs.

2. openfang-desktop's GTK app needs wrapGAppsHook3 (renamed from
   wrapGAppsHook in current nixpkgs) and pkg-config in nativeBuildInputs
   to discover webkitgtk_4_1.pc and properly wrap runtime env vars.

3. libayatana-appindicator added to desktop buildInputs so the closure
   includes it. Without it, libappindicator-sys's runtime dlopen fails
   with 'cannot open shared object file' and the desktop binary panics
   at tray initialization.

4. preFixup hook injects libayatana-appindicator's lib path into
   gappsWrapperArgs. Required because the lib is dlopen'd at runtime
   (no link-time dep), so 'just adding to buildInputs' isn't enough —
   Nix's reference scanner only sees deps that appear in the binary.
   The string interpolation forces inclusion in the closure AND wraps
   LD_LIBRARY_PATH for the dlopen call to succeed.

Tested on NixOS 26.05 (nixos-unstable channel) with AMD RX 7900 XTX,
Hyprland 0.53+, webkitgtk_4_1, gtk3. Desktop window renders cleanly
without any WEBKIT_* fallback env vars.
@jaberjaber23
Copy link
Copy Markdown
Member

Confirmed this is the right NixOS packaging — clang/perl/pkg-config moved to nativeBuildInputs (correct for cross-compile hosts), wrapGAppsHook3 added for the tauri/GTK desktop, libayatana-appindicator runtime closure wired via preFixup LD_LIBRARY_PATH. Supersedes #1047 (closed).

Rebase on latest main when you have a moment so CI picks it up — should go green and land.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants