ghostty/build.zig
Mitchell Hashimoto 8bf5c4ed7f This is a major refactor of build.zig.
The major idea behind the refactor is to split the `build.zig` file up into
distinct `src/build/*.zig` files. By doing so, we can improve readability of
the primary `build.zig` while also enabling better reuse of steps. Our
`build.zig` is now less than 150 lines of code (of course, it calls into a lot
more lines but they're neatly organized now).

Improvements:

  * `build.zig` is less than 150 lines of readable code.
  * Help strings and unicode table generators are only run once when multiple
    artifacts are built since the results are the same regardless of target.
  * Metal lib is only built once per architecture (rather than once per artifact)
  * Resources (shell integration, terminfo, etc.) and docs are only
    built/installed for artifacts that need them

Breaking changes:

  * Removed broken wasm build (@gabydd will re-add)
  * Removed conformance files, shell scripts are better and we don't run
    these anymore
  * Removed macOS app bundle creation, we don't use this anymore since we
    use Xcode

## Some History

Our `build.zig` hasn't been significantly refactored since the project started,
when Zig was _version 0.10_. Since then, the build system has changed
significantly. We've only ever duct taped the `build.zig` as we needed to
support new Zig versions, new features, etc. It was a mess.

The major improvement is adapting the entire Ghostty `build.zig` to the Step
and LazyPath changes introduced way back in Zig 0.12. This lets us better take
advantage of parallelism and the dependency graph so that steps are only
executed as they're needed.

As such, you can see in the build.zig that we initialize a lot of things, but
unless a final target (i.e. install, run) references those steps, _they'll
never be executed_. This lets us clean up a lot.
2025-01-07 19:47:43 -08:00

121 lines
4.3 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const buildpkg = @import("src/build/main.zig");
comptime {
// This is the required Zig version for building this project. We allow
// any patch version but the major and minor must match exactly.
const required_zig = "0.13.0";
// Fail compilation if the current Zig version doesn't meet requirements.
const current_vsn = builtin.zig_version;
const required_vsn = std.SemanticVersion.parse(required_zig) catch unreachable;
if (current_vsn.major != required_vsn.major or
current_vsn.minor != required_vsn.minor)
{
@compileError(std.fmt.comptimePrint(
"Your Zig version v{} does not meet the required build version of v{}",
.{ current_vsn, required_vsn },
));
}
}
pub fn build(b: *std.Build) !void {
const config = try buildpkg.Config.init(b);
// Ghostty resources like terminfo, shell integration, themes, etc.
const resources = try buildpkg.GhosttyResources.init(b, &config);
// Ghostty dependencies used by many artifacts.
const deps = try buildpkg.SharedDeps.init(b, &config);
const exe = try buildpkg.GhosttyExe.init(b, &config, &deps);
if (config.emit_helpgen) deps.help_strings.install();
// Ghostty docs
if (config.emit_docs) {
const docs = try buildpkg.GhosttyDocs.init(b, &deps);
docs.install();
}
// Ghostty webdata
if (config.emit_webdata) {
const webdata = try buildpkg.GhosttyWebdata.init(b, &deps);
webdata.install();
}
// Ghostty bench tools
if (config.emit_bench) {
const bench = try buildpkg.GhosttyBench.init(b, &deps);
bench.install();
}
// If we're not building libghostty, then install the exe and resources.
if (config.app_runtime != .none) {
exe.install();
resources.install();
}
// 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.
if (config.app_runtime == .none) {
if (config.target.result.isDarwin()) darwin: {
if (!config.emit_xcframework) break :darwin;
// Build the xcframework
const xcframework = try buildpkg.GhosttyXCFramework.init(b, &deps);
xcframework.install();
// The xcframework build always installs resources because our
// macOS xcode project contains references to them.
resources.install();
// If we aren't emitting docs we need to emit a placeholder so
// our macOS xcodeproject builds.
if (!config.emit_docs) {
var wf = b.addWriteFiles();
const path = "share/man/.placeholder";
const placeholder = wf.add(path, "emit-docs not true so no man pages");
b.getInstallStep().dependOn(&b.addInstallFile(placeholder, path).step);
}
} else {
const libghostty_shared = try buildpkg.GhosttyLib.initShared(b, &deps);
const libghostty_static = try buildpkg.GhosttyLib.initStatic(b, &deps);
libghostty_shared.installHeader(); // Only need one header
libghostty_shared.install("libghostty.so");
libghostty_static.install("libghostty.a");
}
}
// Run runs the Ghostty exe
{
const run_cmd = b.addRunArtifact(exe.exe);
if (b.args) |args| run_cmd.addArgs(args);
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
// Tests
{
const test_step = b.step("test", "Run all tests");
const test_filter = b.option([]const u8, "test-filter", "Filter for test");
const test_exe = b.addTest(.{
.name = "ghostty-test",
.root_source_file = b.path("src/main.zig"),
.target = config.target,
.filter = test_filter,
});
{
if (config.emit_test_exe) b.installArtifact(test_exe);
_ = try deps.add(test_exe);
const test_run = b.addRunArtifact(test_exe);
test_step.dependOn(&test_run.step);
}
}
}