build: replace lib-vt step with -Demit-lib-vt option

Remove the dedicated `zig build lib-vt` step and replace it with a
`-Demit-lib-vt` build option. This fixes two problems:

1. We can default XCFramework, app, etc. steps to false if emit-lib-vt
   is true, so that the lib-vt build doesn't pull in unrelated
   artifacts. **Most importantly, lib-vt alone can be build without
   full Xcode installations.**

2. We can build lib-vt as part of a bundle with other artifacts if we
   really want.
pull/11716/head
Mitchell Hashimoto 2026-03-20 20:59:27 -07:00
parent e8fb7eabad
commit 3fc04fd4ae
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
9 changed files with 43 additions and 40 deletions

View File

@ -408,11 +408,11 @@ jobs:
- name: Build - name: Build
run: | run: |
nix develop -c zig build lib-vt \ nix develop -c zig build -Demit-lib-vt \
-Dtarget=${{ matrix.target }} \ -Dtarget=${{ matrix.target }} \
-Dsimd=false -Dsimd=false
# lib-vt requires macOS runner for macOS/iOS builds becauase it requires the `apple_sdk` path # lib-vt requires macOS runner for macOS/iOS builds because it requires the `apple_sdk` path
build-libghostty-vt-macos: build-libghostty-vt-macos:
strategy: strategy:
matrix: matrix:
@ -448,7 +448,7 @@ jobs:
- name: Build - name: Build
run: | run: |
nix develop -c zig build lib-vt \ nix develop -c zig build -Demit-lib-vt \
-Dtarget=${{ matrix.target }} -Dtarget=${{ matrix.target }}
# lib-vt requires the Android NDK for Android builds # lib-vt requires the Android NDK for Android builds
@ -494,7 +494,7 @@ jobs:
- name: Build - name: Build
run: | run: |
nix develop -c zig build lib-vt \ nix develop -c zig build -Demit-lib-vt \
-Dtarget=${{ matrix.target }} -Dtarget=${{ matrix.target }}
env: env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}

View File

@ -1,6 +1,6 @@
# CMake wrapper for libghostty-vt # CMake wrapper for libghostty-vt
# #
# This file delegates to `zig build lib-vt` to produce the shared library, # This file delegates to `zig build -Demit-lib-vt` to produce the shared library,
# headers, and pkg-config file. It exists so that CMake-based projects can # headers, and pkg-config file. It exists so that CMake-based projects can
# consume libghostty-vt without interacting with the Zig build system # consume libghostty-vt without interacting with the Zig build system
# directly. However, downstream users do still require `zig` on the PATH. # directly. However, downstream users do still require `zig` on the PATH.
@ -91,10 +91,10 @@ set(GHOSTTY_VT_LIBRARY "${ZIG_OUT_DIR}/lib/${GHOSTTY_VT_REALNAME}")
# INTERFACE_INCLUDE_DIRECTORIES before the zig build has run. # INTERFACE_INCLUDE_DIRECTORIES before the zig build has run.
file(MAKE_DIRECTORY "${ZIG_OUT_DIR}/include") file(MAKE_DIRECTORY "${ZIG_OUT_DIR}/include")
# Custom command: run zig build lib-vt # Custom command: run zig build -Demit-lib-vt
add_custom_command( add_custom_command(
OUTPUT "${GHOSTTY_VT_LIBRARY}" OUTPUT "${GHOSTTY_VT_LIBRARY}"
COMMAND "${ZIG_EXECUTABLE}" build lib-vt ${GHOSTTY_ZIG_BUILD_FLAGS} COMMAND "${ZIG_EXECUTABLE}" build -Demit-lib-vt ${GHOSTTY_ZIG_BUILD_FLAGS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "Building libghostty-vt via zig build..." COMMENT "Building libghostty-vt via zig build..."
USES_TERMINAL USES_TERMINAL

View File

@ -35,7 +35,6 @@ pub fn build(b: *std.Build) !void {
// All our steps which we'll hook up later. The steps are shown // All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting. // up here just so that they are more self-documenting.
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
const run_valgrind_step = b.step( const run_valgrind_step = b.step(
"run-valgrind", "run-valgrind",
@ -91,16 +90,6 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step); check_step.dependOn(dist.install_step);
} }
// libghostty (internal, big)
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
b,
&deps,
);
const libghostty_static = try buildpkg.GhosttyLib.initStatic(
b,
&deps,
);
// libghostty-vt // libghostty-vt
const libghostty_vt_shared = shared: { const libghostty_vt_shared = shared: {
if (config.target.result.cpu.arch.isWasm()) { if (config.target.result.cpu.arch.isWasm()) {
@ -115,7 +104,6 @@ pub fn build(b: *std.Build) !void {
&mod, &mod,
); );
}; };
libghostty_vt_shared.install(libvt_step);
libghostty_vt_shared.install(b.getInstallStep()); libghostty_vt_shared.install(b.getInstallStep());
// Helpgen // Helpgen
@ -128,26 +116,29 @@ pub fn build(b: *std.Build) !void {
resources.install(); resources.install();
if (i18n) |v| v.install(); if (i18n) |v| v.install();
} }
} else { } else if (!config.emit_lib_vt) {
// Libghostty // The macOS Ghostty Library
// //
// Note: libghostty is not stable for general purpose use. It is used // This is NOT libghostty (even though its named that for historical
// heavily by Ghostty on macOS but it isn't built to be reusable yet. // reasons). It is just the glue between Ghostty GUI on macOS and
// As such, these build steps are lacking. For example, the Darwin // the full Ghostty GUI core.
// build only produces an xcframework. const lib_shared = try buildpkg.GhosttyLib.initShared(b, &deps);
const lib_static = try buildpkg.GhosttyLib.initStatic(b, &deps);
// We shouldn't have this guard but we don't currently // We shouldn't have this guard but we don't currently
// build on macOS this way ironically so we need to fix that. // build on macOS this way ironically so we need to fix that.
if (!config.target.result.os.tag.isDarwin()) { if (!config.target.result.os.tag.isDarwin()) {
libghostty_shared.installHeader(); // Only need one header lib_shared.installHeader(); // Only need one header
libghostty_shared.install("libghostty.so"); lib_shared.install("libghostty.so");
libghostty_static.install("libghostty.a"); lib_static.install("libghostty.a");
} }
} }
// macOS only artifacts. These will error if they're initialized for // macOS only artifacts. These will error if they're initialized for
// other targets. // other targets.
if (config.target.result.os.tag.isDarwin()) { if (config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
// Ghostty xcframework // Ghostty xcframework
const xcframework = try buildpkg.GhosttyXCFramework.init( const xcframework = try buildpkg.GhosttyXCFramework.init(
b, b,
@ -202,7 +193,9 @@ pub fn build(b: *std.Build) !void {
// On macOS we can run the macOS app. For "run" we always force // On macOS we can run the macOS app. For "run" we always force
// a native-only build so that we can run as quickly as possible. // a native-only build so that we can run as quickly as possible.
if (config.target.result.os.tag.isDarwin()) { if (config.target.result.os.tag.isDarwin() and
(config.emit_xcframework or config.emit_macos_app))
{
const xcframework_native = try buildpkg.GhosttyXCFramework.init( const xcframework_native = try buildpkg.GhosttyXCFramework.init(
b, b,
&deps, &deps,

View File

@ -2,7 +2,7 @@
The top-level `CMakeLists.txt` wraps the Zig build system so that CMake The top-level `CMakeLists.txt` wraps the Zig build system so that CMake
projects can consume libghostty-vt without invoking `zig build` manually. projects can consume libghostty-vt without invoking `zig build` manually.
Running `cmake --build` triggers `zig build lib-vt` automatically. Running `cmake --build` triggers `zig build -Demit-lib-vt` automatically.
This means downstream projects do require a working Zig compiler on This means downstream projects do require a working Zig compiler on
`PATH` to build, but don't need to know any Zig-specific details. `PATH` to build, but don't need to know any Zig-specific details.

View File

@ -8,7 +8,7 @@ to encode key events into terminal escape sequences.
First, build the WebAssembly module: First, build the WebAssembly module:
```bash ```bash
zig build lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
``` ```
This will create `zig-out/bin/ghostty-vt.wasm`. This will create `zig-out/bin/ghostty-vt.wasm`.

View File

@ -9,7 +9,7 @@ styling attributes.
First, build the WebAssembly module: First, build the WebAssembly module:
```bash ```bash
zig build lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall zig build -Demit-lib-vt -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
``` ```
This will create `zig-out/bin/ghostty-vt.wasm`. This will create `zig-out/bin/ghostty-vt.wasm`.

View File

@ -51,6 +51,7 @@ emit_bench: bool = false,
emit_docs: bool = false, emit_docs: bool = false,
emit_exe: bool = false, emit_exe: bool = false,
emit_helpgen: bool = false, emit_helpgen: bool = false,
emit_lib_vt: bool = false,
emit_macos_app: bool = false, emit_macos_app: bool = false,
emit_terminfo: bool = false, emit_terminfo: bool = false,
emit_termcap: bool = false, emit_termcap: bool = false,
@ -314,11 +315,17 @@ pub fn init(b: *std.Build, appVersion: []const u8) !Config {
//--------------------------------------------------------------- //---------------------------------------------------------------
// Artifacts to Emit // Artifacts to Emit
config.emit_lib_vt = b.option(
bool,
"emit-lib-vt",
"Set defaults for a libghostty-vt-only build (disables xcframework, macOS app, and docs).",
) orelse false;
config.emit_exe = b.option( config.emit_exe = b.option(
bool, bool,
"emit-exe", "emit-exe",
"Build and install main executables with 'build'", "Build and install main executables with 'build'",
) orelse true; ) orelse !config.emit_lib_vt;
config.emit_test_exe = b.option( config.emit_test_exe = b.option(
bool, bool,
@ -352,7 +359,8 @@ pub fn init(b: *std.Build, appVersion: []const u8) !Config {
// If we are emitting any other artifacts then we default to false. // If we are emitting any other artifacts then we default to false.
if (config.emit_bench or if (config.emit_bench or
config.emit_test_exe or config.emit_test_exe or
config.emit_helpgen) break :emit_docs false; config.emit_helpgen or
config.emit_lib_vt) break :emit_docs false;
// We always emit docs in system package mode. // We always emit docs in system package mode.
if (system_package) break :emit_docs true; if (system_package) break :emit_docs true;
@ -401,7 +409,8 @@ pub fn init(b: *std.Build, appVersion: []const u8) !Config {
bool, bool,
"emit-xcframework", "emit-xcframework",
"Build and install the xcframework for the macOS library.", "Build and install the xcframework for the macOS library.",
) orelse builtin.target.os.tag.isDarwin() and ) orelse !config.emit_lib_vt and
builtin.target.os.tag.isDarwin() and
target.result.os.tag == .macos and target.result.os.tag == .macos and
config.app_runtime == .none and config.app_runtime == .none and
(!config.emit_bench and (!config.emit_bench and
@ -412,7 +421,7 @@ pub fn init(b: *std.Build, appVersion: []const u8) !Config {
bool, bool,
"emit-macos-app", "emit-macos-app",
"Build and install the macOS app bundle.", "Build and install the macOS app bundle.",
) orelse config.emit_xcframework; ) orelse !config.emit_lib_vt and config.emit_xcframework;
//--------------------------------------------------------------- //---------------------------------------------------------------
// System Packages // System Packages

View File

@ -29,8 +29,9 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
// Set PIE if requested // Set PIE if requested
if (cfg.pie) exe.pie = true; if (cfg.pie) exe.pie = true;
// Add the shared dependencies // Add the shared dependencies. When building only lib-vt we skip
_ = try deps.add(exe); // heavy deps so cross-compilation doesn't pull in GTK, etc.
if (!cfg.emit_lib_vt) _ = try deps.add(exe);
// Check for possible issues // Check for possible issues
try checkNixShell(exe, cfg); try checkNixShell(exe, cfg);

View File

@ -121,7 +121,7 @@ pub fn add(
// We don't support cross-compiling to Darwin but due to the way // We don't support cross-compiling to Darwin but due to the way
// lazy dependencies work with Zig, we call this function. So we just // lazy dependencies work with Zig, we call this function. So we just
// bail. The build will fail but the build would've failed anyways. // bail. The build will fail but the build would've failed anyways.
// And this lets other non-platform-specific targets like `lib-vt` // And this lets other non-platform-specific targets like `-Demit-lib-vt`
// cross-compile properly. // cross-compile properly.
if (!builtin.target.os.tag.isDarwin() and if (!builtin.target.os.tag.isDarwin() and
self.config.target.result.os.tag.isDarwin()) self.config.target.result.os.tag.isDarwin())