mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
build: zig build test
runs Xcode tests on macOS
Related to #7879 This commit updates `zig build test` to run Xcode tests, too. These run in parallel to the Zig tests, so they don't add any time to the test. The Xcode tests will _not_ run when: (1) the target is not macOS, or (2) the `-Dtest-filter` option is non-empty. This makes it so that this change doesn't affect non-macOS and doesn't affect the general dev cycle because you usually will run `-Dtest-filter` when developing a core feature. I didn't add a step to only run Xcode tests because I find that when I'm working in Xcode I'm probably going to run the tests from there anyways. The integration with `zig build test` is just a convenience, especially around CI. Speaking of CI, this change also makes it so this will run in CI.
This commit is contained in:
33
build.zig
33
build.zig
@ -8,7 +8,22 @@ comptime {
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
// This defines all the available build options (e.g. `-D`).
|
||||
const config = try buildpkg.Config.init(b);
|
||||
const test_filter = b.option(
|
||||
[]const u8,
|
||||
"test-filter",
|
||||
"Filter for test. Only applies to Zig tests.",
|
||||
);
|
||||
|
||||
// All our steps which we'll hook up later. The steps are shown
|
||||
// up here just so that they are more self-documenting.
|
||||
const run_step = b.step("run", "Run the app");
|
||||
const test_step = b.step("test", "Run all tests");
|
||||
const translations_step = b.step(
|
||||
"update-translations",
|
||||
"Update translation files",
|
||||
);
|
||||
|
||||
// Ghostty resources like terminfo, shell integration, themes, etc.
|
||||
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
||||
@ -131,7 +146,6 @@ pub fn build(b: *std.Build) !void {
|
||||
b.getInstallPath(.prefix, "share/ghostty"),
|
||||
);
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
break :run;
|
||||
}
|
||||
@ -157,16 +171,18 @@ pub fn build(b: *std.Build) !void {
|
||||
},
|
||||
);
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
// Run uses the native macOS app
|
||||
run_step.dependOn(&macos_app_native_only.open.step);
|
||||
|
||||
// If we have no test filters, install the tests too
|
||||
if (test_filter == null) {
|
||||
macos_app_native_only.addTestStepDependencies(test_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",
|
||||
.filters = if (test_filter) |v| &.{v} else &.{},
|
||||
@ -180,18 +196,13 @@ pub fn build(b: *std.Build) !void {
|
||||
}),
|
||||
});
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// update-translations does what it sounds like and updates the "pot"
|
||||
// files. These should be committed to the repo.
|
||||
{
|
||||
const step = b.step("update-translations", "Update translation files");
|
||||
step.dependOn(i18n.update_step);
|
||||
}
|
||||
translations_step.dependOn(i18n.update_step);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
A54F45F42E1F047A0046BD5C /* GhosttyTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = GhosttyTests; sourceTree = "<group>"; };
|
||||
A54F45F42E1F047A0046BD5C /* Tests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Tests; sourceTree = "<group>"; };
|
||||
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -612,7 +612,7 @@
|
||||
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
||||
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
|
||||
A54CD6ED299BEB14008C95BB /* Sources */,
|
||||
A54F45F42E1F047A0046BD5C /* GhosttyTests */,
|
||||
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
||||
A5A1F8862A489D7400D1E8BC /* Resources */,
|
||||
A5B30532299BEAAA0047F10C /* Products */,
|
||||
@ -712,7 +712,7 @@
|
||||
A54F45F82E1F047A0046BD5C /* PBXTargetDependency */,
|
||||
);
|
||||
fileSystemSynchronizedGroups = (
|
||||
A54F45F42E1F047A0046BD5C /* GhosttyTests */,
|
||||
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||
);
|
||||
name = GhosttyTests;
|
||||
packageProductDependencies = (
|
||||
|
@ -15,6 +15,7 @@ pub fn build(b: *std.Build) !void {
|
||||
});
|
||||
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
||||
|
||||
const module = harfbuzz: {
|
||||
const module = b.addModule("harfbuzz", .{
|
||||
.root_source_file = b.path("main.zig"),
|
||||
.target = target,
|
||||
@ -25,6 +26,13 @@ pub fn build(b: *std.Build) !void {
|
||||
},
|
||||
});
|
||||
|
||||
const options = b.addOptions();
|
||||
options.addOption(bool, "coretext", coretext_enabled);
|
||||
options.addOption(bool, "freetype", freetype_enabled);
|
||||
module.addOptions("build_options", options);
|
||||
break :harfbuzz module;
|
||||
};
|
||||
|
||||
// For dynamic linking, we prefer dynamic linking and to search by
|
||||
// mode first. Mode first will search all paths for a dynamic library
|
||||
// before falling back to static.
|
||||
|
@ -1,7 +1,8 @@
|
||||
const builtin = @import("builtin");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("hb.h");
|
||||
@cInclude("hb-ft.h");
|
||||
if (builtin.os.tag == .macos) @cInclude("hb-coretext.h");
|
||||
if (build_options.freetype) @cInclude("hb-ft.h");
|
||||
if (build_options.coretext) @cInclude("hb-coretext.h");
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ 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,
|
||||
@ -33,6 +34,21 @@ pub fn init(
|
||||
=> "Release",
|
||||
};
|
||||
|
||||
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.
|
||||
@ -41,12 +57,13 @@ pub fn init(
|
||||
// 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 build = RunStep.create(b, "xcodebuild");
|
||||
build.has_side_effects = true;
|
||||
build.cwd = b.path("macos");
|
||||
build.env_map = env_map;
|
||||
build.addArgs(&.{
|
||||
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",
|
||||
@ -54,36 +71,55 @@ pub fn init(
|
||||
xc_config,
|
||||
});
|
||||
|
||||
switch (deps.xcframework.target) {
|
||||
// Universal is our default target, so we don't have to
|
||||
// add anything.
|
||||
.universal => {},
|
||||
|
||||
// Native we need to override the architecture in the Xcode
|
||||
// project with the -arch flag.
|
||||
.native => build.addArgs(&.{
|
||||
"-arch",
|
||||
switch (builtin.cpu.arch) {
|
||||
.aarch64 => "arm64",
|
||||
.x86_64 => "x86_64",
|
||||
else => @panic("unsupported macOS arch"),
|
||||
},
|
||||
}),
|
||||
}
|
||||
// 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(&build.step);
|
||||
deps.xcframework.addStepDependencies(&step.step);
|
||||
|
||||
// We also need all these resources because the xcode project
|
||||
// references them via symlinks.
|
||||
deps.resources.addStepDependencies(&build.step);
|
||||
deps.i18n.addStepDependencies(&build.step);
|
||||
deps.docs.installDummy(&build.step);
|
||||
deps.resources.addStepDependencies(&step.step);
|
||||
deps.i18n.addStepDependencies(&step.step);
|
||||
deps.docs.installDummy(&step.step);
|
||||
|
||||
// Expect success
|
||||
build.expectExitCode(0);
|
||||
step.expectExitCode(0);
|
||||
|
||||
break :build build;
|
||||
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",
|
||||
});
|
||||
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);
|
||||
deps.i18n.addStepDependencies(&step.step);
|
||||
deps.docs.installDummy(&step.step);
|
||||
|
||||
// Expect success
|
||||
step.expectExitCode(0);
|
||||
|
||||
break :xctest step;
|
||||
};
|
||||
|
||||
// Our step to open the resulting Ghostty app.
|
||||
@ -143,6 +179,7 @@ pub fn init(
|
||||
.build = build,
|
||||
.open = open,
|
||||
.copy = copy,
|
||||
.xctest = xctest,
|
||||
};
|
||||
}
|
||||
|
||||
@ -155,3 +192,10 @@ 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);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ pub fn add(
|
||||
if (b.lazyDependency("harfbuzz", .{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.@"enable-freetype" = true,
|
||||
.@"enable-freetype" = self.config.font_backend.hasFreetype(),
|
||||
.@"enable-coretext" = self.config.font_backend.hasCoretext(),
|
||||
})) |harfbuzz_dep| {
|
||||
step.root_module.addImport(
|
||||
|
Reference in New Issue
Block a user