From 4d09f8dba663cd0cbf00551ffef0e11edd4bec2a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 13 Feb 2023 09:36:11 -0800 Subject: [PATCH] build: add SwiftBuildStep to run "swift build" --- .gitignore | 1 + build.zig | 16 +++---- src/build/SwiftBuildStep.zig | 89 ++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 src/build/SwiftBuildStep.zig diff --git a/.gitignore b/.gitignore index 83d1031dc..2fef0f117 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store .direnv/ zig-cache/ zig-out/ diff --git a/build.zig b/build.zig index 4d340a61a..6dbd83ee3 100644 --- a/build.zig +++ b/build.zig @@ -21,6 +21,7 @@ const zlib = @import("pkg/zlib/build.zig"); const tracylib = @import("pkg/tracy/build.zig"); const system_sdk = @import("vendor/mach/libs/glfw/system_sdk.zig"); const WasmTarget = @import("src/os/wasm/target.zig").Target; +const SwiftBuildStep = @import("src/build/SwiftBuildStep.zig"); // Do a comptime Zig version requirement. The required Zig version is // somewhat arbitrary: it is meant to be a version that we feel works well, @@ -133,18 +134,17 @@ pub fn build(b: *std.build.Builder) !void { // Mac App based on Swift { - // Build the swift binary - // - // TODO: - // - debug vs release modes) - // - arch (arm64 vs x86_64) - const swift_build = b.addSystemCommand(&.{ "swift", "build" }); - swift_build.cwd = "macos"; + const swift_build = SwiftBuildStep.create(b, .{ + .product = "Ghostty", + .target = target, + .optimize = mode, + .cwd = .{ .path = "macos" }, + }); const macapp = b.step("macapp", "Build macOS app"); macapp.dependOn(&swift_build.step); macapp.dependOn(&b.addInstallFileWithDir( - .{ .path = "macos/.build/arm64-apple-macosx/debug/Ghostty" }, + .{ .generated = &swift_build.bin_path }, .prefix, "Ghostty.app/Contents/MacOS/ghostty", ).step); diff --git a/src/build/SwiftBuildStep.zig b/src/build/SwiftBuildStep.zig new file mode 100644 index 000000000..ec8cc04dd --- /dev/null +++ b/src/build/SwiftBuildStep.zig @@ -0,0 +1,89 @@ +//! A zig builder step that runs "swift build" in the context of +//! a Swift project managed with SwiftPM. This is primarily meant to build +//! executables currently since that is what we build. +const SwiftBuildStep = @This(); + +const std = @import("std"); +const Step = std.build.Step; +const GeneratedFile = std.build.GeneratedFile; + +pub const Options = struct { + /// The product name. This is required to determine the output path + /// as well. + product: []const u8, + target: std.zig.CrossTarget, + optimize: std.builtin.Mode, + + /// Directory where Package.swift is + cwd: ?std.build.FileSource = null, + + /// Configuration to build the swift package with. This will default + /// to "debug" for debug modes and "release" for all other Zig build + /// modes. + configuration: ?[]const u8 = null, +}; + +step: Step, +builder: *std.build.Builder, + +/// The generated binary. +bin_path: GeneratedFile, + +/// See Options +product: []const u8, +target: std.zig.CrossTarget, +optimize: std.builtin.Mode, +cwd: ?std.build.FileSource = null, +configuration: ?[]const u8 = null, + +pub fn create(builder: *std.build.Builder, opts: Options) *SwiftBuildStep { + const self = builder.allocator.create(SwiftBuildStep) catch @panic("OOM"); + self.* = .{ + .step = Step.init(.custom, "swift build", builder.allocator, make), + .builder = builder, + .bin_path = .{ .step = &self.step }, + .product = opts.product, + .target = opts.target, + .optimize = opts.optimize, + .cwd = opts.cwd, + .configuration = opts.configuration, + }; + return self; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(SwiftBuildStep, "step", step); + + const configuration = self.configuration orelse switch (self.optimize) { + .Debug => "debug", + else => "release", + }; + + const arch = switch (self.target.getCpuArch()) { + .x86_64 => "x86_64", + .aarch64 => "arm64", + else => return error.UnsupportedSwiftArch, + }; + + // We use a RunStep here to ease our configuration. + const run = std.build.RunStep.create(self.builder, "run swift build"); + run.cwd = if (self.cwd) |cwd| cwd.getPath(self.builder) else null; + run.addArgs(&.{ + "swift", "build", + "--product", self.product, + "-c", configuration, + "--arch", arch, + }); + try run.step.make(); + + // Determine our generated path + self.bin_path.path = self.builder.fmt( + "{s}/.build/{s}-apple-macosx/{s}/{s}", + .{ + run.cwd orelse ".", + arch, + configuration, + self.product, + }, + ); +}