Skip to content

feat(nix): build and bundle terminal.so in the flake#2207

Merged
theangelperalta merged 4 commits into
lem-project:mainfrom
theangelperalta:feat/nix-terminal-so
Jun 3, 2026
Merged

feat(nix): build and bundle terminal.so in the flake#2207
theangelperalta merged 4 commits into
lem-project:mainfrom
theangelperalta:feat/nix-terminal-so

Conversation

@theangelperalta
Copy link
Copy Markdown
Collaborator

Summary

Makes the terminal extension work in Nix builds by compiling and bundling terminal.so in the flake. Until now the flake had no libvterm input and no terminal build step, so on Nix the terminal extension silently disabled itself.

Why

ffi.lisp loads terminal.so best-effort (ignore-errors), and the flake builds Lem via lisp.buildASDFSystem with native deps declared in nativeLibs (ncurses, tree-sitter, ts-wrapper, webview) — but never libvterm/terminal.so. So:

Change

  • New terminal-so derivation that compiles extensions/terminal/terminal.c against pkgs.libvterm, mirroring the existing ts-wrapper / c-webview C derivations.
  • Added to nativeLibs of lem-ncurses, lem-sdl2, and lem-webview (both branches).

Why dynamic (not static like #2205)

On Nix, dynamic linking is the idiomatic and more reliable choice:

  • The stdenv records an RPATH to the pinned libvterm store path, so terminal.so resolves libvterm at runtime with no bundling or relinking — exactly how ts-wrapper resolves tree-sitter today.
  • nativeLibs puts terminal.so itself on the library path that ffi.lisp's "terminal.so" lookup uses, at both build time (so CFFI registers it for image-restore reload) and run time (baked into the wrapProgram LD_LIBRARY_PATH).
  • Static linking would require a libvterm.a that nixpkgs doesn't ship by default.

The output keeps the .so suffix on both platforms (not .dylib), because ffi.lisp loads it by the literal name terminal.so even on macOS.

Test plan

  • Nix CI (.github/workflows/ci.yml) runs nix flake check + nix build .#lem-ncurses/.#lem-webview/.#lem-sdl2 on Linux and macOS — this builds the terminal-so derivation and is the authoritative check. (Could not run nix locally — no nix on this machine.)
  • Confirm pkgs.libvterm is the correct attr and its version compiles terminal.c (the conceal/strike cell-attr fields need libvterm ≥ 0.3; if nixpkgs' libvterm is too old or misnamed, fall back to pkgs.libvterm-neovim).
  • Launch the Nix-built lem, open a *terminal* buffer, confirm a shell runs.

Refs #1964, #2060, #2204, #2205.

The Nix flake never built the lem-terminal native helper: it has no
libvterm input and no terminal.c build step, so on Nix the terminal
extension silently disabled itself (ffi.lisp's use-foreign-library is
wrapped in ignore-errors). Removing the committed binaries in lem-project#2204 did not
regress this -- the prebuilt .so was dynamically linked against a libvterm
that was never present in the Nix sandbox -- but it also left Nix without a
working terminal.

Add a terminal-so derivation that compiles extensions/terminal/terminal.c
against pkgs.libvterm, mirroring the existing ts-wrapper / c-webview C
derivations, and add it to the nativeLibs of lem-ncurses, lem-sdl2 and
lem-webview.

Dynamic linking is the idiomatic choice on Nix (unlike the AppImage/macOS
bundles, which static-link in lem-project#2205): the stdenv records an RPATH to the
pinned libvterm store path, so terminal.so resolves libvterm at runtime with
no bundling or relinking, and nativeLibs puts terminal.so itself on the
library path that ffi.lisp's "terminal.so" lookup uses at build and run time.
nixpkgs' libvterm (0.99.7) has meta.platforms = Linux only, so referencing
pkgs.libvterm unconditionally made `nix flake check --all-systems` fail at
evaluation on the aarch64-darwin / x86_64-darwin systems, breaking every
build job.

Add terminal-so to nativeLibs only when stdenv.isLinux (via lib.optionals,
which doesn't force its list when the condition is false). Terminal works on
Linux Nix builds; Darwin Nix is unchanged (no terminal, as before, since
nixpkgs doesn't package libvterm for Darwin).
…ovim fork)

nixpkgs' libvterm (0.99.7) is the Neovim fork, whose vterm.h #includes
<glib.h>. terminal.c includes vterm.h, so the build failed with
"fatal error: glib.h: No such file or directory".

Add pkg-config + glib and pull GLib's compile/link flags via
`pkg-config --cflags --libs glib-2.0`.
The compile failed on glib.h then curses.h from libvterm-0.99.7's vterm.h
because pkgs.libvterm is the old, abandoned glib/curses-based "libvterm" with
an API incompatible with terminal.c. Leonerd's modern libvterm -- the one
terminal.c targets -- is packaged as pkgs.libvterm-neovim.

Switch to pkgs.libvterm-neovim and drop the glib/pkg-config workaround.
@haxfn
Copy link
Copy Markdown

haxfn commented Jun 3, 2026

Seems to work for me on NixOS:

image

@theangelperalta theangelperalta merged commit 08d1420 into lem-project:main Jun 3, 2026
10 checks passed
@theangelperalta theangelperalta deleted the feat/nix-terminal-so branch June 3, 2026 13:07
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