Skip to content

Commit f614fb7

Browse files
committed
build: use build options to configure terminal C ABI mode
Fixes various issues: - C ABI detection was faulty, which caused some Zig programs to use the C ABI mode and some C programs not to. Let's be explicit. - Unit tests now tests C ABI mode. - Build binary no longer rebuilds on any terminal change (a regression). - Zig programs can choose to depend on the C ABI version of the terminal lib by using the `ghostty-vt-c` module.
1 parent 08ecbe3 commit f614fb7

File tree

9 files changed

+72
-24
lines changed

9 files changed

+72
-24
lines changed

build.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,15 @@ pub fn build(b: *std.Build) !void {
255255
});
256256
const mod_vt_test_run = b.addRunArtifact(mod_vt_test);
257257
test_lib_vt_step.dependOn(&mod_vt_test_run.step);
258+
259+
const mod_vt_c_test = b.addTest(.{
260+
.root_module = mod.vt_c,
261+
.target = config.target,
262+
.optimize = config.optimize,
263+
.filters = test_filters,
264+
});
265+
const mod_vt_c_test_run = b.addRunArtifact(mod_vt_c_test);
266+
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
258267
}
259268

260269
// Tests

src/build/Config.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ pub fn terminalOptions(self: *const Config) TerminalBuildOptions {
498498
.artifact = .ghostty,
499499
.simd = self.simd,
500500
.oniguruma = true,
501+
.c_abi = false,
501502
.slow_runtime_safety = switch (self.optimize) {
502503
.Debug => true,
503504
.ReleaseSafe,

src/build/GhosttyLibVt.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub fn initShared(
2626
const target = zig.vt.resolved_target.?;
2727
const lib = b.addSharedLibrary(.{
2828
.name = "ghostty-vt",
29-
.root_module = zig.vt,
29+
.root_module = zig.vt_c,
3030
});
3131
lib.installHeader(
3232
b.path("include/ghostty/vt.h"),

src/build/GhosttyZig.zig

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,17 @@ const GhosttyZig = @This();
55
const std = @import("std");
66
const Config = @import("Config.zig");
77
const SharedDeps = @import("SharedDeps.zig");
8+
const TerminalBuildOptions = @import("../terminal/build_options.zig").Options;
89

10+
/// The `_c`-suffixed modules are built with the C ABI enabled.
911
vt: *std.Build.Module,
12+
vt_c: *std.Build.Module,
1013

1114
pub fn init(
1215
b: *std.Build,
1316
cfg: *const Config,
1417
deps: *const SharedDeps,
1518
) !GhosttyZig {
16-
// General build options
17-
const general_options = b.addOptions();
18-
try cfg.addOptions(general_options);
19-
2019
// Terminal module build options
2120
var vt_options = cfg.terminalOptions();
2221
vt_options.artifact = .lib;
@@ -25,7 +24,41 @@ pub fn init(
2524
// conditionally do this.
2625
vt_options.oniguruma = false;
2726

28-
const vt = b.addModule("ghostty-vt", .{
27+
return .{
28+
.vt = try initVt(
29+
"ghostty-vt",
30+
b,
31+
cfg,
32+
deps,
33+
vt_options,
34+
),
35+
36+
.vt_c = try initVt(
37+
"ghostty-vt-c",
38+
b,
39+
cfg,
40+
deps,
41+
options: {
42+
var dup = vt_options;
43+
dup.c_abi = true;
44+
break :options dup;
45+
},
46+
),
47+
};
48+
}
49+
50+
fn initVt(
51+
name: []const u8,
52+
b: *std.Build,
53+
cfg: *const Config,
54+
deps: *const SharedDeps,
55+
vt_options: TerminalBuildOptions,
56+
) !*std.Build.Module {
57+
// General build options
58+
const general_options = b.addOptions();
59+
try cfg.addOptions(general_options);
60+
61+
const vt = b.addModule(name, .{
2962
.root_source_file = b.path("src/lib_vt.zig"),
3063
.target = cfg.target,
3164
.optimize = cfg.optimize,
@@ -45,5 +78,5 @@ pub fn init(
4578
try SharedDeps.addSimd(b, vt, null);
4679
}
4780

48-
return .{ .vt = vt };
81+
return vt;
4982
}

src/lib_vt.zig

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//! by thousands of users for years. However, the API itself (functions,
88
//! types, etc.) may change without warning. We're working on stabilizing
99
//! this in the future.
10+
const lib = @This();
1011

1112
// The public API below reproduces a lot of terminal/main.zig but
1213
// is separate because (1) we need our root file to be in `src/`
@@ -68,7 +69,7 @@ pub const Attribute = terminal.Attribute;
6869
comptime {
6970
// If we're building the C library (vs. the Zig module) then
7071
// we want to reference the C API so that it gets exported.
71-
if (terminal.is_c_lib) {
72+
if (@import("root") == lib) {
7273
const c = terminal.c_api;
7374
@export(&c.osc_new, .{ .name = "ghostty_osc_new" });
7475
@export(&c.osc_free, .{ .name = "ghostty_osc_free" });
@@ -81,8 +82,8 @@ comptime {
8182

8283
test {
8384
_ = terminal;
84-
85-
// Tests always test the C API and shared C functions
86-
_ = terminal.c_api;
8785
_ = @import("lib/main.zig");
86+
if (comptime terminal.options.c_abi) {
87+
_ = terminal.c_api;
88+
}
8889
}

src/terminal/build_options.zig

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
const std = @import("std");
22

3-
/// True if we're building the C library libghostty-vt.
4-
pub const is_c_lib = @import("root") == @import("../lib_vt.zig");
5-
3+
/// Options set by Zig build.zig and exposed via `terminal_options`.
64
pub const Options = struct {
75
/// The target artifact to build. This will gate some functionality.
86
artifact: Artifact,
@@ -26,6 +24,10 @@ pub const Options = struct {
2624
/// generally be disabled in production builds.
2725
slow_runtime_safety: bool,
2826

27+
/// Force C ABI mode on or off. If not set, then it will be set based on
28+
/// Options.
29+
c_abi: bool,
30+
2931
/// Add the required build options for the terminal module.
3032
pub fn add(
3133
self: Options,
@@ -34,6 +36,7 @@ pub const Options = struct {
3436
) void {
3537
const opts = b.addOptions();
3638
opts.addOption(Artifact, "artifact", self.artifact);
39+
opts.addOption(bool, "c_abi", self.c_abi);
3740
opts.addOption(bool, "oniguruma", self.oniguruma);
3841
opts.addOption(bool, "simd", self.simd);
3942
opts.addOption(bool, "slow_runtime_safety", self.slow_runtime_safety);

src/terminal/c/osc.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ test "command type" {
7373
));
7474
defer free(p);
7575

76-
p.next('0');
77-
p.next(';');
78-
p.next('a');
79-
const cmd = p.end(0);
76+
next(p, '0');
77+
next(p, ';');
78+
next(p, 'a');
79+
const cmd = end(p, 0);
8080
try testing.expectEqual(.change_window_title, commandType(cmd));
8181
}

src/terminal/main.zig

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const builtin = @import("builtin");
2-
const build_options = @import("terminal_options");
32

43
const charsets = @import("charsets.zig");
54
const sanitize = @import("sanitize.zig");
@@ -21,7 +20,7 @@ pub const page = @import("page.zig");
2120
pub const parse_table = @import("parse_table.zig");
2221
pub const search = @import("search.zig");
2322
pub const size = @import("size.zig");
24-
pub const tmux = if (build_options.tmux_control_mode) @import("tmux.zig") else struct {};
23+
pub const tmux = if (options.tmux_control_mode) @import("tmux.zig") else struct {};
2524
pub const x11_color = @import("x11_color.zig");
2625

2726
pub const Charset = charsets.Charset;
@@ -62,9 +61,11 @@ pub const Attribute = sgr.Attribute;
6261

6362
pub const isSafePaste = sanitize.isSafePaste;
6463

64+
pub const Options = @import("build_options.zig").Options;
65+
pub const options = @import("terminal_options");
66+
6567
/// This is set to true when we're building the C library.
66-
pub const is_c_lib = @import("build_options.zig").is_c_lib;
67-
pub const c_api = if (is_c_lib) @import("c/main.zig") else void;
68+
pub const c_api = if (options.c_abi) @import("c/main.zig") else void;
6869

6970
test {
7071
@import("std").testing.refAllDecls(@This());

src/terminal/osc.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ const osc = @This();
77

88
const std = @import("std");
99
const builtin = @import("builtin");
10+
const build_options = @import("terminal_options");
1011
const mem = std.mem;
1112
const assert = std.debug.assert;
1213
const Allocator = mem.Allocator;
1314
const LibEnum = @import("../lib/enum.zig").Enum;
14-
const is_c_lib = @import("build_options.zig").is_c_lib;
1515
const RGB = @import("color.zig").RGB;
1616
const kitty_color = @import("kitty/color.zig");
1717
const osc_color = @import("osc/color.zig");
@@ -175,7 +175,7 @@ pub const Command = union(Key) {
175175
conemu_guimacro: []const u8,
176176

177177
pub const Key = LibEnum(
178-
if (is_c_lib) .c else .zig,
178+
if (build_options.c_abi) .c else .zig,
179179
// NOTE: Order matters, see LibEnum documentation.
180180
&.{
181181
"invalid",

0 commit comments

Comments
 (0)