Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204const Ghostty = @This();
const std = @import("std");const builtin = @import("builtin");const RunStep = std.Build.Step.Run;const Config = @import("Config.zig");const Docs = @import("GhosttyDocs.zig");const I18n = @import("GhosttyI18n.zig");const Resources = @import("GhosttyResources.zig");const XCFramework = @import("GhosttyXCFramework.zig");
build: *std.Build.Step.Run,open: *std.Build.Step.Run,copy: *std.Build.Step.Run,xctest: *std.Build.Step.Run,
pub const Deps = struct { xcframework: *const XCFramework, docs: *const Docs, i18n: ?*const I18n, resources: *const Resources,};
pub fn init( b: *std.Build, config: *const Config, deps: Deps,) !Ghostty { const xc_config = switch (config.optimize) { .Debug => "Debug", .ReleaseSafe, .ReleaseSmall, .ReleaseFast, => "ReleaseLocal", };
const xc_arch: ?[]const u8 = switch (deps.xcframework.target) { // Universal is our default target, so we don't have to // add anything. .universal => null,
// Native we need to override the architecture in the Xcode // project with the -arch flag. .native => switch (builtin.cpu.arch) { .aarch64 => "arm64", .x86_64 => "x86_64", else => @panic("unsupported macOS arch"), }, };
const env = try std.process.getEnvMap(b.allocator); const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
// Our step to build the Ghostty macOS app. const build = build: { // External environment variables can mess up xcodebuild, so // we create a new empty environment. const env_map = try b.allocator.create(std.process.EnvMap); env_map.* = .init(b.allocator); if (env.get("PATH")) |v| try env_map.put("PATH", v);
const step = RunStep.create(b, "xcodebuild"); step.has_side_effects = true; step.cwd = b.path("macos"); step.env_map = env_map; step.addArgs(&.{ "xcodebuild", "-target", "Ghostty", "-configuration", xc_config, });
// If we have a specific architecture, we need to pass it // to xcodebuild. if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
// We need the xcframework deps.xcframework.addStepDependencies(&step.step);
// We also need all these resources because the xcode project // references them via symlinks. deps.resources.addStepDependencies(&step.step); if (deps.i18n) |v| v.addStepDependencies(&step.step); deps.docs.installDummy(&step.step);
// Expect success step.expectExitCode(0);
break :build step; };
const xctest = xctest: { const env_map = try b.allocator.create(std.process.EnvMap); env_map.* = .init(b.allocator); if (env.get("PATH")) |v| try env_map.put("PATH", v);
const step = RunStep.create(b, "xcodebuild test"); step.has_side_effects = true; step.cwd = b.path("macos"); step.env_map = env_map; step.addArgs(&.{ "xcodebuild", "test", "-scheme", "Ghostty", "-skip-testing", "GhosttyUITests", }); if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
// We need the xcframework deps.xcframework.addStepDependencies(&step.step);
// We also need all these resources because the xcode project // references them via symlinks. deps.resources.addStepDependencies(&step.step); if (deps.i18n) |v| v.addStepDependencies(&step.step); deps.docs.installDummy(&step.step);
// Expect success step.expectExitCode(0);
break :xctest step; };
// Our step to open the resulting Ghostty app. const open = open: { const disable_save_state = RunStep.create(b, "disable save state"); disable_save_state.has_side_effects = true; disable_save_state.addArgs(&.{ "/usr/libexec/PlistBuddy", "-c", // We'll have to change this to `Set` if we ever put this // into our Info.plist. "Add :NSQuitAlwaysKeepsWindows bool false", b.fmt("{s}/Contents/Info.plist", .{app_path}), }); disable_save_state.expectExitCode(0); disable_save_state.step.dependOn(&build.step);
const open = RunStep.create(b, "run Ghostty app"); open.has_side_effects = true; open.cwd = b.path(""); open.addArgs(&.{b.fmt( "{s}/Contents/MacOS/ghostty", .{app_path}, )});
// Open depends on the app open.step.dependOn(&build.step); open.step.dependOn(&disable_save_state.step);
// This overrides our default behavior and forces logs to show // up on stderr (in addition to the centralized macOS log). open.setEnvironmentVariable("GHOSTTY_LOG", "stderr,macos");
// Configure how we're launching open.setEnvironmentVariable("GHOSTTY_MAC_LAUNCH_SOURCE", "zig_run");
if (b.args) |args| { open.addArgs(args); }
break :open open; };
// Our step to copy the app bundle to the install path. // We have to use `cp -R` because there are symlinks in the // bundle. const copy = copy: { const step = RunStep.create(b, "copy app bundle"); step.addArgs(&.{ "cp", "-R" }); step.addFileArg(b.path(app_path)); step.addArg(b.fmt("{s}", .{b.install_path})); step.step.dependOn(&build.step); break :copy step; };
return .{ .build = build, .open = open, .copy = copy, .xctest = xctest, };}
pub fn install(self: *const Ghostty) void { const b = self.copy.step.owner; b.getInstallStep().dependOn(&self.copy.step);}
pub fn installXcframework(self: *const Ghostty) void { const b = self.build.step.owner; b.getInstallStep().dependOn(&self.build.step);}
pub fn addTestStepDependencies( self: *const Ghostty, other_step: *std.Build.Step,) void { other_step.dependOn(&self.xctest.step);}