build: improve caching of macOS builds

This improves caching of builds to speed up `zig build` and
`zig build run` on macOS by avoiding unnecessary rebuilds of the Ghostty
xcframework.
This commit is contained in:
Mitchell Hashimoto
2025-07-07 07:18:58 -07:00
parent 292d89dbe2
commit b78434e741
2 changed files with 38 additions and 22 deletions

View File

@ -1,12 +1,15 @@
const GhosttyXCFramework = @This();
const std = @import("std");
const RunStep = std.Build.Step.Run;
const Config = @import("Config.zig");
const SharedDeps = @import("SharedDeps.zig");
const GhosttyLib = @import("GhosttyLib.zig");
const XCFrameworkStep = @import("XCFrameworkStep.zig");
xcframework: *XCFrameworkStep,
copy: *std.Build.Step,
target: Target,
pub const Target = enum { native, universal };
@ -58,7 +61,6 @@ pub fn init(
// it to the final app built with Swift.
const xcframework = XCFrameworkStep.create(b, .{
.name = "GhosttyKit",
.out_path = "macos/GhosttyKit.xcframework",
.libraries = switch (target) {
.universal => &.{
.{
@ -82,8 +84,32 @@ pub fn init(
},
});
// A command to copy the xcframework to the output directory,
// because the xcode project needs a stable path.
const copy = copy: {
const remove = RunStep.create(b, "remove old xcframework");
remove.has_side_effects = true;
remove.cwd = b.path("");
remove.addArgs(&.{
"rm",
"-rf",
"macos/GhosttyKit.xcframework",
});
remove.expectExitCode(0);
const step = RunStep.create(b, "copy xcframework");
step.has_side_effects = true;
step.cwd = b.path("");
step.addArgs(&.{ "cp", "-R" });
step.addDirectoryArg(xcframework.output);
step.addArg("macos/GhosttyKit.xcframework");
step.step.dependOn(&remove.step);
break :copy step;
};
return .{
.xcframework = xcframework,
.copy = &copy.step,
.target = target,
};
}
@ -97,5 +123,5 @@ pub fn addStepDependencies(
self: *const GhosttyXCFramework,
other_step: *std.Build.Step,
) void {
other_step.dependOn(self.xcframework.step);
other_step.dependOn(self.copy);
}

View File

@ -12,9 +12,6 @@ pub const Options = struct {
/// The name of the xcframework to create.
name: []const u8,
/// The path to write the framework
out_path: []const u8,
/// The libraries to bundle
libraries: []const Library,
};
@ -30,40 +27,33 @@ pub const Library = struct {
step: *Step,
output: LazyPath,
pub fn create(b: *std.Build, opts: Options) *XCFrameworkStep {
const self = b.allocator.create(XCFrameworkStep) catch @panic("OOM");
// We have to delete the old xcframework first since we're writing
// to a static path.
const run_delete = run: {
const run = RunStep.create(b, b.fmt("xcframework delete {s}", .{opts.name}));
run.has_side_effects = true;
run.addArgs(&.{ "rm", "-rf", opts.out_path });
break :run run;
};
// Then we run xcodebuild to create the framework.
const run_create = run: {
const run_create, const run_output = run: {
const run = RunStep.create(b, b.fmt("xcframework {s}", .{opts.name}));
run.has_side_effects = true;
run.addArgs(&.{ "xcodebuild", "-create-xcframework" });
for (opts.libraries) |lib| {
run.addArg("-library");
run.addFileArg(lib.library);
run.addArg("-headers");
run.addFileArg(lib.headers);
run.addDirectoryArg(lib.headers);
}
run.addArg("-output");
run.addArg(opts.out_path);
const output = run.addOutputDirectoryArg(b.fmt(
"{s}.xcframework",
.{opts.name},
));
run.expectExitCode(0);
_ = run.captureStdOut();
_ = run.captureStdErr();
break :run run;
break :run .{ run, output };
};
run_create.step.dependOn(&run_delete.step);
self.* = .{
.step = &run_create.step,
.output = run_output,
};
return self;