Skip to content

chore(terminal): add build script for lem-terminal native helper#2182

Merged
theangelperalta merged 1 commit into
lem-project:mainfrom
theangelperalta:chore/terminal-build-script
May 30, 2026
Merged

chore(terminal): add build script for lem-terminal native helper#2182
theangelperalta merged 1 commit into
lem-project:mainfrom
theangelperalta:chore/terminal-build-script

Conversation

@theangelperalta
Copy link
Copy Markdown
Collaborator

Summary

Adds scripts/build-terminal.lisp and a make terminal-lib target that compiles extensions/terminal/terminal.c into the platform-specific path extensions/terminal/lib/<os>/<arch>/terminal.so — the same path extensions/terminal/ffi.lisp already pushes onto cffi:*foreign-library-directories* at runtime.

This is the missing build path discussed in #1964 and #2060, so the prebuilt .so binaries can eventually be removed from version control without breaking source installs.

Why this scope

The target is optional and standalone:

  • lem-terminal/ffi.lisp already wraps cffi:use-foreign-library in ignore-errors, so platforms without libvterm or a C toolchain continue to work — they just don't get the terminal extension.
  • The main make sdl2 / make ncurses / make webview targets are unchanged, so this doesn't add a hard libvterm dependency to normal builds.
  • The committed .so binaries are not removed in this PR. Removing them can be done in a follow-up (or by reopening Remove binary files #1964) once CI is verified producing them.

Details

  • Honors CC, CFLAGS, LDFLAGS env vars for cross-distro / Nix / Guix friendliness.
  • Uses the Guix package's -lutil on Linux for forkpty; macOS uses Homebrew's -I/opt/homebrew/include -L/opt/homebrew/lib.
  • Falls back to deriving architecture from *features* when uiop:architecture returns NIL (older bundled UIOP on Apple Silicon).
  • Surfaces a clear error and exits non-zero if compilation fails, so it's safe to wire into CI later.

Test plan

  • make terminal-lib on macOS arm64 (Homebrew libvterm) produces a working extensions/terminal/lib/macosx/arm64/terminal.so (byte-identical size to the committed one).
  • make terminal-lib on Linux x64 with libvterm + libutil.
  • make terminal-lib on a host without libvterm — exits non-zero with the install hint, does not corrupt the tree.
  • make sdl2 / make ncurses / make webview still build without touching the terminal helper.
  • Verify lem-terminal loads the freshly-built .so at runtime by opening a *terminal* buffer.

Refs #1964, #2060.

Adds scripts/build-terminal.lisp and a `make terminal-lib` target that
compiles extensions/terminal/terminal.c into the platform-specific
extensions/terminal/lib/<os>/<arch>/terminal.so path that ffi.lisp
already expects at runtime.

This is the missing build path mentioned in lem-project#1964 and discussion lem-project#2060
so the prebuilt .so binaries can eventually be removed from version
control without breaking source installs.

The target is optional and standalone: lem-terminal already wraps its
foreign-library load in ignore-errors, so platforms without libvterm
or a C toolchain continue to work, just without the terminal extension.

Respects CC / CFLAGS / LDFLAGS env vars and falls back to deriving
architecture from *features* when uiop:architecture returns NIL (older
bundled UIOP on Apple Silicon).
@theangelperalta theangelperalta requested a review from vindarel May 15, 2026 00:08
@vindarel
Copy link
Copy Markdown
Collaborator

Do you know the minimal libvterm version?

On an old-ish Debian, libvterm-dev 0.1.4-1 may be too old:

Building lem-terminal native helper:
  cc  /home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c -lvterm -lutil  -o /home/vince/bacasable/lisp-projects/lem/extensions/terminal/lib/linux/x64/terminal.so -shared -fPIC
/home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c: In function ‘terminal_last_cell_attrs_conceal’:
/home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c:440:34: error: ‘VTermScreenCellAttrs’ has no member named ‘conceal’
  440 |   return terminal->lastCell.attrs.conceal;

@theangelperalta
Copy link
Copy Markdown
Collaborator Author

theangelperalta commented May 16, 2026

Do you know the minimal libvterm version?

On an old-ish Debian, libvterm-dev 0.1.4-1 may be too old:

Building lem-terminal native helper:
  cc  /home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c -lvterm -lutil  -o /home/vince/bacasable/lisp-projects/lem/extensions/terminal/lib/linux/x64/terminal.so -shared -fPIC
/home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c: In function ‘terminal_last_cell_attrs_conceal’:
/home/vince/bacasable/lisp-projects/lem/extensions/terminal/terminal.c:440:34: error: ‘VTermScreenCellAttrs’ has no member named ‘conceal’
  440 |   return terminal->lastCell.attrs.conceal;

It seems like that version from 2020, can you try updating to at least 3.x @vindarel

@theangelperalta theangelperalta merged commit 803e492 into lem-project:main May 30, 2026
10 checks passed
theangelperalta added a commit that referenced this pull request Jun 3, 2026
)

* chore(terminal): remove committed terminal.so binaries, build from source

Removes the three prebuilt terminal.so shared objects from version control
and replaces them with a from-source build path, addressing #1964 ("Open
source software should, by definition, not be distributing binary files").

The build script and `make terminal-lib` target landed in #2182; this wires
them into the editor build and removes the binaries:

- git rm the linux/arm64, linux/x64 and macosx/arm64 terminal.so files.
- Invoke `terminal-lib` best-effort (`-$(MAKE) terminal-lib`) from the
  ncurses, sdl2, sdl2-ncurses, webview and webview-ncurses targets so source
  installs still get a terminal. A missing libvterm/compiler is non-fatal:
  lem-terminal/ffi.lisp already wraps use-foreign-library in ignore-errors
  and silently disables itself when the library is absent.
- gitignore extensions/terminal/lib/**/*.so so locally-built helpers are
  never re-committed.
- Convert .github/workflows/build-terminal-shared-object.yml from a workflow
  that recompiled and re-committed terminal.so on every push (which would
  reintroduce exactly the binaries this removes) into a verify-only CI check
  that builds terminal.so from source on Linux and macOS and fails if the
  build breaks.

Refs #1964, #2060, #2182.

* chore(terminal): exit explicitly and verify artifact in build script

build-terminal.lisp dropped into the SBCL REPL after a successful build
(exiting only on stdin EOF) and trusted the compiler's exit code without
checking that terminal.so was actually written.

- Quit 0 after a successful build so `sbcl --load` never blocks on stdin.
- Delete any stale .so before compiling, then assert the artifact exists
  afterwards, so a compiler that exits 0 without producing the file is
  treated as a failure instead of a silent no-op.
- Factor the failure path into build-failed (stderr + exit 1).

* chore(terminal): bundle static terminal.so into release artifacts

Release bundles (Linux AppImage, macOS zip) never shipped or loaded
terminal.so: ffi.lisp resolves it from the build machine's source tree via
asdf:system-relative-pathname, and the macOS deploy library only bundles a
foreign library that is loaded at build time -- which failed because the CI
runner lacked libvterm. Even when bundled, a dynamic terminal.so referenced
Homebrew's libvterm by absolute path and would break on a clean machine.

Build a self-contained terminal.so with libvterm statically linked for
releases, so the deploy library (macOS) and LD_LIBRARY_PATH=usr/lib
(AppImage) can load it with no external libvterm dependency.

- build-terminal.lisp: add LEM_TERMINAL_STATIC mode. macOS links
  libvterm.a directly (prefix via LIBVTERM_PREFIX / brew --prefix); Linux
  wraps -lvterm in -Wl,-Bstatic. Default stays dynamic for source installs.
- macos-deploy.bash + nightly-builds.yml: install libvterm and build the
  static helper before asdf:make so deploy bundles it; assert it landed in
  the .app.
- Dockerfile-AppImage: install libvterm-dev and build the static helper
  before asdf:make; make_appdir.sh asserts terminal.so reached usr/lib.

No ffi.lisp/core changes: deploy + LD_LIBRARY_PATH handle runtime resolution
once a self-contained .so is bundled.

Refs #1964, #2060.
theangelperalta added a commit that referenced this pull request Jun 3, 2026
…urce (#2204)

* chore(terminal): remove committed terminal.so binaries, build from source

Removes the three prebuilt terminal.so shared objects from version control
and replaces them with a from-source build path, addressing #1964 ("Open
source software should, by definition, not be distributing binary files").

The build script and `make terminal-lib` target landed in #2182; this wires
them into the editor build and removes the binaries:

- git rm the linux/arm64, linux/x64 and macosx/arm64 terminal.so files.
- Invoke `terminal-lib` best-effort (`-$(MAKE) terminal-lib`) from the
  ncurses, sdl2, sdl2-ncurses, webview and webview-ncurses targets so source
  installs still get a terminal. A missing libvterm/compiler is non-fatal:
  lem-terminal/ffi.lisp already wraps use-foreign-library in ignore-errors
  and silently disables itself when the library is absent.
- gitignore extensions/terminal/lib/**/*.so so locally-built helpers are
  never re-committed.
- Convert .github/workflows/build-terminal-shared-object.yml from a workflow
  that recompiled and re-committed terminal.so on every push (which would
  reintroduce exactly the binaries this removes) into a verify-only CI check
  that builds terminal.so from source on Linux and macOS and fails if the
  build breaks.

Refs #1964, #2060, #2182.

* chore(terminal): exit explicitly and verify artifact in build script

build-terminal.lisp dropped into the SBCL REPL after a successful build
(exiting only on stdin EOF) and trusted the compiler's exit code without
checking that terminal.so was actually written.

- Quit 0 after a successful build so `sbcl --load` never blocks on stdin.
- Delete any stale .so before compiling, then assert the artifact exists
  afterwards, so a compiler that exits 0 without producing the file is
  treated as a failure instead of a silent no-op.
- Factor the failure path into build-failed (stderr + exit 1).
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