aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/build
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-09-10 21:51:57 +0300
committerGitHub <noreply@github.com>2026-09-10 21:51:57 +0300
commit425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch)
treee52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/build
parent90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff)
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/build')
-rw-r--r--vendor/libghostty-vt/src/build/Config.zig251
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyBench.zig4
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyDist.zig4
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyDocs.zig6
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyExe.zig17
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyFrameData.zig8
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyI18n.zig21
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyLib.zig38
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyLibVt.zig217
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyResources.zig30
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyWebdata.zig6
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyXCFramework.zig39
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyXcodebuild.zig10
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyZig.zig18
-rw-r--r--vendor/libghostty-vt/src/build/GitVersion.zig14
-rw-r--r--vendor/libghostty-vt/src/build/HelpStrings.zig2
-rw-r--r--vendor/libghostty-vt/src/build/LibsystemOverrideStep.zig51
-rw-r--r--vendor/libghostty-vt/src/build/MetallibStep.zig11
-rw-r--r--vendor/libghostty-vt/src/build/SharedDeps.zig299
-rw-r--r--vendor/libghostty-vt/src/build/UnicodeTables.zig4
-rw-r--r--vendor/libghostty-vt/src/build/XCFrameworkStep.zig4
-rw-r--r--vendor/libghostty-vt/src/build/combine_archives.zig28
-rw-r--r--vendor/libghostty-vt/src/build/docker/lib-c-docs/Dockerfile1
-rw-r--r--vendor/libghostty-vt/src/build/gtk.zig2
-rwxr-xr-xvendor/libghostty-vt/src/build/libsystem_override.sh123
-rw-r--r--vendor/libghostty-vt/src/build/mdgen/main_ghostty_1.zig7
-rw-r--r--vendor/libghostty-vt/src/build/mdgen/main_ghostty_5.zig7
-rw-r--r--vendor/libghostty-vt/src/build/uucode_config.zig227
-rw-r--r--vendor/libghostty-vt/src/build/wasm_patch_growable_table.zig21
-rw-r--r--vendor/libghostty-vt/src/build/webgen/main_actions.zig4
-rw-r--r--vendor/libghostty-vt/src/build/webgen/main_commands.zig4
-rw-r--r--vendor/libghostty-vt/src/build/webgen/main_config.zig4
32 files changed, 1092 insertions, 390 deletions
diff --git a/vendor/libghostty-vt/src/build/Config.zig b/vendor/libghostty-vt/src/build/Config.zig
index 0a994731..71fa4d28 100644
--- a/vendor/libghostty-vt/src/build/Config.zig
+++ b/vendor/libghostty-vt/src/build/Config.zig
@@ -43,7 +43,7 @@ lib_version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 },
/// Binary properties
pie: bool = false,
strip: bool = false,
-patch_rpath: ?[]const u8 = null,
+patchelf: ?PatchElf = null,
/// Artifacts
flatpak: bool = false,
@@ -62,17 +62,30 @@ emit_xcframework: bool = false,
emit_webdata: bool = false,
emit_unicode_table_gen: bool = false,
+/// Feature gates for libghostty-vt artifacts (-Dvt-features). The full
+/// Ghostty application ignores this and always enables everything.
+vt_features: TerminalBuildOptions.Features = .{},
+
/// True when Ghostty is being built as a dependency of another project
/// rather than as the root project.
is_dep: bool = false,
/// Environmental properties
-env: std.process.EnvMap,
+env: *const std.process.Environ.Map,
pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Config {
// Setup our standard Zig target and optimize options, i.e.
// `-Doptimize` and `-Dtarget`.
const optimize = b.standardOptimizeOption(.{});
+
+ // Default dependency builds to libghostty-vt-only mode. Consumers can
+ // still explicitly disable this to request the full Ghostty build.
+ const is_dep = b.dep_prefix.len > 0;
+ const emit_lib_vt = b.option(
+ bool,
+ "emit-lib-vt",
+ "Set defaults for a libghostty-vt-only build (disables xcframework, macOS app, and docs).",
+ ) orelse is_dep;
const target = target: {
var result = b.standardTargetOptions(.{});
@@ -97,19 +110,48 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
result = b.resolveTargetQuery(query);
}
+ // On wasm, default to enabling the simd128 feature. Every
+ // browser engine has supported it since 2023 or earlier
+ // (Chrome 91, Firefox 89, Safari 16.4) and it is a large
+ // performance win for the terminal hot paths (50%+ on
+ // print-heavy VT streams). Only apply when no explicit CPU
+ // was requested; targets for exotic non-browser runtimes
+ // can opt out with `-Dcpu=generic`.
+ if (result.result.cpu.arch.isWasm() and
+ result.query.cpu_model == .determined_by_arch_os and
+ result.query.cpu_features_add.isEmpty() and
+ result.query.cpu_features_sub.isEmpty())
+ {
+ var query = result.query;
+ query.cpu_features_add.addFeature(
+ @intFromEnum(std.Target.wasm.Feature.simd128),
+ );
+ result = b.resolveTargetQuery(query);
+ }
+
+ // The full Ghostty build no longer supports iOS; Fail early
+ // with a clear message rather than partway through the build.
+ if (result.result.os.tag == .ios and !emit_lib_vt) {
+ std.log.err(
+ "iOS is not a supported target for the full Ghostty build; " ++
+ "only libghostty-vt supports iOS (-Demit-lib-vt)",
+ .{},
+ );
+ return error.UnsupportedTarget;
+ }
+
// If we have no minimum OS version, we set the default based on
// our tag. Not all tags have a minimum so this may be null.
if (result.query.os_version_min == null) {
- result.query.os_version_min = osVersionMin(result.result.os.tag);
+ result.query.os_version_min = if (emit_lib_vt)
+ osVersionMinLibVt(result.result.os.tag)
+ else
+ osVersionMin(result.result.os.tag);
}
break :target result;
};
- // Detect if Ghostty is a dependency of another project.
- // dep_prefix is non-empty when this build is running as a dependency.
- const is_dep = b.dep_prefix.len > 0;
-
// This is set to true when we're building a system package. For now
// this is trivially detected using the "system_package_mode" bool
// but we may want to make this more sophisticated in the future.
@@ -124,10 +166,10 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
// defaults.
const gtk_targets = gtk.targets(b);
- // We use env vars throughout the build so we grab them immediately here.
- var env = try std.process.getEnvMap(b.allocator);
- errdefer env.deinit();
+ // Grab the environment from build state
+ const env = &b.graph.environ_map;
+ // We use env vars throughout the build so we grab them immediately here.
var config: Config = .{
.optimize = optimize,
.target = target,
@@ -198,9 +240,10 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
"simd",
"Build with SIMD-accelerated code paths. Results in significant performance improvements.",
) orelse simd: {
- // We can't build our SIMD dependencies for Wasm. Note that we may
- // still use SIMD features in the Wasm-builds.
- if (target.result.cpu.arch.isWasm()) break :simd false;
+ // We can't build our SIMD dependencies for Wasm or freestanding
+ // targets. Note that we may still use SIMD features in the Wasm-builds.
+ if (target.result.cpu.arch.isWasm() or
+ target.result.os.tag == .freestanding) break :simd false;
break :simd true;
};
@@ -312,24 +355,55 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
//---------------------------------------------------------------
// Binary Properties
- // On NixOS, the built binary from `zig build` needs to patch the rpath
- // into the built binary for it to be portable across the NixOS system
- // it was built for. We default this to true if we can detect we're in
- // a Nix shell and have LD_LIBRARY_PATH set.
- config.patch_rpath = b.option(
+ // On NixOS, the built binary from `zig build` needs to patch the interp
+ // and rpath into the built binary for it to be portable across the NixOS
+ // system it was built for. We default this to true if we can detect we're
+ // in a Nix shell.
+ //
+ // Note that this option is only available on Linux and if building
+ // natively.
+ //
+ // NOTE: Zig does now have an option to pass in the dynamic linker
+ // (-Ddynamic-linker), but it does seem to have some issues in 0.16.0 that
+ // may be fixed in 0.17.0. We may want to revisit this afterwards; although
+ // I'm not too sure if that helps to clean up rpath, this may just be the
+ // better option. See https://codeberg.org/ziglang/zig/issues/31760.
+ if (b.option(
+ []const u8,
+ "patch-interp",
+ "Inject the supplied path as the dynamic linker in the built binary. " ++
+ "Under Nix, this defaults to the dynamic linker found in PATH.",
+ )) |interp| {
+ PatchElf.setInterp(&config, interp);
+ } else patch_interp: {
+ if (!(target.result.os.tag == .linux) or !target.query.isNativeCpu()) break :patch_interp;
+ if (env.get("IN_NIX_SHELL") == null) break :patch_interp;
+
+ if (b.findProgram(&.{"ld.so"}, &.{})) |ld_so| {
+ PatchElf.setInterp(
+ &config,
+ std.Io.Dir.realPathFileAbsoluteAlloc(b.graph.io, ld_so, b.allocator) catch break :patch_interp,
+ );
+ } else |_| {}
+ }
+
+ if (b.option(
[]const u8,
"patch-rpath",
- "Inject the LD_LIBRARY_PATH as the rpath in the built binary. " ++
- "This defaults to LD_LIBRARY_PATH if we're in a Nix shell environment on NixOS.",
- ) orelse patch_rpath: {
- // We only do the patching if we're targeting our own CPU and its Linux.
- if (!(target.result.os.tag == .linux) or !target.query.isNativeCpu()) break :patch_rpath null;
-
- // If we're in a nix shell we default to doing this.
- // Note: we purposely never deinit envmap because we leak the strings
- if (env.get("IN_NIX_SHELL") == null) break :patch_rpath null;
- break :patch_rpath env.get("LD_LIBRARY_PATH");
- };
+ "Inject the supplied colon-delimited search path as the rpath in the built binary. " ++
+ "This defaults to LD_LIBRARY_PATH if we're in a Nix shell environment.",
+ )) |rpath| {
+ PatchElf.setRpath(&config, rpath);
+ } else patch_rpath: {
+ if (!(target.result.os.tag == .linux) or !target.query.isNativeCpu()) break :patch_rpath;
+ if (env.get("IN_NIX_SHELL") == null) break :patch_rpath;
+
+ if (env.get("LD_LIBRARY_PATH")) |ld_library_path| {
+ if (ld_library_path.len > 0) {
+ PatchElf.setRpath(&config, ld_library_path);
+ }
+ }
+ }
config.pie = b.option(
bool,
@@ -350,11 +424,31 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
//---------------------------------------------------------------
// 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_lib_vt = emit_lib_vt;
+
+ config.vt_features = features: {
+ const list = b.option(
+ []const u8,
+ "vt-features",
+ "Comma-separated libghostty-vt feature modifications applied " ++
+ "to the default all-enabled set, -Dcpu style: `+feature` " ++
+ "or `feature` enables, `-feature` disables, and `all` " ++
+ "means every feature (e.g. `-all,+render-state` for a " ++
+ "render-only build). Only applies to lib artifacts.",
+ ) orelse break :features .{};
+ break :features TerminalBuildOptions.Features.parse(list) catch {
+ var valid: std.ArrayList(u8) = .empty;
+ inline for (@typeInfo(TerminalBuildOptions.Features).@"struct".fields) |field| {
+ if (valid.items.len > 0) try valid.appendSlice(b.allocator, ", ");
+ try valid.appendSlice(b.allocator, field.name);
+ }
+ std.log.err(
+ "-Dvt-features={s} contains an unknown feature. Valid features: all, {s}",
+ .{ list, valid.items },
+ );
+ return error.UnknownVtFeature;
+ };
+ };
config.emit_exe = b.option(
bool,
@@ -401,7 +495,7 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
if (system_package) break :emit_docs true;
// We only default to true if we can find pandoc.
- const path = expandPath(b.allocator, "pandoc") catch
+ const path = expandPath(b.graph.io, b.allocator, &b.graph.environ_map, "pandoc") catch
break :emit_docs false;
defer if (path) |p| b.allocator.free(p);
break :emit_docs path != null;
@@ -450,7 +544,7 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
if (config.emit_lib_vt) {
// In lib-vt mode default to whether xcodebuild is available,
// since xcodebuild is required to produce the XCFramework.
- const path = expandPath(b.allocator, "xcodebuild") catch
+ const path = expandPath(b.graph.io, b.allocator, &b.graph.environ_map, "xcodebuild") catch
break :emit_xcfw false;
defer if (path) |p| b.allocator.free(p);
break :emit_xcfw path != null;
@@ -522,6 +616,45 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
return config;
}
+const PatchElf = struct {
+ interp: ?[]const u8 = null,
+ rpath: ?[]const u8 = null,
+
+ fn setInterp(config: *Config, interp: []const u8) void {
+ if (config.patchelf) |*patchelf| {
+ patchelf.interp = interp;
+ return;
+ }
+
+ config.patchelf = .{ .interp = interp };
+ }
+
+ fn setRpath(config: *Config, rpath: []const u8) void {
+ if (config.patchelf) |*patchelf| {
+ patchelf.rpath = rpath;
+ return;
+ }
+
+ config.patchelf = .{ .rpath = rpath };
+ }
+};
+
+/// Add a patchelf step for the supplied `artifact`, depending on the supplied
+/// `step`, if `patchelf` is present in the config.
+pub fn addPatchElf(self: *const Config, artifact: *std.Build.Step.Compile, step: *std.Build.Step) void {
+ const b = artifact.step.owner;
+ std.debug.assert(b == step.owner);
+
+ if (self.patchelf) |patchelf| {
+ const run = std.Build.Step.Run.create(b, "patchelf");
+ run.addArgs(&.{"patchelf"});
+ if (patchelf.interp) |interp| run.addArgs(&.{ "--set-interpreter", interp });
+ if (patchelf.rpath) |rpath| run.addArgs(&.{ "--set-rpath", rpath });
+ run.addArtifactArg(artifact);
+ step.dependOn(&run.step);
+ }
+}
+
/// Configure the build options with our values.
pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
// We need to break these down individual because addOption doesn't
@@ -570,17 +703,27 @@ pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
/// Returns the build options for the terminal module. This assumes a
/// Ghostty executable being built. Callers should modify this as needed.
-pub fn terminalOptions(self: *const Config, artifact: TerminalBuildOptions.Artifact) TerminalBuildOptions {
+pub fn terminalOptions(
+ self: *const Config,
+ artifact: TerminalBuildOptions.Artifact,
+ optimize: std.builtin.OptimizeMode,
+) TerminalBuildOptions {
return .{
.artifact = artifact,
.simd = self.simd,
.oniguruma = true,
.c_abi = false,
+ // The application requires every feature; only lib artifacts
+ // may trim them.
+ .features = switch (artifact) {
+ .ghostty => .{},
+ .lib => self.vt_features,
+ },
.version = switch (artifact) {
.ghostty => self.version,
.lib => self.lib_version,
},
- .slow_runtime_safety = switch (self.optimize) {
+ .slow_runtime_safety = switch (optimize) {
.Debug => true,
.ReleaseSafe,
.ReleaseSmall,
@@ -591,7 +734,7 @@ pub fn terminalOptions(self: *const Config, artifact: TerminalBuildOptions.Artif
}
/// Returns a baseline CPU target retaining all the other CPU configs.
-pub fn baselineTarget(self: *const Config) std.Build.ResolvedTarget {
+pub fn baselineTarget(self: *const Config, io: std.Io) std.Build.ResolvedTarget {
// Set our cpu model as baseline. There may need to be other modifications
// we need to make such as resetting CPU features but for now this works.
var q = self.target.query;
@@ -601,7 +744,7 @@ pub fn baselineTarget(self: *const Config) std.Build.ResolvedTarget {
// handle the native case.
return .{
.query = q,
- .result = std.zig.system.resolveTargetQuery(q) catch
+ .result = std.zig.system.resolveTargetQuery(io, q) catch
@panic("unable to resolve baseline query"),
};
}
@@ -630,6 +773,17 @@ pub fn fromOptions() Config {
};
}
+/// Whether release artifacts should omit frame pointers.
+///
+/// Stripped release builds omit them in general, but we always keep frame
+/// pointers on Apple platforms: the Apple arm64 ABI expects x29 to
+/// be a valid frame pointer and Apple's profiling and crash reporting
+/// tools rely on it for backtraces.
+pub fn omitFramePointer(self: *const Config) bool {
+ if (self.target.result.os.tag.isDarwin()) return false;
+ return self.strip;
+}
+
/// Returns the minimum OS version for the given OS tag. This shouldn't
/// be used generally, it should only be used for Darwin-based OS currently.
pub fn osVersionMin(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion {
@@ -642,19 +796,22 @@ pub fn osVersionMin(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion {
.patch = 0,
} },
- // iOS 17 picked arbitrarily
- .ios => .{ .semver = .{
- .major = 17,
- .minor = 0,
- .patch = 0,
- } },
-
// This should never happen currently. If we add a new target then
// we should add a new case here.
else => null,
};
}
+/// Returns the minimum OS version for lib-vt build.
+///
+/// This should only be used for Darwin targets.
+pub fn osVersionMinLibVt(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion {
+ // lib-vt is the only thing we still build for iOS, so its deployment
+ // target lives here rather than in osVersionMin.
+ if (tag == .ios) return .{ .semver = .{ .major = 13, .minor = 0, .patch = 0 } };
+ return osVersionMin(tag);
+}
+
// Returns a ResolvedTarget for a mac with a `target.result.cpu.model.name` of `generic`.
// `b.standardTargetOptions()` returns a more specific cpu like `apple_a15`.
//
diff --git a/vendor/libghostty-vt/src/build/GhosttyBench.zig b/vendor/libghostty-vt/src/build/GhosttyBench.zig
index 27dda880..fbf8029d 100644
--- a/vendor/libghostty-vt/src/build/GhosttyBench.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyBench.zig
@@ -23,9 +23,9 @@ pub fn init(
// We always want our datagen to be fast because it
// takes awhile to run.
.optimize = .ReleaseFast,
+ .link_libc = true,
}),
});
- exe.linkLibC();
_ = try deps.add(exe);
try steps.append(b.allocator, exe);
}
@@ -39,9 +39,9 @@ pub fn init(
.target = deps.config.target,
// We always want our benchmarks to be in release mode.
.optimize = .ReleaseFast,
+ .link_libc = true,
}),
});
- exe.linkLibC();
_ = try deps.add(exe);
try steps.append(b.allocator, exe);
}
diff --git a/vendor/libghostty-vt/src/build/GhosttyDist.zig b/vendor/libghostty-vt/src/build/GhosttyDist.zig
index 448047f4..fe8b863f 100644
--- a/vendor/libghostty-vt/src/build/GhosttyDist.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyDist.zig
@@ -237,11 +237,11 @@ pub const Resource = struct {
/// Returns true if the dist path exists at build time.
pub fn exists(self: *const Resource, b: *std.Build) bool {
- if (b.build_root.handle.access(self.dist, .{})) {
+ if (b.build_root.handle.access(b.graph.io, self.dist, .{})) {
// If we have a ".git" directory then we're a git checkout
// and we never want to use the dist path. This shouldn't happen
// so show a warning to the user.
- if (b.build_root.handle.access(".git", .{})) {
+ if (b.build_root.handle.access(b.graph.io, ".git", .{})) {
std.log.warn(
"dist resource '{s}' should not be in a git checkout",
.{self.dist},
diff --git a/vendor/libghostty-vt/src/build/GhosttyDocs.zig b/vendor/libghostty-vt/src/build/GhosttyDocs.zig
index cd75fc06..2b207f23 100644
--- a/vendor/libghostty-vt/src/build/GhosttyDocs.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyDocs.zig
@@ -50,7 +50,7 @@ pub fn init(
generate_markdown.root_module.addOptions("build_options", generate_markdown_options);
const generate_markdown_step = b.addRunArtifact(generate_markdown);
- const markdown_output = generate_markdown_step.captureStdOut();
+ const markdown_output = generate_markdown_step.captureStdOut(.{});
try steps.append(b.allocator, &b.addInstallFile(
markdown_output,
@@ -68,7 +68,7 @@ pub fn init(
generate_html.addFileArg(markdown_output);
try steps.append(b.allocator, &b.addInstallFile(
- generate_html.captureStdOut(),
+ generate_html.captureStdOut(.{}),
"share/ghostty/doc/" ++ manpage.name ++ "." ++ manpage.section ++ ".html",
).step);
@@ -83,7 +83,7 @@ pub fn init(
generate_manpage.addFileArg(markdown_output);
try steps.append(b.allocator, &b.addInstallFile(
- generate_manpage.captureStdOut(),
+ generate_manpage.captureStdOut(.{}),
"share/man/man" ++ manpage.section ++ "/" ++ manpage.name ++ "." ++ manpage.section,
).step);
}
diff --git a/vendor/libghostty-vt/src/build/GhosttyExe.zig b/vendor/libghostty-vt/src/build/GhosttyExe.zig
index caa564bf..22f39b7b 100644
--- a/vendor/libghostty-vt/src/build/GhosttyExe.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyExe.zig
@@ -18,7 +18,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
.target = cfg.target,
.optimize = cfg.optimize,
.strip = cfg.strip,
- .omit_frame_pointer = cfg.strip,
+ .omit_frame_pointer = cfg.omitFramePointer(),
.unwind_tables = if (cfg.strip) .none else .sync,
}),
// Crashes on x86_64 self-hosted on 0.15.1
@@ -36,21 +36,14 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
// Check for possible issues
try checkNixShell(exe, cfg);
- // Patch our rpath if that option is specified.
- if (cfg.patch_rpath) |rpath| {
- if (rpath.len > 0) {
- const run = std.Build.Step.Run.create(b, "patchelf rpath");
- run.addArgs(&.{ "patchelf", "--set-rpath", rpath });
- run.addArtifactArg(exe);
- install_step.step.dependOn(&run.step);
- }
- }
+ // Add patchelf step if that option is specified.
+ cfg.addPatchElf(exe, &install_step.step);
// OS-specific
switch (cfg.target.result.os.tag) {
.windows => {
exe.subsystem = .Windows;
- exe.addWin32ResourceFile(.{
+ exe.root_module.addWin32ResourceFile(.{
.file = b.path("dist/windows/ghostty.rc"),
});
},
@@ -85,7 +78,7 @@ fn checkNixShell(exe: *std.Build.Step.Compile, cfg: *const Config) !void {
if (!cfg.target.query.isNativeOs()) return;
// Verify we're in NixOS
- std.fs.accessAbsolute("/etc/NIXOS", .{}) catch return;
+ std.Io.Dir.accessAbsolute(exe.step.owner.graph.io, "/etc/NIXOS", .{}) catch return;
// If we're in a nix shell, not a problem
if (cfg.env.get("IN_NIX_SHELL") != null) return;
diff --git a/vendor/libghostty-vt/src/build/GhosttyFrameData.zig b/vendor/libghostty-vt/src/build/GhosttyFrameData.zig
index 8469759f..be61f029 100644
--- a/vendor/libghostty-vt/src/build/GhosttyFrameData.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyFrameData.zig
@@ -40,16 +40,16 @@ pub fn distResources(b: *std.Build) struct {
.name = "framegen",
.root_module = b.createModule(.{
.target = b.graph.host,
+ .link_libc = true,
}),
});
- exe.addCSourceFile(.{
+ exe.root_module.addCSourceFile(.{
.file = b.path("src/build/framegen/main.c"),
.flags = &.{},
});
- exe.linkLibC();
if (b.systemIntegrationOption("zlib", .{})) {
- exe.linkSystemLibrary2("zlib", .{
+ exe.root_module.linkSystemLibrary("zlib", .{
.preferred_link_mode = .dynamic,
.search_strategy = .mode_first,
});
@@ -58,7 +58,7 @@ pub fn distResources(b: *std.Build) struct {
.target = b.graph.host,
.optimize = .ReleaseFast,
})) |zlib_dep| {
- exe.linkLibrary(zlib_dep.artifact("z"));
+ exe.root_module.linkLibrary(zlib_dep.artifact("z"));
}
}
diff --git a/vendor/libghostty-vt/src/build/GhosttyI18n.zig b/vendor/libghostty-vt/src/build/GhosttyI18n.zig
index 0874676c..eb6ee5ee 100644
--- a/vendor/libghostty-vt/src/build/GhosttyI18n.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyI18n.zig
@@ -26,7 +26,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
// so we need to remove it from `locale` to have a correct destination string.
// (/usr/local/share/locale/en_AU/LC_MESSAGES)
const target_locale = comptime if (builtin.target.os.tag == .freebsd)
- std.mem.trimRight(u8, locale, ".UTF-8")
+ std.mem.trimEnd(u8, locale, ".UTF-8")
else
locale;
@@ -34,7 +34,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
msgfmt.addFileArg(b.path("po/" ++ locale ++ ".po"));
try steps.append(b.allocator, &b.addInstallFile(
- msgfmt.captureStdOut(),
+ msgfmt.captureStdOut(.{}),
std.fmt.comptimePrint(
"share/locale/{s}/LC_MESSAGES/{s}.mo",
.{ target_locale, domain },
@@ -66,6 +66,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
"--language=C", // Silence the "unknown extension" errors
"--from-code=UTF-8",
"--keyword=_",
+ "--keyword=N_",
"--keyword=C_:1c,2",
});
@@ -103,14 +104,15 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
}
var gtk_dir = try b.build_root.handle.openDir(
+ b.graph.io,
"src/apprt/gtk",
.{ .iterate = true },
);
- defer gtk_dir.close();
+ defer gtk_dir.close(b.graph.io);
var walk = try gtk_dir.walk(b.allocator);
defer walk.deinit();
- while (try walk.next()) |src| {
+ while (try walk.next(b.graph.io)) |src| {
switch (src.kind) {
.file => if (!std.mem.endsWith(
u8,
@@ -147,6 +149,11 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
}
}
+ // For localization of command palette
+ const command_palette_path = "src/input/command.zig";
+ xgettext.addArg(command_palette_path);
+ xgettext.addFileInput(b.path(command_palette_path));
+
// Add support for localizing our `nautilus` integration
const xgettext_py = b.addSystemCommand(&.{
"xgettext",
@@ -178,15 +185,15 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
xgettext_merge.addFileArg(gtk_pot);
const usf = b.addUpdateSourceFiles();
usf.addCopyFileToSource(
- xgettext_merge.captureStdOut(),
+ xgettext_merge.captureStdOut(.{}),
"po/" ++ domain ++ ".pot",
);
inline for (locales) |locale| {
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--quiet", "--no-fuzzy-matching" });
msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po"));
- msgmerge.addFileArg(xgettext_merge.captureStdOut());
- usf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po");
+ msgmerge.addFileArg(xgettext_merge.captureStdOut(.{}));
+ usf.addCopyFileToSource(msgmerge.captureStdOut(.{}), "po/" ++ locale ++ ".po");
}
return &usf.step;
diff --git a/vendor/libghostty-vt/src/build/GhosttyLib.zig b/vendor/libghostty-vt/src/build/GhosttyLib.zig
index b762da8b..529bb282 100644
--- a/vendor/libghostty-vt/src/build/GhosttyLib.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyLib.zig
@@ -1,9 +1,11 @@
const GhosttyLib = @This();
const std = @import("std");
+const builtin = @import("builtin");
const RunStep = std.Build.Step.Run;
const CombineArchivesStep = @import("CombineArchivesStep.zig");
const Config = @import("Config.zig");
+const LibsystemOverrideStep = @import("LibsystemOverrideStep.zig");
const SharedDeps = @import("SharedDeps.zig");
const LipoStep = @import("LipoStep.zig");
@@ -27,14 +29,14 @@ pub fn initStatic(
.target = deps.config.target,
.optimize = deps.config.optimize,
.strip = deps.config.strip,
- .omit_frame_pointer = deps.config.strip,
+ .omit_frame_pointer = deps.config.omitFramePointer(),
.unwind_tables = if (deps.config.strip) .none else .sync,
+ .link_libc = true,
}),
// Fails on self-hosted x86_64 on macOS
.use_llvm = true,
});
- lib.linkLibC();
// These must be bundled since we're compiling into a static lib.
// Otherwise, you get undefined symbol errors.
@@ -57,9 +59,19 @@ pub fn initStatic(
const combined = CombineArchivesStep.create(b, deps.config.target, "ghostty-internal", lib_list.items);
combined.step.dependOn(&lib.step);
+ // On Darwin, prefer libSystem's libc/libm over the bundled
+ // compiler-rt for consumers of this archive. See
+ // libsystem_override.sh for details. This is a no-op elsewhere.
+ const override = LibsystemOverrideStep.create(
+ b,
+ deps.config.target,
+ combined.output,
+ "libghostty-internal.a",
+ );
+
return .{
- .step = combined.step,
- .output = combined.output,
+ .step = override.step orelse combined.step,
+ .output = override.output,
// Static libraries cannot have dSYMs because they aren't linked.
.dsym = null,
@@ -72,6 +84,14 @@ pub fn initShared(
b: *std.Build,
deps: *const SharedDeps,
) !GhosttyLib {
+ // For dynamic linking, we prefer dynamic linking and to search by
+ // mode first. Mode first will search all paths for a dynamic library
+ // before falling back to static.
+ const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
+ .preferred_link_mode = .dynamic,
+ .search_strategy = .mode_first,
+ };
+
const lib = b.addLibrary(.{
.name = "ghostty",
.linkage = .dynamic,
@@ -80,7 +100,7 @@ pub fn initShared(
.target = deps.config.target,
.optimize = deps.config.optimize,
.strip = deps.config.strip,
- .omit_frame_pointer = deps.config.strip,
+ .omit_frame_pointer = deps.config.omitFramePointer(),
.unwind_tables = if (deps.config.strip) .none else .sync,
}),
@@ -99,12 +119,12 @@ pub fn initShared(
{
// The CRT initialization code in msvcrt.lib calls __vcrt_initialize
// and __acrt_initialize, which are in the static CRT libraries.
- lib.linkSystemLibrary("libvcruntime");
+ lib.root_module.linkSystemLibrary("libvcruntime", dynamic_link_opts);
// ucrt.lib is in the Windows SDK 'ucrt' dir. Detect the SDK
// installation and add the UCRT library path.
const arch = deps.config.target.result.cpu.arch;
- const sdk = std.zig.WindowsSdk.find(b.allocator, arch) catch null;
+ const sdk = std.zig.WindowsSdk.find(b.allocator, b.graph.io, arch, &b.graph.environ_map) catch null;
if (sdk) |s| {
if (s.windows10sdk) |w10| {
const arch_str: []const u8 = switch (arch) {
@@ -120,11 +140,11 @@ pub fn initShared(
) catch null;
if (ucrt_lib_path) |path| {
- lib.addLibraryPath(.{ .cwd_relative = path });
+ lib.root_module.addLibraryPath(.{ .cwd_relative = path });
}
}
}
- lib.linkSystemLibrary("libucrt");
+ lib.root_module.linkSystemLibrary("libucrt", dynamic_link_opts);
}
// Get our debug symbols
diff --git a/vendor/libghostty-vt/src/build/GhosttyLibVt.zig b/vendor/libghostty-vt/src/build/GhosttyLibVt.zig
index 65f945bf..690f864c 100644
--- a/vendor/libghostty-vt/src/build/GhosttyLibVt.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyLibVt.zig
@@ -5,6 +5,7 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const RunStep = std.Build.Step.Run;
const CombineArchivesStep = @import("CombineArchivesStep.zig");
+const LibsystemOverrideStep = @import("LibsystemOverrideStep.zig");
const Config = @import("Config.zig");
const GhosttyZig = @import("GhosttyZig.zig");
const LipoStep = @import("LipoStep.zig");
@@ -57,6 +58,12 @@ pub fn initWasm(
// There is no entrypoint for this wasm module.
exe.entry = .disabled;
+ // Default Zig stack size in Zig 0.16 is 1MB. Lower to 128 KB since
+ // this has to be preallocated up front in Wasm linear memory. Peak
+ // stack under various artificial loads is 17 KB at the time of this
+ // comment but lets do 128KB to be safe. We can lower later.
+ exe.stack_size = 128 * 1024;
+
// Zig's WASM linker doesn't support --growable-table, so the table
// is emitted with max == min and can't be grown from JS. Run a
// small Zig build tool that patches the binary's table section to
@@ -101,6 +108,16 @@ pub fn initShared(
b: *std.Build,
zig: *const GhosttyZig,
) !GhosttyLibVt {
+ const target = zig.vt.resolved_target.?;
+
+ // Prefer Apple's linker for final Darwin dylibs when its toolchain is
+ // available. Besides producing the platform load commands expected by
+ // Apple distribution, this lets the static archive's libSystem symbol
+ // override take effect. Cross-compiled macOS dylibs continue through Zig.
+ if (@import("apple_sdk").nativeLink.available(target)) {
+ return initLibApple(b, zig);
+ }
+
return initLib(b, zig, .dynamic);
}
@@ -172,16 +189,21 @@ pub fn initStaticAppleUniversal(
const target_query: std.Target.Query = .{
.cpu_arch = .aarch64,
.os_tag = p.os_tag,
- .os_version_min = Config.osVersionMin(p.os_tag),
+ .os_version_min = Config.osVersionMinLibVt(p.os_tag),
};
- if (detectAppleSDK(b.resolveTargetQuery(target_query).result)) {
+ if (detectAppleSDK(
+ b.graph.io,
+ b.allocator,
+ &b.graph.environ_map,
+ b.resolveTargetQuery(target_query).result,
+ )) {
const dev_zig = try zig.retarget(b, cfg, deps, b.resolveTargetQuery(target_query));
result.put(p.device, try initStatic(b, &dev_zig));
const sim_zig = try zig.retarget(b, cfg, deps, b.resolveTargetQuery(.{
.cpu_arch = .aarch64,
.os_tag = p.os_tag,
- .os_version_min = Config.osVersionMin(p.os_tag),
+ .os_version_min = Config.osVersionMinLibVt(p.os_tag),
.abi = .simulator,
.cpu_model = .{ .explicit = &std.Target.aarch64.cpu.apple_a17 },
}));
@@ -224,13 +246,28 @@ fn initLib(
// Enable PIC so the static library can be linked into PIE
// executables, which is the default on most Linux distributions.
- lib.root_module.pic = true;
+ // Native freestanding targets don't have a dynamic loader and some,
+ // such as Xtensa, don't support PIC relocations.
+ lib.root_module.pic = target.result.os.tag != .freestanding;
}
if (target.result.os.tag == .windows) {
// Zig's ubsan emits /exclude-symbols linker directives that
// are incompatible with the MSVC linker (LNK4229).
lib.bundle_ubsan_rt = false;
+
+ if (kind == .static) {
+ if (target.result.abi == .msvc) {
+ // Zig's compiler runtime doesn't provide MSVC's security
+ // cookie symbols when libc is linked. Disable stack-protector
+ // generation so static consumers don't need BufferOverflowU.
+ lib.root_module.stack_protector = false;
+ }
+
+ // The Zig standard library uses NT and kernel32 symbols.
+ lib.root_module.linkSystemLibrary("ntdll", .{});
+ lib.root_module.linkSystemLibrary("kernel32", .{});
+ }
}
if (lib.rootModuleTarget().abi.isAndroid()) {
@@ -290,28 +327,171 @@ fn initLib(
const combined = CombineArchivesStep.create(b, target, "ghostty-vt", sources.items);
combined.step.dependOn(&lib.step);
+ // On Darwin, prefer libSystem's libc/libm over the bundled
+ // compiler-rt for consumers of this archive. See GhosttyLib
+ // and libsystem_override.sh for details.
+ const override = LibsystemOverrideStep.create(
+ b,
+ target,
+ combined.output,
+ "libghostty-vt-fat.a",
+ );
+
return .{
- .step = combined.step,
+ .step = override.step orelse combined.step,
.artifact = &b.addInstallArtifact(lib, .{}).step,
.kind = kind,
- .output = combined.output,
+ .output = override.output,
.dsym = dsymutil,
.pkg_config = if (pcs) |v| v.shared else null,
.pkg_config_static = if (pcs) |v| v.static else null,
};
}
+ // Same libSystem preference for the plain (no vendored SIMD)
+ // static archive; a no-op off Darwin.
+ const override: LibsystemOverrideStep.Result = if (kind == .static) LibsystemOverrideStep.create(
+ b,
+ target,
+ lib.getEmittedBin(),
+ "libghostty-vt-static.a",
+ ) else .{
+ .step = null,
+ .output = lib.getEmittedBin(),
+ };
+
return .{
- .step = &lib.step,
+ .step = override.step orelse &lib.step,
.artifact = &b.addInstallArtifact(lib, .{}).step,
.kind = kind,
- .output = lib.getEmittedBin(),
+ .output = override.output,
.dsym = dsymutil,
.pkg_config = if (pcs) |v| v.shared else null,
.pkg_config_static = if (pcs) |v| v.static else null,
};
}
+/// Builds a shared Darwin library with Apple's linker.
+fn initLibApple(
+ b: *std.Build,
+ zig: *const GhosttyZig,
+) !GhosttyLibVt {
+ // Sorry, this function has a lot of comments because there are
+ // a lot of flags that aren't obvious.
+
+ const target = zig.vt.resolved_target.?;
+ assert(target.result.os.tag.isDarwin());
+
+ // Build the combined archive through the normal static path first.
+ const static = try initStatic(b, zig);
+
+ // Zig's module-level export metadata does not carry into this separate
+ // native link, so explicitly expose only libghostty-vt's public C ABI.
+ const exports = b.addWriteFiles().add(
+ "libghostty-vt.exports",
+ "_ghostty_*\n",
+ );
+
+ // Match Zig's versioned dylib naming so existing consumers and packaging
+ // continue to receive the same real name and compatibility symlinks.
+ const real_name = b.fmt("libghostty-vt.{d}.{d}.{d}.dylib", .{
+ zig.version.major,
+ zig.version.minor,
+ zig.version.patch,
+ });
+ const soname = b.fmt("libghostty-vt.{d}.dylib", .{zig.version.major});
+
+ const native_link = try @import("apple_sdk").nativeLink.addCommand(
+ b,
+ "link libghostty-vt with Apple ld",
+ target,
+ );
+
+ native_link.addArgs(&.{
+ // Emit a Mach-O dynamic library instead of an executable.
+ "-dynamiclib",
+ // Pull every object from the combined static archive.
+ "-Wl,-all_load",
+ // Remove unreachable private code pulled in by all_load.
+ "-Wl,-dead_strip",
+ // Leave room for packaging tools to rewrite install names.
+ "-Wl,-headerpad_max_install_names",
+ });
+ // Restrict exports to libghostty-vt's public C ABI.
+ native_link.addPrefixedFileArg("-Wl,-exported_symbols_list,", exports);
+ // Link the archive produced by the normal static-library path.
+ native_link.addFileArg(static.output);
+ native_link.addArgs(&.{
+ // Give framework consumers a stable runtime-relative identity.
+ "-install_name",
+ "@rpath/libghostty-vt.dylib",
+ // Record the exact package version for runtime inspection.
+ "-current_version",
+ b.fmt("{d}.{d}.{d}", .{
+ zig.version.major,
+ zig.version.minor,
+ zig.version.patch,
+ }),
+ // Preserve compatibility with the initial public ABI.
+ "-compatibility_version",
+ "1.0.0",
+ // Write the fully versioned dylib used by the install symlinks.
+ "-o",
+ });
+ const output = native_link.addOutputFileArg(real_name);
+
+ // Recreate addInstallArtifact's dylib layout: install the fully versioned
+ // file, then point the major-version and unversioned names at it.
+ const artifact_install = b.addInstallFileWithDir(
+ output,
+ .lib,
+ real_name,
+ );
+ const soname_install = b.addSystemCommand(&.{
+ "/bin/ln",
+ "-sf",
+ real_name,
+ b.getInstallPath(.lib, soname),
+ });
+ soname_install.step.dependOn(&artifact_install.step);
+ const unversioned_install = b.addSystemCommand(&.{
+ "/bin/ln",
+ "-sf",
+ soname,
+ b.getInstallPath(.lib, "libghostty-vt.dylib"),
+ });
+ unversioned_install.step.dependOn(&soname_install.step);
+
+ // The native link is a Run step rather than a Compile step, so install the
+ // public headers explicitly instead of relying on addInstallArtifact.
+ const headers_install = b.addInstallDirectory(.{
+ .source_dir = b.path("include/ghostty"),
+ .install_dir = .header,
+ .install_subdir = "ghostty",
+ .include_extensions = &.{".h"},
+ });
+ unversioned_install.step.dependOn(&headers_install.step);
+
+ // Preserve the debug-symbol output exposed by the normal shared-library
+ // path for framework and release packaging.
+ const dsymutil = RunStep.create(b, "dsymutil");
+ dsymutil.addArgs(&.{"dsymutil"});
+ dsymutil.addFileArg(output);
+ dsymutil.addArgs(&.{"-o"});
+ const dsym = dsymutil.addOutputFileArg("libghostty-vt.dSYM");
+
+ const pcs = pkgConfigFiles(b, zig, target.result.os.tag);
+ return .{
+ .step = &native_link.step,
+ .artifact = &unversioned_install.step,
+ .kind = .shared,
+ .output = output,
+ .dsym = dsym,
+ .pkg_config = pcs.shared,
+ .pkg_config_static = pcs.static,
+ };
+}
+
/// Returns the Libs.private value for the pkg-config file.
/// Vendored C++ dependencies are built in no-libcxx mode so consumers
/// don't need libc++. System-provided simdutf still requires it.
@@ -438,12 +618,21 @@ pub fn xcframework(
}
/// Returns true if the Apple SDK for the given target is installed.
-fn detectAppleSDK(target: std.Target) bool {
- _ = std.zig.LibCInstallation.findNative(.{
- .allocator = std.heap.page_allocator,
- .target = &target,
- .verbose = false,
- }) catch return false;
+fn detectAppleSDK(
+ io: std.Io,
+ alloc: std.mem.Allocator,
+ environ_map: *const std.process.Environ.Map,
+ target: std.Target,
+) bool {
+ _ = std.zig.LibCInstallation.findNative(
+ alloc,
+ io,
+ .{
+ .environ_map = environ_map,
+ .target = &target,
+ .verbose = false,
+ },
+ ) catch return false;
return true;
}
diff --git a/vendor/libghostty-vt/src/build/GhosttyResources.zig b/vendor/libghostty-vt/src/build/GhosttyResources.zig
index 6f857655..673c7e56 100644
--- a/vendor/libghostty-vt/src/build/GhosttyResources.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyResources.zig
@@ -21,9 +21,9 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
.strip = false,
.omit_frame_pointer = false,
.unwind_tables = .sync,
+ .link_libc = true,
}),
});
- build_data_exe.linkLibC();
deps.help_strings.addImport(build_data_exe);
@@ -39,7 +39,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run = b.addRunArtifact(build_data_exe);
run.addArg("+terminfo");
const wf = b.addWriteFiles();
- const source = wf.addCopyFile(run.captureStdOut(), "ghostty.terminfo");
+ const source = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.terminfo");
if (cfg.emit_terminfo) {
const source_install = b.addInstallFile(
@@ -63,8 +63,8 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run_step = RunStep.create(b, "infotocap");
run_step.addArg("infotocap");
run_step.addFileArg(source);
- const out_source = run_step.captureStdOut();
- _ = run_step.captureStdErr(); // so we don't see stderr
+ const out_source = run_step.captureStdOut(.{});
+ _ = run_step.captureStdErr(.{}); // so we don't see stderr
const cap_install = b.addInstallFile(
out_source,
@@ -84,7 +84,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const path = run_step.addOutputFileArg(terminfo_share_dir);
run_step.addFileArg(source);
- _ = run_step.captureStdErr(); // so we don't see stderr
+ _ = run_step.captureStdErr(.{}); // so we don't see stderr
// Ensure that `share/terminfo` is a directory, otherwise the `cp
// -R` will create a file named `share/terminfo`
@@ -143,7 +143,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run = b.addRunArtifact(build_data_exe);
run.addArg("+fish");
const wf = b.addWriteFiles();
- _ = wf.addCopyFile(run.captureStdOut(), "ghostty.fish");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.fish");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -158,7 +158,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run = b.addRunArtifact(build_data_exe);
run.addArg("+zsh");
const wf = b.addWriteFiles();
- _ = wf.addCopyFile(run.captureStdOut(), "_ghostty");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "_ghostty");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -173,7 +173,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run = b.addRunArtifact(build_data_exe);
run.addArg("+bash");
const wf = b.addWriteFiles();
- _ = wf.addCopyFile(run.captureStdOut(), "ghostty.bash");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.bash");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -190,22 +190,22 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-syntax");
- _ = wf.addCopyFile(run.captureStdOut(), "syntax/ghostty.vim");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "syntax/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-ftdetect");
- _ = wf.addCopyFile(run.captureStdOut(), "ftdetect/ghostty.vim");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "ftdetect/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-ftplugin");
- _ = wf.addCopyFile(run.captureStdOut(), "ftplugin/ghostty.vim");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "ftplugin/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-compiler");
- _ = wf.addCopyFile(run.captureStdOut(), "compiler/ghostty.vim");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "compiler/ghostty.vim");
}
const vim_step = b.addInstallDirectory(.{
@@ -233,7 +233,7 @@ pub fn init(b: *std.Build, cfg: *const Config, deps: *const SharedDeps) !Ghostty
const run = b.addRunArtifact(build_data_exe);
run.addArg("+sublime");
const wf = b.addWriteFiles();
- _ = wf.addCopyFile(run.captureStdOut(), "ghostty.sublime-syntax");
+ _ = wf.addCopyFile(run.captureStdOut(.{}), "ghostty.sublime-syntax");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -358,10 +358,10 @@ fn addLinuxAppResources(
// Template output has a single header line we want to remove.
// We use `tail` to do it since its part of the POSIX standard.
const tail = b.addSystemCommand(&.{ "tail", "-n", "+2" });
- tail.setStdIn(.{ .lazy_path = tpl.getOutput() });
+ tail.setStdIn(.{ .lazy_path = tpl.getOutputFile() });
const copy = b.addInstallFile(
- tail.captureStdOut(),
+ tail.captureStdOut(.{}),
template[1],
);
diff --git a/vendor/libghostty-vt/src/build/GhosttyWebdata.zig b/vendor/libghostty-vt/src/build/GhosttyWebdata.zig
index e29b20c2..7057ad03 100644
--- a/vendor/libghostty-vt/src/build/GhosttyWebdata.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyWebdata.zig
@@ -40,7 +40,7 @@ pub fn init(
}
const webgen_config_step = b.addRunArtifact(webgen_config);
- const webgen_config_out = webgen_config_step.captureStdOut();
+ const webgen_config_out = webgen_config_step.captureStdOut(.{});
try steps.append(b.allocator, &b.addInstallFile(
webgen_config_out,
@@ -71,7 +71,7 @@ pub fn init(
}
const webgen_actions_step = b.addRunArtifact(webgen_actions);
- const webgen_actions_out = webgen_actions_step.captureStdOut();
+ const webgen_actions_out = webgen_actions_step.captureStdOut(.{});
try steps.append(b.allocator, &b.addInstallFile(
webgen_actions_out,
@@ -102,7 +102,7 @@ pub fn init(
}
const webgen_commands_step = b.addRunArtifact(webgen_commands);
- const webgen_commands_out = webgen_commands_step.captureStdOut();
+ const webgen_commands_out = webgen_commands_step.captureStdOut(.{});
try steps.append(b.allocator, &b.addInstallFile(
webgen_commands_out,
diff --git a/vendor/libghostty-vt/src/build/GhosttyXCFramework.zig b/vendor/libghostty-vt/src/build/GhosttyXCFramework.zig
index a19dd18a..3f3b97eb 100644
--- a/vendor/libghostty-vt/src/build/GhosttyXCFramework.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyXCFramework.zig
@@ -24,35 +24,6 @@ pub fn init(
Config.genericMacOSTarget(b, null),
));
- // iOS
- const ios = try GhosttyLib.initStatic(b, &try deps.retarget(
- b,
- b.resolveTargetQuery(.{
- .cpu_arch = .aarch64,
- .os_tag = .ios,
- .os_version_min = Config.osVersionMin(.ios),
- .abi = null,
- }),
- ));
-
- // iOS Simulator
- const ios_sim = try GhosttyLib.initStatic(b, &try deps.retarget(
- b,
- b.resolveTargetQuery(.{
- .cpu_arch = .aarch64,
- .os_tag = .ios,
- .os_version_min = Config.osVersionMin(.ios),
- .abi = .simulator,
-
- // We force the Apple CPU model because the simulator
- // doesn't support the generic CPU model as of Zig 0.14 due
- // to missing "altnzcv" instructions, which is false. This
- // surely can't be right but we can fix this if/when we get
- // back to running simulator builds.
- .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.apple_a17 },
- }),
- ));
-
// Generate a headers directory with only ghostty.h and the module
// map. We can't use include/ directly because it also contains the
// libghostty-vt headers under include/ghostty/, which would trigger
@@ -75,16 +46,6 @@ pub fn init(
.headers = headers,
.dsym = macos_universal.dsym,
},
- .{
- .library = ios.output,
- .headers = headers,
- .dsym = ios.dsym,
- },
- .{
- .library = ios_sim.output,
- .headers = headers,
- .dsym = ios_sim.dsym,
- },
},
.native => &.{.{
diff --git a/vendor/libghostty-vt/src/build/GhosttyXcodebuild.zig b/vendor/libghostty-vt/src/build/GhosttyXcodebuild.zig
index 81af994c..6f7e18dc 100644
--- a/vendor/libghostty-vt/src/build/GhosttyXcodebuild.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyXcodebuild.zig
@@ -48,21 +48,21 @@ pub fn init(
},
};
- const env = try std.process.getEnvMap(b.allocator);
+ const env = b.graph.environ_map;
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
// Our step to build the Ghostty macOS app.
const build = build: {
// External environment variables can mess up xcodebuild, so
// we create a new empty environment.
- const env_map = try b.allocator.create(std.process.EnvMap);
+ const env_map = try b.allocator.create(std.process.Environ.Map);
env_map.* = .init(b.allocator);
if (env.get("PATH")) |v| try env_map.put("PATH", v);
const step = RunStep.create(b, "xcodebuild");
step.has_side_effects = true;
step.cwd = b.path("macos");
- step.env_map = env_map;
+ step.environ_map = env_map;
step.addArgs(&.{
"xcodebuild",
"-target",
@@ -91,14 +91,14 @@ pub fn init(
};
const xctest = xctest: {
- const env_map = try b.allocator.create(std.process.EnvMap);
+ const env_map = try b.allocator.create(std.process.Environ.Map);
env_map.* = .init(b.allocator);
if (env.get("PATH")) |v| try env_map.put("PATH", v);
const step = RunStep.create(b, "xcodebuild test");
step.has_side_effects = true;
step.cwd = b.path("macos");
- step.env_map = env_map;
+ step.environ_map = env_map;
step.addArgs(&.{
"xcodebuild",
"test",
diff --git a/vendor/libghostty-vt/src/build/GhosttyZig.zig b/vendor/libghostty-vt/src/build/GhosttyZig.zig
index 44c300e1..46ab05d5 100644
--- a/vendor/libghostty-vt/src/build/GhosttyZig.zig
+++ b/vendor/libghostty-vt/src/build/GhosttyZig.zig
@@ -64,7 +64,7 @@ fn initInner(
vt_c_name: []const u8,
) !GhosttyZig {
// Terminal module build options
- var vt_options = cfg.terminalOptions(.lib);
+ var vt_options = cfg.terminalOptions(.lib, cfg.optimize);
vt_options.artifact = .lib;
// We presently don't allow Oniguruma in our Zig module at all.
// We should expose this as a build option in the future so we can
@@ -135,7 +135,21 @@ fn initVt(
deps.unicode_tables.addModuleImport(vt);
// We need uucode for grapheme break support
- deps.addUucode(b, vt, cfg.target, cfg.optimize);
+ vt.addImport("uucode", deps.uucode_mod);
+
+ // We need wuffs for Kitty graphics pixel operations (format
+ // conversion and alpha blending). Unlike pure Zig dependencies
+ // its C code is compiled whenever the module is in the build
+ // graph regardless of analysis, so only wire it in when Kitty
+ // graphics is actually enabled.
+ if (vt_options.kittyGraphics(cfg.target.result)) {
+ if (b.lazyDependency("wuffs", .{
+ .target = cfg.target,
+ .optimize = cfg.optimize,
+ })) |dep| {
+ vt.addImport("wuffs", dep.module("wuffs"));
+ }
+ }
// If SIMD is enabled, add all our SIMD dependencies.
if (cfg.simd) {
diff --git a/vendor/libghostty-vt/src/build/GitVersion.zig b/vendor/libghostty-vt/src/build/GitVersion.zig
index 41cc7f84..2365a110 100644
--- a/vendor/libghostty-vt/src/build/GitVersion.zig
+++ b/vendor/libghostty-vt/src/build/GitVersion.zig
@@ -23,7 +23,7 @@ pub fn detect(b: *std.Build) !Version {
const tmp: []u8 = b.runAllowFail(
&[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "rev-parse", "--abbrev-ref", "HEAD" },
&code,
- .Ignore,
+ .ignore,
) catch |err| switch (err) {
error.FileNotFound => return error.GitNotFound,
error.ExitCodeFailure => return error.GitNotRepository,
@@ -44,19 +44,19 @@ pub fn detect(b: *std.Build) !Version {
const output = b.runAllowFail(
&[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "-c", "log.showSignature=false", "log", "--pretty=format:%h", "-n", "1" },
&code,
- .Ignore,
+ .ignore,
) catch |err| switch (err) {
error.FileNotFound => return error.GitNotFound,
else => return err,
};
- break :short_hash std.mem.trimRight(u8, output, "\r\n ");
+ break :short_hash std.mem.trimEnd(u8, output, "\r\n ");
};
const tag = b.runAllowFail(
&[_][]const u8{ "git", "-C", b.build_root.path orelse ".", "describe", "--exact-match", "--tags" },
&code,
- .Ignore,
+ .ignore,
) catch |err| switch (err) {
error.FileNotFound => return error.GitNotFound,
error.ExitCodeFailure => "", // expected
@@ -70,7 +70,7 @@ pub fn detect(b: *std.Build) !Version {
"diff",
"--quiet",
"--exit-code",
- }, &code, .Ignore) catch |err| switch (err) {
+ }, &code, .ignore) catch |err| switch (err) {
error.FileNotFound => return error.GitNotFound,
error.ExitCodeFailure => {}, // expected
else => return err,
@@ -80,7 +80,7 @@ pub fn detect(b: *std.Build) !Version {
return .{
.short_hash = short_hash,
.changes = changes,
- .tag = if (tag.len > 0) std.mem.trimRight(u8, tag, "\r\n ") else null,
- .branch = std.mem.trimRight(u8, branch, "\r\n "),
+ .tag = if (tag.len > 0) std.mem.trimEnd(u8, tag, "\r\n ") else null,
+ .branch = std.mem.trimEnd(u8, branch, "\r\n "),
};
}
diff --git a/vendor/libghostty-vt/src/build/HelpStrings.zig b/vendor/libghostty-vt/src/build/HelpStrings.zig
index 96505cab..24ae82e2 100644
--- a/vendor/libghostty-vt/src/build/HelpStrings.zig
+++ b/vendor/libghostty-vt/src/build/HelpStrings.zig
@@ -34,7 +34,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !HelpStrings {
// Generated Zig files have to end with .zig
const wf = b.addWriteFiles();
- const output = wf.addCopyFile(help_run.captureStdOut(), "helpgen.zig");
+ const output = wf.addCopyFile(help_run.captureStdOut(.{}), "helpgen.zig");
return .{
.exe = exe,
diff --git a/vendor/libghostty-vt/src/build/LibsystemOverrideStep.zig b/vendor/libghostty-vt/src/build/LibsystemOverrideStep.zig
new file mode 100644
index 00000000..3e1cafa5
--- /dev/null
+++ b/vendor/libghostty-vt/src/build/LibsystemOverrideStep.zig
@@ -0,0 +1,51 @@
+//! Wraps a Darwin static archive with the libsystem_override.sh
+//! post-processing step so that consumers linking the archive bind
+//! well-known libc/libm symbols (memcpy, memmove, memset, cos, sin,
+//! ...) to Apple's libSystem instead of the bundled Zig compiler-rt.
+//! See src/build/libsystem_override.sh for the full rationale.
+//!
+//! This applies to every static archive we produce, public
+//! (e.g. libghostty-vt) and app-internal alike: the compiler-rt
+//! bundle must stay because the few symbols libSystem does not
+//! provide (f128 conversions, *q math, sincos*, ___zig_probe_stack)
+//! have live references, e.g. from the bundled ubsan runtime and
+//! x86_64 stack probing in Debug builds.
+//!
+//! Note shared libraries can't use either approach: Zig 0.16 links
+//! compiler-rt as an eagerly-included object, so its definitions are
+//! already bound into the dylib at link time and cannot be repaired
+//! post-hoc. That needs an upstream Zig fix.
+const std = @import("std");
+const builtin = @import("builtin");
+
+pub const Result = struct {
+ /// The step performing the override, or null if the override
+ /// doesn't apply to this target/host (in which case `output` is
+ /// the unmodified input).
+ step: ?*std.Build.Step,
+ output: std.Build.LazyPath,
+};
+
+/// Post-process the given static archive on Darwin. Requires a Darwin
+/// host for the Apple toolchain (nmedit); in all other configurations
+/// this is a no-op and the input is returned unmodified, which is
+/// functional (the bundled compiler-rt symbols are used), just slower.
+pub fn create(
+ b: *std.Build,
+ target: std.Build.ResolvedTarget,
+ input: std.Build.LazyPath,
+ out_name: []const u8,
+) Result {
+ if (!target.result.os.tag.isDarwin() or
+ comptime !builtin.os.tag.isDarwin())
+ {
+ return .{ .step = null, .output = input };
+ }
+
+ const run = b.addSystemCommand(&.{"/bin/sh"});
+ run.setName("libsystem override");
+ run.addFileArg(b.path("src/build/libsystem_override.sh"));
+ run.addFileArg(input);
+ const output = run.addOutputFileArg(out_name);
+ return .{ .step = &run.step, .output = output };
+}
diff --git a/vendor/libghostty-vt/src/build/MetallibStep.zig b/vendor/libghostty-vt/src/build/MetallibStep.zig
index fcf3055f..81c7a4a9 100644
--- a/vendor/libghostty-vt/src/build/MetallibStep.zig
+++ b/vendor/libghostty-vt/src/build/MetallibStep.zig
@@ -24,20 +24,10 @@ output: LazyPath,
pub fn create(b: *std.Build, opts: Options) ?*MetallibStep {
const sdk = switch (opts.target.result.os.tag) {
.macos => "macosx",
- .ios => switch (opts.target.result.abi) {
- // The iOS simulator uses the same SDK for Metal as the device,
- // but the minimum version tag causes different behaviors.
- .simulator => "iphoneos",
- else => "iphoneos",
- },
else => return null,
};
const platform_version_arg = switch (opts.target.result.os.tag) {
.macos => "-mmacos-version-min",
- .ios => switch (opts.target.result.abi) {
- .simulator => "-mios-simulator-version-min",
- else => "-mios-version-min",
- },
else => null,
};
@@ -47,7 +37,6 @@ pub fn create(b: *std.Build, opts: Options) ?*MetallibStep {
b.fmt("{f}", .{v.semver})
else switch (opts.target.result.os.tag) {
.macos => "10.14",
- .ios => "11.0",
else => unreachable,
};
diff --git a/vendor/libghostty-vt/src/build/SharedDeps.zig b/vendor/libghostty-vt/src/build/SharedDeps.zig
index b68be92d..72abfb9a 100644
--- a/vendor/libghostty-vt/src/build/SharedDeps.zig
+++ b/vendor/libghostty-vt/src/build/SharedDeps.zig
@@ -9,6 +9,7 @@ const MetallibStep = @import("MetallibStep.zig");
const UnicodeTables = @import("UnicodeTables.zig");
const GhosttyFrameData = @import("GhosttyFrameData.zig");
const DistResource = @import("GhosttyDist.zig").Resource;
+const gtk_helpers = @import("gtk.zig");
config: *const Config,
@@ -19,6 +20,43 @@ unicode_tables: UnicodeTables,
framedata: GhosttyFrameData,
uucode_tables: std.Build.LazyPath,
+/// Singleton uucode module, instantiated once in `init` and reused
+/// everywhere so that ghostty and vaxis share the same compiled tables in
+/// each final binary instead of each linking its own copy.
+///
+/// Sharing one instance is also a hard requirement (not just an
+/// optimization) for Zig 0.16's strict module model. `SharedDeps.add` runs
+/// many times across different (target, optimize) tuples (macos-aarch64,
+/// macos-x86_64, ios-aarch64, Debug + ReleaseFast, etc.), and on each
+/// call we have to wire uucode into both the step's root module and into
+/// vaxis_mod (because vaxis's `Parser.zig` does `@import("uucode")` and
+/// we pass `external_uucode = true` to vaxis's build.zig so vaxis doesn't
+/// instantiate its own uucode dep). If those two import bindings ever
+/// resolve to *different* `*Module` pointers within a single Compile
+/// step's analysis, Zig fails with:
+///
+/// vaxis/src/Parser.zig: file exists in modules 'uucode' and 'uucode0'
+///
+/// because all those uucode module instances share the same physical
+/// `uucode/src/root.zig` file on disk, and Zig requires every file to belong
+/// to exactly one module within a Compile graph.
+///
+/// The natural way to keep them the same would be to call
+/// `b.lazyDependency("uucode", .{ .tables_path, .build_config_path })`
+/// from each call site and let Zig's dependency cache deduplicate
+/// identical args. That fails because of a bug in Zig's
+/// `userLazyPathsAreTheSame` (Build.zig) where the `.src_path` and
+/// `.generated` equality checks are inverted: `if (std.mem.eql(...))
+/// return false` instead of `if (!std.mem.eql(...)) return false`. The
+/// dep cache key therefore always misses whenever any arg is a
+/// `b.path(...)` LazyPath, so each call returns a fresh `*Dependency`
+/// with a fresh `*Module`. Hoisting the dep into one eager
+/// `b.dependency` call here sidesteps the cache entirely.
+///
+/// This conflict is independent of whether vaxis itself is acquired as a
+/// singleton or per-target dep.
+uucode_mod: *std.Build.Module,
+
/// Used to keep track of a list of file sources.
pub const LazyPathList = std.ArrayList(std.Build.LazyPath);
@@ -31,12 +69,26 @@ pub fn init(b: *std.Build, cfg: *const Config) !SharedDeps {
break :blk uucode.namedLazyPath("tables.zig");
};
+ // Instantiate the singleton uucode module that both ghostty and vaxis
+ // import. See the doc comment on `uucode_mod`.
+ const uucode_mod = b.dependency("uucode", .{
+ .tables_path = uucode_tables,
+ .build_config_path = b.path("src/build/uucode_config.zig"),
+ }).module("uucode");
+
+ // Re-export the uucode module so that Zig programs that embed libgtostty-vt
+ // can use it. This is necessary to use libraries like libvaxis in
+ // the embedding program that need uucode as well (libvaxis provides
+ // -Dexternal_uucode for this).
+ try b.modules.put(b.allocator, b.dupe("uucode"), uucode_mod);
+
var result: SharedDeps = .{
.config = cfg,
.help_strings = try .init(b, cfg),
.unicode_tables = try .init(b, uucode_tables),
.framedata = try .init(b),
.uucode_tables = uucode_tables,
+ .uucode_mod = uucode_mod,
// Setup by retarget
.options = undefined,
@@ -133,7 +185,10 @@ pub fn add(
step.root_module.addOptions("build_options", self.options);
// Every exe needs the terminal options
- self.config.terminalOptions(.ghostty).add(b, step.root_module);
+ self.config.terminalOptions(.ghostty, optimize).add(b, step.root_module);
+
+ // Every exe needs the uucode module
+ step.root_module.addImport("uucode", self.uucode_mod);
// C imports for locale constants and functions
{
@@ -143,11 +198,15 @@ pub fn add(
.optimize = optimize,
});
if (target.result.os.tag.isDarwin()) {
- const libc = try std.zig.LibCInstallation.findNative(.{
- .allocator = b.allocator,
- .target = &target.result,
- .verbose = false,
- });
+ const libc = try std.zig.LibCInstallation.findNative(
+ b.allocator,
+ b.graph.io,
+ .{
+ .environ_map = &b.graph.environ_map,
+ .target = &target.result,
+ .verbose = false,
+ },
+ );
c.addSystemIncludePath(.{ .cwd_relative = libc.sys_include_dir.? });
}
step.root_module.addImport("locale-c", c.createModule());
@@ -166,11 +225,15 @@ pub fn add(
});
switch (target.result.os.tag) {
.macos => {
- const libc = try std.zig.LibCInstallation.findNative(.{
- .allocator = b.allocator,
- .target = &target.result,
- .verbose = false,
- });
+ const libc = try std.zig.LibCInstallation.findNative(
+ b.allocator,
+ b.graph.io,
+ .{
+ .environ_map = &b.graph.environ_map,
+ .target = &target.result,
+ .verbose = false,
+ },
+ );
c.addSystemIncludePath(.{ .cwd_relative = libc.sys_include_dir.? });
},
else => {},
@@ -194,10 +257,10 @@ pub fn add(
);
if (b.systemIntegrationOption("freetype", .{})) {
- step.linkSystemLibrary2("bzip2", dynamic_link_opts);
- step.linkSystemLibrary2("freetype2", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("bzip2", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("freetype2", dynamic_link_opts);
} else {
- step.linkLibrary(freetype_dep.artifact("freetype"));
+ step.root_module.linkLibrary(freetype_dep.artifact("freetype"));
try static_libs.append(
b.allocator,
freetype_dep.artifact("freetype").getEmittedBin(),
@@ -219,9 +282,9 @@ pub fn add(
harfbuzz_dep.module("harfbuzz"),
);
if (b.systemIntegrationOption("harfbuzz", .{})) {
- step.linkSystemLibrary2("harfbuzz", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("harfbuzz", dynamic_link_opts);
} else {
- step.linkLibrary(harfbuzz_dep.artifact("harfbuzz"));
+ step.root_module.linkLibrary(harfbuzz_dep.artifact("harfbuzz"));
try static_libs.append(
b.allocator,
harfbuzz_dep.artifact("harfbuzz").getEmittedBin(),
@@ -243,9 +306,9 @@ pub fn add(
);
if (b.systemIntegrationOption("fontconfig", .{})) {
- step.linkSystemLibrary2("fontconfig", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("fontconfig", dynamic_link_opts);
} else {
- step.linkLibrary(fontconfig_dep.artifact("fontconfig"));
+ step.root_module.linkLibrary(fontconfig_dep.artifact("fontconfig"));
try static_libs.append(
b.allocator,
fontconfig_dep.artifact("fontconfig").getEmittedBin(),
@@ -263,7 +326,7 @@ pub fn add(
.target = target,
.optimize = optimize,
})) |libpng_dep| {
- step.linkLibrary(libpng_dep.artifact("png"));
+ step.root_module.linkLibrary(libpng_dep.artifact("png"));
try static_libs.append(
b.allocator,
libpng_dep.artifact("png").getEmittedBin(),
@@ -277,7 +340,7 @@ pub fn add(
.target = target,
.optimize = optimize,
})) |zlib_dep| {
- step.linkLibrary(zlib_dep.artifact("z"));
+ step.root_module.linkLibrary(zlib_dep.artifact("z"));
try static_libs.append(
b.allocator,
zlib_dep.artifact("z").getEmittedBin(),
@@ -295,9 +358,9 @@ pub fn add(
oniguruma_dep.module("oniguruma"),
);
if (b.systemIntegrationOption("oniguruma", .{})) {
- step.linkSystemLibrary2("oniguruma", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("oniguruma", dynamic_link_opts);
} else {
- step.linkLibrary(oniguruma_dep.artifact("oniguruma"));
+ step.root_module.linkLibrary(oniguruma_dep.artifact("oniguruma"));
try static_libs.append(
b.allocator,
oniguruma_dep.artifact("oniguruma").getEmittedBin(),
@@ -312,13 +375,13 @@ pub fn add(
})) |glslang_dep| {
step.root_module.addImport("glslang", glslang_dep.module("glslang"));
if (b.systemIntegrationOption("glslang", .{})) {
- step.linkSystemLibrary2("glslang", dynamic_link_opts);
- step.linkSystemLibrary2(
+ step.root_module.linkSystemLibrary("glslang", dynamic_link_opts);
+ step.root_module.linkSystemLibrary(
"glslang-default-resource-limits",
dynamic_link_opts,
);
} else {
- step.linkLibrary(glslang_dep.artifact("glslang"));
+ step.root_module.linkLibrary(glslang_dep.artifact("glslang"));
try static_libs.append(
b.allocator,
glslang_dep.artifact("glslang").getEmittedBin(),
@@ -336,9 +399,9 @@ pub fn add(
spirv_cross_dep.module("spirv_cross"),
);
if (b.systemIntegrationOption("spirv-cross", .{})) {
- step.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts);
} else {
- step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
+ step.root_module.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
try static_libs.append(
b.allocator,
spirv_cross_dep.artifact("spirv_cross").getEmittedBin(),
@@ -357,7 +420,7 @@ pub fn add(
"sentry",
sentry_dep.module("sentry"),
);
- step.linkLibrary(sentry_dep.artifact("sentry"));
+ step.root_module.linkLibrary(sentry_dep.artifact("sentry"));
try static_libs.append(
b.allocator,
sentry_dep.artifact("sentry").getEmittedBin(),
@@ -404,18 +467,18 @@ pub fn add(
if (step.rootModuleTarget().os.tag == .linux) {
const triple = try step.rootModuleTarget().linuxTriple(b.allocator);
const path = b.fmt("/usr/lib/{s}", .{triple});
- if (std.fs.accessAbsolute(path, .{})) {
- step.addLibraryPath(.{ .cwd_relative = path });
+ if (std.Io.Dir.accessAbsolute(b.graph.io, path, .{})) {
+ step.root_module.addLibraryPath(.{ .cwd_relative = path });
} else |_| {}
}
// C files
- step.linkLibC();
- step.addIncludePath(b.path("src/stb"));
+ step.root_module.link_libc = true;
+ step.root_module.addIncludePath(b.path("src/stb"));
// Disable ubsan for MSVC: Zig's ubsan runtime cannot be bundled
// on Windows (LNK4229), leaving __ubsan_handle_* unresolved when
// the static archive is consumed by an external linker.
- step.addCSourceFiles(.{
+ step.root_module.addCSourceFiles(.{
.files = &.{"src/stb/stb.c"},
.flags = if (step.rootModuleTarget().abi == .msvc)
&.{ "-fno-sanitize=undefined", "-fno-sanitize-trap=undefined" }
@@ -423,7 +486,7 @@ pub fn add(
&.{},
});
if (step.rootModuleTarget().os.tag == .linux) {
- step.addIncludePath(b.path("src/apprt/gtk"));
+ step.root_module.addIncludePath(b.path("src/apprt/gtk"));
}
// libcpp is required for various dependencies. On MSVC, we must
@@ -433,7 +496,7 @@ pub fn add(
// include directories (already added via linkLibC above) contain
// both C and C++ headers, so linkLibCpp is not needed.
if (step.rootModuleTarget().abi != .msvc) {
- step.linkLibCpp();
+ step.root_module.link_libcpp = true;
}
// We always require the system SDK so that our system headers are available.
@@ -452,8 +515,14 @@ pub fn add(
if (b.lazyDependency("opengl", .{})) |dep| {
step.root_module.addImport("opengl", dep.module("opengl"));
}
- if (b.lazyDependency("vaxis", .{})) |dep| {
- step.root_module.addImport("vaxis", dep.module("vaxis"));
+ if (b.lazyDependency("vaxis", .{
+ .target = target,
+ .optimize = optimize,
+ .external_uucode = true,
+ })) |dep| {
+ const vaxis = dep.module("vaxis");
+ step.root_module.addImport("vaxis", vaxis);
+ vaxis.addImport("uucode", self.uucode_mod);
}
if (b.lazyDependency("wuffs", .{
.target = target,
@@ -473,7 +542,6 @@ pub fn add(
})) |dep| {
step.root_module.addImport("z2d", dep.module("z2d"));
}
- self.addUucode(b, step.root_module, target, optimize);
if (b.lazyDependency("zf", .{
.target = target,
.optimize = optimize,
@@ -502,7 +570,7 @@ pub fn add(
"macos",
macos_dep.module("macos"),
);
- step.linkLibrary(
+ step.root_module.linkLibrary(
macos_dep.artifact("macos"),
);
try static_libs.append(
@@ -512,7 +580,7 @@ pub fn add(
}
if (self.config.renderer == .opengl) {
- step.linkFramework("OpenGL");
+ step.root_module.linkFramework("OpenGL", .{});
}
// Apple platforms do not include libc libintl so we bundle it.
@@ -523,7 +591,7 @@ pub fn add(
.target = target,
.optimize = optimize,
})) |libintl_dep| {
- step.linkLibrary(libintl_dep.artifact("intl"));
+ step.root_module.linkLibrary(libintl_dep.artifact("intl"));
try static_libs.append(
b.allocator,
libintl_dep.artifact("intl").getEmittedBin(),
@@ -543,7 +611,7 @@ pub fn add(
.@"backend-opengl3" = !target.result.os.tag.isDarwin(),
})) |dep| {
step.root_module.addImport("dcimgui", dep.module("dcimgui"));
- step.linkLibrary(dep.artifact("dcimgui"));
+ step.root_module.linkLibrary(dep.artifact("dcimgui"));
try static_libs.append(
b.allocator,
dep.artifact("dcimgui").getEmittedBin(),
@@ -592,15 +660,38 @@ pub fn add(
// If we're building an exe then we have additional dependencies.
if (step.kind != .lib) {
// We always statically compile glad
- step.addIncludePath(b.path("vendor/glad/include/"));
- step.addCSourceFile(.{
+ step.root_module.addIncludePath(b.path("vendor/glad/include/"));
+ step.root_module.addCSourceFile(.{
.file = b.path("vendor/glad/src/gl.c"),
.flags = &.{},
});
// When we're targeting flatpak we ALWAYS link GTK so we
// get access to glib for dbus.
- if (self.config.flatpak) step.linkSystemLibrary2("gtk4", dynamic_link_opts);
+ if (self.config.flatpak) {
+ step.root_module.linkSystemLibrary("gtk4", dynamic_link_opts);
+
+ // We need to translate gio headers too
+ gio_translate: {
+ // translate-c stuff
+ const translate_c = b.lazyImport(@import("../../build.zig"), "translate_c") orelse
+ break :gio_translate;
+ const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse
+ break :gio_translate;
+ const translated: translate_c.Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add("gio_c.h",
+ \\#include <gio/gio.h>
+ \\#include <gio/gunixfdlist.h>
+ ),
+ .target = target,
+ .optimize = optimize,
+ .link_system_libs = &.{
+ .{ .name = "gio-2.0", .options = dynamic_link_opts },
+ },
+ });
+ step.root_module.addImport("gio_c", translated.mod);
+ }
+ }
switch (self.config.app_runtime) {
.none => {},
@@ -634,6 +725,7 @@ fn addGtkNg(
.{ "gdk", "gdk4" },
.{ "gio", "gio2" },
.{ "glib", "glib2" },
+ .{ "glibunix", "glibunix2" },
.{ "gobject", "gobject2" },
.{ "gtk", "gtk4" },
.{ "xlib", "xlib2" },
@@ -643,12 +735,44 @@ fn addGtkNg(
step.root_module.addImport(name, gobject.module(module));
}
}
-
- step.linkSystemLibrary2("gtk4", dynamic_link_opts);
- step.linkSystemLibrary2("libadwaita-1", dynamic_link_opts);
+ gtk_adw_translate: {
+ // translate-c stuff
+ const translate_c = b.lazyImport(@import("../../build.zig"), "translate_c") orelse break :gtk_adw_translate;
+ const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :gtk_adw_translate;
+ const Translator = translate_c.Translator;
+
+ {
+ // GTK headers
+ const translated: Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add("gtk_c.h",
+ \\#include <gtk/gtk.h>
+ ),
+ .target = target,
+ .optimize = optimize,
+ .link_system_libs = &.{
+ .{ .name = "gtk4", .options = dynamic_link_opts },
+ },
+ });
+ step.root_module.addImport("gtk_c", translated.mod);
+ }
+ {
+ // Adwaita headers
+ const translated: Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add("adw_c.h",
+ \\#include <adwaita.h>
+ ),
+ .target = target,
+ .optimize = optimize,
+ .link_system_libs = &.{
+ .{ .name = "libadwaita-1", .options = dynamic_link_opts },
+ },
+ });
+ step.root_module.addImport("adw_c", translated.mod);
+ }
+ }
if (self.config.x11) {
- step.linkSystemLibrary2("X11", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("X11", dynamic_link_opts);
if (gobject_) |gobject| {
step.root_module.addImport(
"gdk_x11",
@@ -699,13 +823,19 @@ fn addGtkNg(
);
scanner.addSystemProtocol("staging/xdg-activation/xdg-activation-v1.xml");
scanner.addSystemProtocol("staging/ext-background-effect/ext-background-effect-v1.xml");
+ scanner.addCustomProtocol(
+ b.path("src/apprt/gtk/winproto/wayland/protocols/vicinae-hotkey-v1.xml"),
+ );
scanner.generate("wl_compositor", 1);
+ // Only referenced by vicinae_hotkey_manager_v1.bind (nullable arg).
+ scanner.generate("wl_seat", 1);
scanner.generate("org_kde_kwin_server_decoration_manager", 1);
scanner.generate("org_kde_kwin_slide_manager", 1);
scanner.generate("kde_output_order_v1", 1);
scanner.generate("xdg_activation_v1", 1);
scanner.generate("ext_background_effect_manager_v1", 1);
+ scanner.generate("vicinae_hotkey_manager_v1", 1);
step.root_module.addImport("wayland", b.createModule(.{
.root_source_file = scanner.result,
@@ -732,24 +862,39 @@ fn addGtkNg(
// IMPORTANT: gtk4-layer-shell must be linked BEFORE
// wayland-client, as it relies on shimming libwayland's APIs.
if (b.systemIntegrationOption("gtk4-layer-shell", .{})) {
- step.linkSystemLibrary2("gtk4-layer-shell-0", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("gtk4-layer-shell-0", dynamic_link_opts);
} else {
// gtk4-layer-shell *must* be dynamically linked,
// so we don't add it as a static library
const shared_lib = gtk4_layer_shell.artifact("gtk4-layer-shell");
b.installArtifact(shared_lib);
- step.linkLibrary(shared_lib);
+ step.root_module.linkLibrary(shared_lib);
}
}
- step.linkSystemLibrary2("wayland-client", dynamic_link_opts);
+ step.root_module.linkSystemLibrary("wayland-client", dynamic_link_opts);
}
- {
+ ghostty_resources_translate: {
// Get our gresource c/h files and add them to our build.
const dist = gtkNgDistResources(b);
- step.addCSourceFile(.{ .file = dist.resources_c.path(b), .flags = &.{} });
- step.addIncludePath(dist.resources_h.path(b).dirname());
+ const translate_c = b.lazyImport(@import("../../build.zig"), "translate_c") orelse
+ break :ghostty_resources_translate;
+ const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse
+ break :ghostty_resources_translate;
+ const translated: translate_c.Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add("c.h",
+ \\#include <ghostty_resources.h>
+ ),
+ .target = target,
+ .optimize = optimize,
+ .link_system_libs = &.{
+ .{ .name = "glib-2.0", .options = dynamic_link_opts },
+ },
+ });
+ translated.addIncludePath(dist.resources_h.path(b).dirname());
+ translated.mod.addCSourceFile(.{ .file = dist.resources_c.path(b), .flags = &.{} });
+ step.root_module.addImport("ghostty_gtk_resources", translated.mod);
}
}
@@ -853,6 +998,11 @@ pub fn addSimd(
"-fno-sanitize=undefined",
"-fno-sanitize-trap=undefined",
});
+ if (target.result.abi == .msvc) try flags.appendSlice(b.allocator, &.{
+ // -fno-autolink also drops UCRT's /alternatename fallback.
+ "-D_Avx2WmemEnabledWeakValue=_Avx2WmemEnabled",
+ "-fno-autolink",
+ });
m.addCSourceFiles(.{
.files = &.{
@@ -890,11 +1040,25 @@ pub fn gtkNgDistResources(
.root_module = b.createModule(.{
.root_source_file = b.path("src/apprt/gtk/build/blueprint.zig"),
.target = b.graph.host,
+ .link_libc = true,
}),
});
- blueprint_exe.linkLibC();
- blueprint_exe.linkSystemLibrary2("gtk4", dynamic_link_opts);
- blueprint_exe.linkSystemLibrary2("libadwaita-1", dynamic_link_opts);
+ adw_translate: {
+ // Adwaita headers
+ const translate_c = b.lazyImport(@import("../../build.zig"), "translate_c") orelse break :adw_translate;
+ const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :adw_translate;
+ const translated: translate_c.Translator = .init(translate_c_dep, .{
+ .c_source_file = b.addWriteFiles().add("adw_c.h",
+ \\#include <adwaita.h>
+ ),
+ .target = b.graph.host,
+ .optimize = .Debug,
+ .link_system_libs = &.{
+ .{ .name = "libadwaita-1", .options = dynamic_link_opts },
+ },
+ });
+ blueprint_exe.root_module.addImport("adw_c", translated.mod);
+ }
for (gresource.blueprints) |bp| {
const blueprint_run = b.addRunArtifact(blueprint_exe);
@@ -923,7 +1087,7 @@ pub fn gtkNgDistResources(
xml_run.addFileArg(ui_file);
}
- break :gresource_xml xml_run.captureStdOut();
+ break :gresource_xml xml_run.captureStdOut(.{});
};
const generate_c = b.addSystemCommand(&.{
@@ -964,23 +1128,6 @@ pub fn gtkNgDistResources(
};
}
-pub fn addUucode(
- self: *const SharedDeps,
- b: *std.Build,
- module: *std.Build.Module,
- target: std.Build.ResolvedTarget,
- optimize: std.builtin.OptimizeMode,
-) void {
- if (b.lazyDependency("uucode", .{
- .target = target,
- .optimize = optimize,
- .tables_path = self.uucode_tables,
- .build_config_path = b.path("src/build/uucode_config.zig"),
- })) |dep| {
- module.addImport("uucode", dep.module("uucode"));
- }
-}
-
// For dynamic linking, we prefer dynamic linking and to search by
// mode first. Mode first will search all paths for a dynamic library
// before falling back to static.
diff --git a/vendor/libghostty-vt/src/build/UnicodeTables.zig b/vendor/libghostty-vt/src/build/UnicodeTables.zig
index 17a839ea..843ada51 100644
--- a/vendor/libghostty-vt/src/build/UnicodeTables.zig
+++ b/vendor/libghostty-vt/src/build/UnicodeTables.zig
@@ -54,8 +54,8 @@ pub fn init(b: *std.Build, uucode_tables: std.Build.LazyPath) !UnicodeTables {
// Generated Zig files have to end with .zig
const wf = b.addWriteFiles();
- const props_output = wf.addCopyFile(props_run.captureStdOut(), "props.zig");
- const symbols_output = wf.addCopyFile(symbols_run.captureStdOut(), "symbols.zig");
+ const props_output = wf.addCopyFile(props_run.captureStdOut(.{}), "props.zig");
+ const symbols_output = wf.addCopyFile(symbols_run.captureStdOut(.{}), "symbols.zig");
return .{
.props_exe = props_exe,
diff --git a/vendor/libghostty-vt/src/build/XCFrameworkStep.zig b/vendor/libghostty-vt/src/build/XCFrameworkStep.zig
index 39f0f9ba..5f1b676f 100644
--- a/vendor/libghostty-vt/src/build/XCFrameworkStep.zig
+++ b/vendor/libghostty-vt/src/build/XCFrameworkStep.zig
@@ -63,8 +63,8 @@ pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep {
run.addArg("-output");
run.addArg(opts.out_path);
run.expectExitCode(0);
- _ = run.captureStdOut();
- _ = run.captureStdErr();
+ _ = run.captureStdOut(.{});
+ _ = run.captureStdErr(.{});
break :run run;
};
run_create.step.dependOn(&run_delete.step);
diff --git a/vendor/libghostty-vt/src/build/combine_archives.zig b/vendor/libghostty-vt/src/build/combine_archives.zig
index 04ec8e97..3df5ed0e 100644
--- a/vendor/libghostty-vt/src/build/combine_archives.zig
+++ b/vendor/libghostty-vt/src/build/combine_archives.zig
@@ -11,11 +11,10 @@
const std = @import("std");
-pub fn main() !void {
- var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
- const alloc = gpa.allocator();
+pub fn main(init: std.process.Init) !void {
+ const alloc = init.arena.allocator();
- const args = try std.process.argsAlloc(alloc);
+ const args = try init.minimal.args.toSlice(alloc);
if (args.len < 4) {
std.log.err("usage: combine_archives <zig_exe> <output> <input...>", .{});
std.process.exit(1);
@@ -37,19 +36,20 @@ pub fn main() !void {
}
try script.appendSlice(alloc, "SAVE\nEND\n");
- var child: std.process.Child = .init(&.{ zig_exe, "ar", "-M" }, alloc);
- child.stdin_behavior = .Pipe;
- child.stdout_behavior = .Inherit;
- child.stderr_behavior = .Inherit;
+ var child = try std.process.spawn(init.io, .{
+ .argv = &.{ zig_exe, "ar", "-M" },
+ .stdin = .pipe,
+ .stdout = .inherit,
+ .stderr = .inherit,
+ });
- try child.spawn();
- try child.stdin.?.writeAll(script.items);
- child.stdin.?.close();
+ try child.stdin.?.writeStreamingAll(init.io, script.items);
+ child.stdin.?.close(init.io);
child.stdin = null;
- const term = try child.wait();
- if (term.Exited != 0) {
- std.log.err("zig ar -M exited with code {d}", .{term.Exited});
+ const term = try child.wait(init.io);
+ if (term.exited != 0) {
+ std.log.err("zig ar -M exited with code {d}", .{term.exited});
std.process.exit(1);
}
}
diff --git a/vendor/libghostty-vt/src/build/docker/lib-c-docs/Dockerfile b/vendor/libghostty-vt/src/build/docker/lib-c-docs/Dockerfile
index a3cfdcc9..b5d17616 100644
--- a/vendor/libghostty-vt/src/build/docker/lib-c-docs/Dockerfile
+++ b/vendor/libghostty-vt/src/build/docker/lib-c-docs/Dockerfile
@@ -14,6 +14,7 @@ WORKDIR /ghostty
COPY include/ ./include/
COPY images/ ./images/
COPY dist/doxygen/ ./dist/doxygen/
+COPY src/terminal/c/types.schema.json ./src/terminal/c/types.schema.json
COPY example/ ./example/
COPY Doxyfile ./
COPY DoxygenLayout.xml ./
diff --git a/vendor/libghostty-vt/src/build/gtk.zig b/vendor/libghostty-vt/src/build/gtk.zig
index 7adb3cdb..1035367e 100644
--- a/vendor/libghostty-vt/src/build/gtk.zig
+++ b/vendor/libghostty-vt/src/build/gtk.zig
@@ -14,7 +14,7 @@ pub fn targets(b: *std.Build) Targets {
const output = b.runAllowFail(
&.{ "pkg-config", "--variable=targets", "gtk4" },
&code,
- .Ignore,
+ .ignore,
) catch return .{};
const x11 = std.mem.indexOf(u8, output, "x11") != null;
diff --git a/vendor/libghostty-vt/src/build/libsystem_override.sh b/vendor/libghostty-vt/src/build/libsystem_override.sh
new file mode 100755
index 00000000..14ed191b
--- /dev/null
+++ b/vendor/libghostty-vt/src/build/libsystem_override.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Darwin-only: rewrite a static archive so that consumers linking it bind
+# libc/libm symbols to Apple's libSystem instead of the bundled Zig
+# compiler-rt. This uses the Apple toolchain (xcrun, nmedit) and libSystem
+# semantics, so it must run on a Darwin host for a Darwin target.
+#
+# Background: our static library bundles Zig's compiler-rt, which defines
+# strong global implementations of libc/libm functions (memcpy, memmove,
+# memset, cos, sin, ...). When a consumer (e.g. the macOS app via the
+# XCFramework) links this archive, ld64 resolves those symbols from the
+# archive instead of libSystem, silently replacing Apple's highly
+# optimized implementations (_platform_memmove and friends, vectorized
+# libm) with compiler-rt's generic ones. We measured Zig 0.16 (LLVM 21)
+# compiler-rt memmove costing several percent of PTY throughput on
+# scroll-region workloads versus libSystem's.
+#
+# The mechanism is to localize (make non-external) the libSystem-provided
+# symbols defined by the compiler_rt.o archive member. This keeps
+# compiler_rt.o functional for the intrinsics that libSystem does NOT
+# provide (e.g. the f128 conversions ___extenddftf2/___extendxftf2, *q
+# math, sincos*) while letting every other archive member bind the
+# well-known libc/libm symbols to libSystem at final link.
+#
+# usage: libsystem_override.sh <input.a> <output.a>
+set -eu
+
+in="$1"
+out="$2"
+
+tmp="$(mktemp -d)"
+trap 'rm -rf "$tmp"' EXIT
+
+cp -f "$in" "$out"
+chmod u+w "$out"
+
+# The symbols to prefer from libSystem. Everything listed here is a
+# stable macOS export (verified against libSystem's link surface).
+# Notably NOT listed (not exported by libSystem): the *q (f128)
+# variants, sincos/sincosf/sincosl, and all ___-prefixed compiler
+# intrinsics except the fortify _chk wrappers below.
+cat >"$tmp/localize.txt" <<'EOF'
+_bcmp
+_memcmp
+_memcpy
+_memmove
+_memset
+_strlen
+___memcpy_chk
+___memmove_chk
+___memset_chk
+___strcat_chk
+___strcpy_chk
+_ceil
+_ceilf
+_ceill
+_cos
+_cosf
+_cosl
+_exp
+_exp2
+_exp2f
+_exp2l
+_expf
+_expl
+_fabs
+_fabsf
+_fabsl
+_floor
+_floorf
+_floorl
+_fma
+_fmaf
+_fmal
+_fmax
+_fmaxf
+_fmaxl
+_fmin
+_fminf
+_fminl
+_fmod
+_fmodf
+_fmodl
+_log
+_log10
+_log10f
+_log10l
+_log2
+_log2f
+_log2l
+_logf
+_logl
+_round
+_roundf
+_roundl
+_sin
+_sinf
+_sinl
+_sqrt
+_sqrtf
+_sqrtl
+_tan
+_tanf
+_tanl
+_trunc
+_truncf
+_truncl
+EOF
+
+cd "$tmp"
+
+xcrun ar x "$out" compiler_rt.o
+chmod 644 compiler_rt.o
+
+# nmedit takes a keep-list (-s): all current global definitions except
+# the ones we want to localize.
+xcrun nm -g compiler_rt.o | awk '$2 ~ /^[A-TV-Z]$/ {print $3}' | sort -u >all.txt
+sort -u localize.txt >loc.txt
+comm -23 all.txt loc.txt >keep.txt
+xcrun nmedit -s keep.txt compiler_rt.o
+
+xcrun ar r "$out" compiler_rt.o
+xcrun ranlib "$out" 2>/dev/null || true
diff --git a/vendor/libghostty-vt/src/build/mdgen/main_ghostty_1.zig b/vendor/libghostty-vt/src/build/mdgen/main_ghostty_1.zig
index 2bb413d9..e511768c 100644
--- a/vendor/libghostty-vt/src/build/mdgen/main_ghostty_1.zig
+++ b/vendor/libghostty-vt/src/build/mdgen/main_ghostty_1.zig
@@ -1,12 +1,11 @@
const std = @import("std");
const gen = @import("mdgen.zig");
-pub fn main() !void {
- var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
- const alloc = gpa.allocator();
+pub fn main(init: std.process.Init) !void {
+ const alloc = init.arena.allocator();
var buffer: [1024]u8 = undefined;
- var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer);
const writer = &stdout_writer.interface;
try gen.substitute(alloc, @embedFile("ghostty_1_header.md"), writer);
try gen.genActions(writer);
diff --git a/vendor/libghostty-vt/src/build/mdgen/main_ghostty_5.zig b/vendor/libghostty-vt/src/build/mdgen/main_ghostty_5.zig
index 2123b0bc..4f7c4882 100644
--- a/vendor/libghostty-vt/src/build/mdgen/main_ghostty_5.zig
+++ b/vendor/libghostty-vt/src/build/mdgen/main_ghostty_5.zig
@@ -1,12 +1,11 @@
const std = @import("std");
const gen = @import("mdgen.zig");
-pub fn main() !void {
- var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
- const alloc = gpa.allocator();
+pub fn main(init: std.process.Init) !void {
+ const alloc = init.arena.allocator();
var buffer: [1024]u8 = undefined;
- var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer);
const writer = &stdout_writer.interface;
try gen.substitute(alloc, @embedFile("ghostty_5_header.md"), writer);
try gen.genConfig(writer, false);
diff --git a/vendor/libghostty-vt/src/build/uucode_config.zig b/vendor/libghostty-vt/src/build/uucode_config.zig
index 2bb0d450..20c42551 100644
--- a/vendor/libghostty-vt/src/build/uucode_config.zig
+++ b/vendor/libghostty-vt/src/build/uucode_config.zig
@@ -1,109 +1,162 @@
const std = @import("std");
const assert = std.debug.assert;
const config = @import("config.zig");
-const config_x = @import("config.x.zig");
-const d = config.default;
-const wcwidth = config_x.wcwidth;
-const grapheme_break_no_control = config_x.grapheme_break_no_control;
const Allocator = std.mem.Allocator;
-fn computeWidth(
- alloc: std.mem.Allocator,
- cp: u21,
- data: anytype,
- backing: anytype,
- tracking: anytype,
-) Allocator.Error!void {
- _ = alloc;
- _ = cp;
- _ = backing;
- _ = tracking;
-
- // This condition is needed as Ghostty currently has a singular concept for
- // the `width` of a code point, while `uucode` splits the concept into
- // `wcwidth_standalone` and `wcwidth_zero_in_grapheme`. The two cases where
- // we want to use the `wcwidth_standalone` despite the code point occupying
- // zero width in a grapheme (`wcwidth_zero_in_grapheme`) are emoji
- // modifiers and prepend code points. For emoji modifiers we want to
- // support displaying them in isolation as color patches, and if prepend
- // characters were to be width 0 they would disappear from the output with
- // Ghostty's current width 0 handling. Future work will take advantage of
- // the new uucode `wcwidth_standalone` vs `wcwidth_zero_in_grapheme` split.
- if (data.wcwidth_zero_in_grapheme and !data.is_emoji_modifier and data.grapheme_break_no_control != .prepend) {
- data.width = 0;
- } else {
- data.width = @min(2, data.wcwidth_standalone);
- }
-}
-
-const width = config.Extension{
- .inputs = &.{
- "wcwidth_standalone",
- "wcwidth_zero_in_grapheme",
- "is_emoji_modifier",
- "grapheme_break_no_control",
+pub const fields = &config.mergeFields(config.fields, &.{
+ .{ .name = "width", .type = u2 },
+ .{ .name = "is_symbol", .type = bool },
+});
+pub const build_components = &config.mergeComponents(config.build_components, &.{
+ .{
+ .Impl = WidthComponent,
+ .inputs = &.{
+ "wcwidth_standalone",
+ "wcwidth_zero_in_grapheme",
+ "is_emoji_modifier",
+ "grapheme_break_no_control",
+ },
+ .fields = &.{"width"},
},
- .compute = &computeWidth,
- .fields = &.{
- .{ .name = "width", .type = u2 },
+ .{
+ .Impl = IsSymbolComponent,
+ .inputs = &.{ "block", "general_category" },
+ .fields = &.{"is_symbol"},
},
-};
+});
-fn computeIsSymbol(
- alloc: Allocator,
- cp: u21,
- data: anytype,
- backing: anytype,
- tracking: anytype,
-) Allocator.Error!void {
- _ = alloc;
- _ = cp;
- _ = backing;
- _ = tracking;
- const block = data.block;
- data.is_symbol = data.general_category == .other_private_use or
- block == .arrows or
- block == .dingbats or
- block == .emoticons or
- block == .miscellaneous_symbols or
- block == .enclosed_alphanumerics or
- block == .enclosed_alphanumeric_supplement or
- block == .miscellaneous_symbols_and_pictographs or
- block == .transport_and_map_symbols;
-}
-
-const is_symbol = config.Extension{
- .inputs = &.{ "block", "general_category" },
- .compute = &computeIsSymbol,
- .fields = &.{
- .{ .name = "is_symbol", .type = bool },
- },
-};
+pub const get_components: []const config.Component = &.{};
pub const tables = [_]config.Table{
.{
.name = "runtime",
- .extensions = &.{},
.fields = &.{
- d.field("is_emoji_presentation"),
- d.field("case_folding_full"),
+ "is_emoji_presentation",
+ "case_folding_full",
},
},
.{
- .name = "buildtime",
- .extensions = &.{
- wcwidth,
- grapheme_break_no_control,
- width,
- is_symbol,
+ // Fields that libvaxis needs that aren't included in the `runtime`
+ // table.
+ .name = "libvaxis_only",
+ .fields = &.{
+ "east_asian_width",
+ "general_category",
+ "grapheme_break",
},
+ },
+ .{
+ .name = "buildtime",
+ // Unpacked, because a packed table this size cannot be evaluated
+ // at comptime by Zig 0.16.0 and this one has to be, whether or not
+ // anything reads it.
+ //
+ // `uucode.get.FieldEnum` is built by walking `@TypeOf(tables)`, so
+ // instantiating anything that names a field -- `grapheme.Iterator`,
+ // among others -- materialises every table including this one. In a
+ // packed layout its rows are a `@bitCast` of a 32000 element `[_]u10`,
+ // and the compiler gives up on it two different ways depending on
+ // build options:
+ //
+ // tables.zig: error: unable to evaluate comptime expression
+ // thread panic: TODO implement writeToPackedMemory for more types
+ //
+ // Ghostty does not hit this, because its own uses of these fields go
+ // through the tables generated at build time rather than through
+ // `uucode.get`. A downstream pairing this config with libvaxis does:
+ // vaxis measures grapheme widths with `grapheme.Iterator`, so any
+ // program calling `Vaxis.render` fails to compile.
+ //
+ // The cost is the size of a table nothing reads at runtime. The fix
+ // belongs upstream in uucode or in the compiler; this is what makes
+ // the pairing build today.
+ .packing = .unpacked,
.fields = &.{
- width.field("width"),
- wcwidth.field("wcwidth_zero_in_grapheme"),
- grapheme_break_no_control.field("grapheme_break_no_control"),
- is_symbol.field("is_symbol"),
- d.field("is_emoji_vs_base"),
+ "width",
+ "wcwidth_zero_in_grapheme",
+ "grapheme_break_no_control",
+ "is_symbol",
+ "is_emoji_vs_base",
},
},
};
+
+const WidthComponent = struct {
+ pub fn build(
+ comptime InputRow: type,
+ comptime Row: type,
+ allocator: std.mem.Allocator,
+ io: std.Io,
+ inputs: config.MultiSlice(InputRow),
+ rows: *config.MultiSlice(Row),
+ backing: anytype,
+ tracking: anytype,
+ ) !void {
+ _ = allocator;
+ _ = io;
+ _ = backing;
+ _ = tracking;
+
+ rows.len = config.num_code_points;
+ const items = rows.items(.width);
+ const standalone = inputs.items(.wcwidth_standalone);
+ const zero_in_grapheme = inputs.items(.wcwidth_zero_in_grapheme);
+ const is_emoji_modifier = inputs.items(.is_emoji_modifier);
+ const grapheme_break_no_control = inputs.items(.grapheme_break_no_control);
+
+ // This condition is needed as Ghostty currently has a singular concept for
+ // the `width` of a code point, while `uucode` splits the concept into
+ // `wcwidth_standalone` and `wcwidth_zero_in_grapheme`. The two cases where
+ // we want to use the `wcwidth_standalone` despite the code point occupying
+ // zero width in a grapheme (`wcwidth_zero_in_grapheme`) are emoji
+ // modifiers and prepend code points. For emoji modifiers we want to
+ // support displaying them in isolation as color patches, and if prepend
+ // characters were to be width 0 they would disappear from the output with
+ // Ghostty's current width 0 handling. Future work will take advantage of
+ // the new uucode `wcwidth_standalone` vs `wcwidth_zero_in_grapheme` split.
+ for (0..config.num_code_points) |i| {
+ if (zero_in_grapheme[i] and !is_emoji_modifier[i] and grapheme_break_no_control[i] != .prepend) {
+ items[i] = 0;
+ } else {
+ items[i] = @min(2, standalone[i]);
+ }
+ }
+ }
+};
+
+const IsSymbolComponent = struct {
+ pub fn build(
+ comptime InputRow: type,
+ comptime Row: type,
+ allocator: std.mem.Allocator,
+ io: std.Io,
+ inputs: config.MultiSlice(InputRow),
+ rows: *config.MultiSlice(Row),
+ backing: anytype,
+ tracking: anytype,
+ ) !void {
+ _ = allocator;
+ _ = io;
+ _ = backing;
+ _ = tracking;
+
+ rows.len = config.num_code_points;
+ const items = rows.items(.is_symbol);
+ const block = inputs.items(.block);
+ const general_category = inputs.items(.general_category);
+
+ for (0..config.num_code_points) |i| {
+ items[i] =
+ general_category[i] == .other_private_use or
+ block[i] == .arrows or
+ block[i] == .dingbats or
+ block[i] == .emoticons or
+ block[i] == .miscellaneous_symbols or
+ block[i] == .enclosed_alphanumerics or
+ block[i] == .enclosed_alphanumeric_supplement or
+ block[i] == .miscellaneous_symbols_and_pictographs or
+ block[i] == .transport_and_map_symbols;
+ }
+ }
+};
diff --git a/vendor/libghostty-vt/src/build/wasm_patch_growable_table.zig b/vendor/libghostty-vt/src/build/wasm_patch_growable_table.zig
index c40c0a9c..555734ab 100644
--- a/vendor/libghostty-vt/src/build/wasm_patch_growable_table.zig
+++ b/vendor/libghostty-vt/src/build/wasm_patch_growable_table.zig
@@ -12,15 +12,13 @@ const std = @import("std");
const testing = std.testing;
const Allocator = std.mem.Allocator;
-pub fn main() !void {
+pub fn main(init: std.process.Init) !void {
// This is a one-off patcher, so we leak all our memory on purpose
// and let the OS clean it up when we exit.
- var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
- const alloc = gpa.allocator();
+ const alloc = init.arena.allocator();
// Parse args: program input output
- const args = try std.process.argsAlloc(alloc);
- defer std.process.argsFree(alloc, args);
+ const args = try init.minimal.args.toSlice(alloc);
if (args.len != 3) {
std.log.err("usage: wasm_growable_table <input.wasm> <output.wasm>", .{});
std.process.exit(1);
@@ -30,17 +28,18 @@ pub fn main() !void {
// Patch the file.
const output: []const u8 = try patchTableGrowable(
alloc,
- try std.fs.cwd().readFileAlloc(
- alloc,
+ try std.Io.Dir.cwd().readFileAlloc(
+ init.io,
args[1],
- std.math.maxInt(usize),
+ alloc,
+ .unlimited,
),
);
// Write our output
- const out_file = try std.fs.cwd().createFile(args[2], .{});
- defer out_file.close();
- try out_file.writeAll(output);
+ const out_file = try std.Io.Dir.cwd().createFile(init.io, args[2], .{});
+ defer out_file.close(init.io);
+ try out_file.writePositionalAll(init.io, output, 0);
}
/// Patch the WASM binary's table section to remove the maximum size
diff --git a/vendor/libghostty-vt/src/build/webgen/main_actions.zig b/vendor/libghostty-vt/src/build/webgen/main_actions.zig
index b0de6537..38cda3f7 100644
--- a/vendor/libghostty-vt/src/build/webgen/main_actions.zig
+++ b/vendor/libghostty-vt/src/build/webgen/main_actions.zig
@@ -1,9 +1,9 @@
const std = @import("std");
const helpgen_actions = @import("../../input/helpgen_actions.zig");
-pub fn main() !void {
+pub fn main(init: std.process.Init) !void {
var buffer: [2048]u8 = undefined;
- var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer);
const stdout = &stdout_writer.interface;
try helpgen_actions.generate(stdout, .markdown, true, std.heap.page_allocator);
}
diff --git a/vendor/libghostty-vt/src/build/webgen/main_commands.zig b/vendor/libghostty-vt/src/build/webgen/main_commands.zig
index 65f14452..c895948d 100644
--- a/vendor/libghostty-vt/src/build/webgen/main_commands.zig
+++ b/vendor/libghostty-vt/src/build/webgen/main_commands.zig
@@ -2,9 +2,9 @@ const std = @import("std");
const Action = @import("../../cli/ghostty.zig").Action;
const help_strings = @import("help_strings");
-pub fn main() !void {
+pub fn main(init: std.process.Init) !void {
var buffer: [2048]u8 = undefined;
- var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer);
const stdout = &stdout_writer.interface;
try genActions(stdout);
}
diff --git a/vendor/libghostty-vt/src/build/webgen/main_config.zig b/vendor/libghostty-vt/src/build/webgen/main_config.zig
index 1363fadc..82ecc950 100644
--- a/vendor/libghostty-vt/src/build/webgen/main_config.zig
+++ b/vendor/libghostty-vt/src/build/webgen/main_config.zig
@@ -2,9 +2,9 @@ const std = @import("std");
const Config = @import("../../config/Config.zig");
const help_strings = @import("help_strings");
-pub fn main() !void {
+pub fn main(init: std.process.Init) !void {
var buffer: [2048]u8 = undefined;
- var stdout_writer = std.fs.File.stdout().writer(&buffer);
+ var stdout_writer = std.Io.File.stdout().writer(init.io, &buffer);
const stdout = &stdout_writer.interface;
try genConfig(stdout);
}