libghostty: expose version information via build options and C API

Add version (std.SemanticVersion) to the terminal build options so that
the terminal module has access to the application version at comptime.
The add() function breaks it out into version_string, version_major,
version_minor, version_patch, and version_build terminal options.

On the C API side, five new GhosttyBuildInfo variants expose these
through ghostty_build_info(). String values use GhosttyString; numeric
values use size_t. When no build metadata is present, version_build
returns a zero-length string.

The c-vt-build-info example is updated to query and print all version
fields.
This commit is contained in:
Mitchell Hashimoto
2026-03-28 09:12:15 -07:00
parent 608bc7d24d
commit 8813261341
5 changed files with 134 additions and 0 deletions

View File

@@ -14,6 +14,28 @@ void query_build_info() {
printf("SIMD: %s\n", simd ? "enabled" : "disabled");
printf("Kitty graphics: %s\n", kitty_graphics ? "enabled" : "disabled");
printf("Tmux control mode: %s\n", tmux_control_mode ? "enabled" : "disabled");
GhosttyString version_string = {0};
size_t version_major = 0;
size_t version_minor = 0;
size_t version_patch = 0;
GhosttyString version_build = {0};
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_STRING, &version_string);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MAJOR, &version_major);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_MINOR, &version_minor);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_PATCH, &version_patch);
ghostty_build_info(GHOSTTY_BUILD_INFO_VERSION_BUILD, &version_build);
printf("Version: %.*s\n", (int)version_string.len, version_string.ptr);
printf("Version major: %zu\n", version_major);
printf("Version minor: %zu\n", version_minor);
printf("Version patch: %zu\n", version_patch);
if (version_build.len > 0) {
printf("Version build: %.*s\n", (int)version_build.len, version_build.ptr);
} else {
printf("Version build: (none)\n");
}
}
//! [build-info-query]

View File

@@ -23,6 +23,7 @@
* @{
*/
#include <stddef.h>
#include <stdbool.h>
#include <ghostty/vt/types.h>
@@ -77,6 +78,42 @@ typedef enum {
* Output type: GhosttyOptimizeMode *
*/
GHOSTTY_BUILD_INFO_OPTIMIZE = 4,
/**
* The full version string (e.g. "1.2.3" or "1.2.3-dev+abcdef").
*
* Output type: GhosttyString *
*/
GHOSTTY_BUILD_INFO_VERSION_STRING = 5,
/**
* The major version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_MAJOR = 6,
/**
* The minor version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_MINOR = 7,
/**
* The patch version number.
*
* Output type: size_t *
*/
GHOSTTY_BUILD_INFO_VERSION_PATCH = 8,
/**
* The build metadata string (e.g. commit hash). Has zero length if
* no build metadata is present.
*
* Output type: GhosttyString *
*/
GHOSTTY_BUILD_INFO_VERSION_BUILD = 9,
} GhosttyBuildInfo;
/**

View File

@@ -545,6 +545,7 @@ pub fn terminalOptions(self: *const Config) TerminalBuildOptions {
.simd = self.simd,
.oniguruma = true,
.c_abi = false,
.version = self.version,
.slow_runtime_safety = switch (self.optimize) {
.Debug => true,
.ReleaseSafe,

View File

@@ -28,7 +28,13 @@ pub const Options = struct {
/// Options.
c_abi: bool,
/// The version of the application.
version: std.SemanticVersion,
/// Add the required build options for the terminal module.
///
/// The memory referenced by self is expected to stick around (it isn't
/// copied), since we expect we're in a build environment.
pub fn add(
self: Options,
b: *std.Build,
@@ -45,6 +51,22 @@ pub const Options = struct {
opts.addOption(bool, "kitty_graphics", self.oniguruma);
opts.addOption(bool, "tmux_control_mode", self.oniguruma);
// Version information.
var buf: [1024]u8 = undefined;
opts.addOption(
[]const u8,
"version_string",
std.fmt.bufPrint(
&buf,
"{f}",
.{self.version},
) catch @panic("version string too long"),
);
opts.addOption(usize, "version_major", self.version.major);
opts.addOption(usize, "version_minor", self.version.minor);
opts.addOption(usize, "version_patch", self.version.patch);
opts.addOption(?[]const u8, "version_build", self.version.build);
m.addOptions("terminal_options", opts);
}
};

View File

@@ -21,6 +21,11 @@ pub const BuildInfo = enum(c_int) {
kitty_graphics = 2,
tmux_control_mode = 3,
optimize = 4,
version_string = 5,
version_major = 6,
version_minor = 7,
version_patch = 8,
version_build = 9,
/// Output type expected for querying the data of the given kind.
pub fn OutType(comptime self: BuildInfo) type {
@@ -28,6 +33,8 @@ pub const BuildInfo = enum(c_int) {
.invalid => void,
.simd, .kitty_graphics, .tmux_control_mode => bool,
.optimize => OptimizeMode,
.version_string, .version_build => lib.String,
.version_major, .version_minor, .version_patch => usize,
};
}
};
@@ -67,6 +74,17 @@ fn getTyped(
.ReleaseSmall => .release_small,
.ReleaseFast => .release_fast,
},
.version_string => out.* = .{ .ptr = build_options.version_string.ptr, .len = build_options.version_string.len },
.version_major => out.* = build_options.version_major,
.version_minor => out.* = build_options.version_minor,
.version_patch => out.* = build_options.version_patch,
.version_build => {
if (build_options.version_build) |b| {
out.* = .{ .ptr = b.ptr, .len = b.len };
} else {
out.* = .{ .ptr = "", .len = 0 };
}
},
}
return .success;
@@ -105,6 +123,40 @@ test "get optimize" {
}, value);
}
test "get version_string" {
const testing = std.testing;
var value: lib.String = undefined;
try testing.expectEqual(Result.success, get(.version_string, @ptrCast(&value)));
try testing.expect(value.len > 0);
}
test "get version_major" {
const testing = std.testing;
var value: usize = undefined;
try testing.expectEqual(Result.success, get(.version_major, @ptrCast(&value)));
try testing.expectEqual(build_options.version_major, value);
}
test "get version_minor" {
const testing = std.testing;
var value: usize = undefined;
try testing.expectEqual(Result.success, get(.version_minor, @ptrCast(&value)));
try testing.expectEqual(build_options.version_minor, value);
}
test "get version_patch" {
const testing = std.testing;
var value: usize = undefined;
try testing.expectEqual(Result.success, get(.version_patch, @ptrCast(&value)));
try testing.expectEqual(build_options.version_patch, value);
}
test "get version_build" {
const testing = std.testing;
var value: lib.String = undefined;
try testing.expectEqual(Result.success, get(.version_build, @ptrCast(&value)));
}
test "get invalid" {
try std.testing.expectEqual(Result.invalid_value, get(.invalid, null));
}