mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00

This adds two explicit `zig build` steps: `run-valgrind` and `test-valgrind` to run the Ghostty exe or tests under Valgrind, respectively. This simplifies the manual Valgrind calls in a few ways: 1. It automatically sets the CPU to baseline, which is a frequent and requirement for Valgrind on newer CPUs, and generally safe. 2. It sets up the rather complicated set of flags to call Valgrind with, importantly setting up our suppressions. 3. It enables pairing it with the typical and comfortable workflow of specifying extra args (with `--`) or flags like `-Dtest-filter` for tests.
261 lines
8.8 KiB
Zig
261 lines
8.8 KiB
Zig
const std = @import("std");
|
|
const assert = std.debug.assert;
|
|
const builtin = @import("builtin");
|
|
const buildpkg = @import("src/build/main.zig");
|
|
|
|
comptime {
|
|
buildpkg.requireZig("0.14.0");
|
|
}
|
|
|
|
pub fn build(b: *std.Build) !void {
|
|
// This defines all the available build options (e.g. `-D`).
|
|
const config = try buildpkg.Config.init(b);
|
|
const test_filter = b.option(
|
|
[]const u8,
|
|
"test-filter",
|
|
"Filter for test. Only applies to Zig tests.",
|
|
);
|
|
|
|
// All our steps which we'll hook up later. The steps are shown
|
|
// up here just so that they are more self-documenting.
|
|
const run_step = b.step("run", "Run the app");
|
|
const run_valgrind_step = b.step(
|
|
"run-valgrind",
|
|
"Run the app under valgrind",
|
|
);
|
|
const test_step = b.step("test", "Run tests");
|
|
const test_valgrind_step = b.step(
|
|
"test-valgrind",
|
|
"Run tests under valgrind",
|
|
);
|
|
const translations_step = b.step(
|
|
"update-translations",
|
|
"Update translation files",
|
|
);
|
|
|
|
// Ghostty resources like terminfo, shell integration, themes, etc.
|
|
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
|
const i18n = if (config.i18n) try buildpkg.GhosttyI18n.init(b, &config) else null;
|
|
|
|
// Ghostty dependencies used by many artifacts.
|
|
const deps = try buildpkg.SharedDeps.init(b, &config);
|
|
if (config.emit_helpgen) deps.help_strings.install();
|
|
|
|
// Ghostty executable, the actual runnable Ghostty program.
|
|
const exe = try buildpkg.GhosttyExe.init(b, &config, &deps);
|
|
|
|
// Ghostty docs
|
|
const docs = try buildpkg.GhosttyDocs.init(b, &deps);
|
|
if (config.emit_docs) {
|
|
docs.install();
|
|
} else if (config.target.result.os.tag.isDarwin()) {
|
|
// If we aren't emitting docs we need to emit a placeholder so
|
|
// our macOS xcodeproject builds since it expects the `share/man`
|
|
// directory to exist to copy into the app bundle.
|
|
docs.installDummy(b.getInstallStep());
|
|
}
|
|
|
|
// Ghostty webdata
|
|
const webdata = try buildpkg.GhosttyWebdata.init(b, &deps);
|
|
if (config.emit_webdata) webdata.install();
|
|
|
|
// Ghostty bench tools
|
|
const bench = try buildpkg.GhosttyBench.init(b, &deps);
|
|
if (config.emit_bench) bench.install();
|
|
|
|
// Ghostty dist tarball
|
|
const dist = try buildpkg.GhosttyDist.init(b, &config);
|
|
{
|
|
const step = b.step("dist", "Build the dist tarball");
|
|
step.dependOn(dist.install_step);
|
|
const check_step = b.step("distcheck", "Install and validate the dist tarball");
|
|
check_step.dependOn(dist.check_step);
|
|
check_step.dependOn(dist.install_step);
|
|
}
|
|
|
|
// libghostty
|
|
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
|
|
b,
|
|
&deps,
|
|
);
|
|
const libghostty_static = try buildpkg.GhosttyLib.initStatic(
|
|
b,
|
|
&deps,
|
|
);
|
|
|
|
// Runtime "none" is libghostty, anything else is an executable.
|
|
if (config.app_runtime != .none) {
|
|
if (config.emit_exe) {
|
|
exe.install();
|
|
resources.install();
|
|
if (i18n) |v| v.install();
|
|
}
|
|
} else {
|
|
// Libghostty
|
|
//
|
|
// Note: libghostty is not stable for general purpose use. It is used
|
|
// heavily by Ghostty on macOS but it isn't built to be reusable yet.
|
|
// As such, these build steps are lacking. For example, the Darwin
|
|
// build only produces an xcframework.
|
|
|
|
// We shouldn't have this guard but we don't currently
|
|
// build on macOS this way ironically so we need to fix that.
|
|
if (!config.target.result.os.tag.isDarwin()) {
|
|
libghostty_shared.installHeader(); // Only need one header
|
|
libghostty_shared.install("libghostty.so");
|
|
libghostty_static.install("libghostty.a");
|
|
}
|
|
}
|
|
|
|
// macOS only artifacts. These will error if they're initialized for
|
|
// other targets.
|
|
if (config.target.result.os.tag.isDarwin()) {
|
|
// Ghostty xcframework
|
|
const xcframework = try buildpkg.GhosttyXCFramework.init(
|
|
b,
|
|
&deps,
|
|
config.xcframework_target,
|
|
);
|
|
if (config.emit_xcframework) {
|
|
xcframework.install();
|
|
|
|
// The xcframework build always installs resources because our
|
|
// macOS xcode project contains references to them.
|
|
resources.install();
|
|
if (i18n) |v| v.install();
|
|
}
|
|
|
|
// Ghostty macOS app
|
|
const macos_app = try buildpkg.GhosttyXcodebuild.init(
|
|
b,
|
|
&config,
|
|
.{
|
|
.xcframework = &xcframework,
|
|
.docs = &docs,
|
|
.i18n = if (i18n) |v| &v else null,
|
|
.resources = &resources,
|
|
},
|
|
);
|
|
if (config.emit_macos_app) {
|
|
macos_app.install();
|
|
}
|
|
}
|
|
|
|
// Run step
|
|
run: {
|
|
if (config.app_runtime != .none) {
|
|
const run_cmd = b.addRunArtifact(exe.exe);
|
|
if (b.args) |args| run_cmd.addArgs(args);
|
|
|
|
// Set the proper resources dir so things like shell integration
|
|
// work correctly. If we're running `zig build run` in Ghostty,
|
|
// this also ensures it overwrites the release one with our debug
|
|
// build.
|
|
run_cmd.setEnvironmentVariable(
|
|
"GHOSTTY_RESOURCES_DIR",
|
|
b.getInstallPath(.prefix, "share/ghostty"),
|
|
);
|
|
|
|
run_step.dependOn(&run_cmd.step);
|
|
break :run;
|
|
}
|
|
|
|
assert(config.app_runtime == .none);
|
|
|
|
// On macOS we can run the macOS app. For "run" we always force
|
|
// a native-only build so that we can run as quickly as possible.
|
|
if (config.target.result.os.tag.isDarwin()) {
|
|
const xcframework_native = try buildpkg.GhosttyXCFramework.init(
|
|
b,
|
|
&deps,
|
|
.native,
|
|
);
|
|
const macos_app_native_only = try buildpkg.GhosttyXcodebuild.init(
|
|
b,
|
|
&config,
|
|
.{
|
|
.xcframework = &xcframework_native,
|
|
.docs = &docs,
|
|
.i18n = if (i18n) |v| &v else null,
|
|
.resources = &resources,
|
|
},
|
|
);
|
|
|
|
// Run uses the native macOS app
|
|
run_step.dependOn(&macos_app_native_only.open.step);
|
|
|
|
// If we have no test filters, install the tests too
|
|
if (test_filter == null) {
|
|
macos_app_native_only.addTestStepDependencies(test_step);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Valgrind
|
|
if (config.app_runtime != .none) {
|
|
// We need to rebuild Ghostty with a baseline CPU target.
|
|
const valgrind_exe = exe: {
|
|
var valgrind_config = config;
|
|
valgrind_config.target = valgrind_config.baselineTarget();
|
|
break :exe try buildpkg.GhosttyExe.init(
|
|
b,
|
|
&valgrind_config,
|
|
&deps,
|
|
);
|
|
};
|
|
|
|
const run_cmd = b.addSystemCommand(&.{
|
|
"valgrind",
|
|
"--leak-check=full",
|
|
"--num-callers=50",
|
|
b.fmt("--suppressions={s}", .{b.pathFromRoot("valgrind.supp")}),
|
|
"--gen-suppressions=all",
|
|
});
|
|
run_cmd.addArtifactArg(valgrind_exe.exe);
|
|
if (b.args) |args| run_cmd.addArgs(args);
|
|
run_valgrind_step.dependOn(&run_cmd.step);
|
|
}
|
|
|
|
// Tests
|
|
{
|
|
const test_exe = b.addTest(.{
|
|
.name = "ghostty-test",
|
|
.filters = if (test_filter) |v| &.{v} else &.{},
|
|
.root_module = b.createModule(.{
|
|
.root_source_file = b.path("src/main.zig"),
|
|
.target = config.baselineTarget(),
|
|
.optimize = .Debug,
|
|
.strip = false,
|
|
.omit_frame_pointer = false,
|
|
.unwind_tables = .sync,
|
|
}),
|
|
});
|
|
|
|
if (config.emit_test_exe) b.installArtifact(test_exe);
|
|
_ = try deps.add(test_exe);
|
|
|
|
// Normal test running
|
|
const test_run = b.addRunArtifact(test_exe);
|
|
test_step.dependOn(&test_run.step);
|
|
|
|
// Valgrind test running
|
|
const valgrind_run = b.addSystemCommand(&.{
|
|
"valgrind",
|
|
"--leak-check=full",
|
|
"--num-callers=50",
|
|
b.fmt("--suppressions={s}", .{b.pathFromRoot("valgrind.supp")}),
|
|
"--gen-suppressions=all",
|
|
});
|
|
valgrind_run.addArtifactArg(test_exe);
|
|
test_valgrind_step.dependOn(&valgrind_run.step);
|
|
}
|
|
|
|
// update-translations does what it sounds like and updates the "pot"
|
|
// files. These should be committed to the repo.
|
|
if (i18n) |v| {
|
|
translations_step.dependOn(v.update_step);
|
|
} else {
|
|
try translations_step.addError("cannot update translations when i18n is disabled", .{});
|
|
}
|
|
}
|