build: add -Demit-macos-app

This commit is contained in:
Mitchell Hashimoto
2025-07-04 21:16:23 -07:00
parent 91ee75ae4d
commit 5fc0bbc58f
3 changed files with 95 additions and 64 deletions

140
build.zig
View File

@ -23,7 +23,22 @@ pub fn build(b: *std.Build) !void {
// Ghostty docs // Ghostty docs
const docs = try buildpkg.GhosttyDocs.init(b, &deps); const docs = try buildpkg.GhosttyDocs.init(b, &deps);
if (config.emit_docs) docs.install(); 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.
var wf = b.addWriteFiles();
const path = "share/man/.placeholder";
b.getInstallStep().dependOn(&b.addInstallFile(
wf.add(
path,
"emit-docs not true so no man pages",
),
path,
).step);
}
// Ghostty webdata // Ghostty webdata
const webdata = try buildpkg.GhosttyWebdata.init(b, &deps); const webdata = try buildpkg.GhosttyWebdata.init(b, &deps);
@ -43,15 +58,70 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step); check_step.dependOn(dist.install_step);
} }
// If we're not building libghostty, then install the exe and resources. // 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.app_runtime != .none) {
exe.install(); exe.install();
resources.install(); resources.install();
i18n.install(); i18n.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.
// Run runs the Ghostty exe. We only do this if we are building // We shouldn't have this guard but we don't currently
// an apprt. // 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();
i18n.install();
}
// Ghostty macOS app
const macos_app = try buildpkg.GhosttyXcodebuild.init(
b,
&config,
&xcframework,
);
if (config.emit_macos_app) {
macos_app.install();
}
}
// Run step
run: {
if (config.app_runtime != .none) {
const run_cmd = b.addRunArtifact(exe.exe); const run_cmd = b.addRunArtifact(exe.exe);
if (b.args) |args| run_cmd.addArgs(args); if (b.args) |args| run_cmd.addArgs(args);
@ -66,73 +136,27 @@ pub fn build(b: *std.Build) !void {
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step); run_step.dependOn(&run_cmd.step);
} break :run;
}
// 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) none: {
if (!config.target.result.os.tag.isDarwin()) {
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");
break :none;
} }
assert(config.target.result.os.tag.isDarwin()); assert(config.app_runtime == .none);
if (!config.emit_xcframework) break :none;
// Build the xcframework // On macOS we can run the macOS app. For "run" we always force
const xcframework = try buildpkg.GhosttyXCFramework.init( // a native-only build so that we can run as quickly as possible.
b, if (config.target.result.os.tag.isDarwin()) {
&deps,
config.xcframework_target,
);
xcframework.install();
// The xcframework build always installs resources because our
// macOS xcode project contains references to them.
resources.install();
i18n.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);
}
// Build our macOS app
{
const xcframework_native = try buildpkg.GhosttyXCFramework.init( const xcframework_native = try buildpkg.GhosttyXCFramework.init(
b, b,
&deps, &deps,
.native, .native,
); );
const macos_app_native_only = try buildpkg.GhosttyXcodebuild.init(
const app = try buildpkg.GhosttyXcodebuild.init(
b, b,
&config, &config,
&xcframework_native, &xcframework_native,
); );
// Add a run command that opens our mac app.
const run_step = b.step("run", "Run the app"); const run_step = b.step("run", "Run the app");
run_step.dependOn(&app.open.step); run_step.dependOn(&macos_app_native_only.open.step);
} }
} }

View File

@ -50,14 +50,15 @@ patch_rpath: ?[]const u8 = null,
/// Artifacts /// Artifacts
flatpak: bool = false, flatpak: bool = false,
emit_test_exe: bool = false,
emit_bench: bool = false, emit_bench: bool = false,
emit_helpgen: bool = false,
emit_docs: bool = false, emit_docs: bool = false,
emit_webdata: bool = false, emit_helpgen: bool = false,
emit_xcframework: bool = false, emit_macos_app: bool = false,
emit_terminfo: bool = false, emit_terminfo: bool = false,
emit_termcap: bool = false, emit_termcap: bool = false,
emit_test_exe: bool = false,
emit_xcframework: bool = false,
emit_webdata: bool = false,
/// Environmental properties /// Environmental properties
env: std.process.EnvMap, env: std.process.EnvMap,
@ -350,6 +351,12 @@ pub fn init(b: *std.Build) !Config {
!config.emit_test_exe and !config.emit_test_exe and
!config.emit_helpgen); !config.emit_helpgen);
config.emit_macos_app = b.option(
bool,
"emit-macos-app",
"Build and install the macOS app bundle.",
) orelse config.emit_xcframework;
//--------------------------------------------------------------- //---------------------------------------------------------------
// System Packages // System Packages

View File

@ -65,8 +65,8 @@ pub fn init(
build.expectExitCode(0); build.expectExitCode(0);
// Capture stdout/stderr so we don't pollute our zig build // Capture stdout/stderr so we don't pollute our zig build
_ = build.captureStdOut(); // _ = build.captureStdOut();
_ = build.captureStdErr(); // _ = build.captureStdErr();
break :build build; break :build build;
}; };