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:
41
build.zig
41
build.zig
@ -8,7 +8,22 @@ comptime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(b: *std.Build) !void {
|
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 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.
|
// Ghostty resources like terminfo, shell integration, themes, etc.
|
||||||
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
const resources = try buildpkg.GhosttyResources.init(b, &config);
|
||||||
@ -131,7 +146,6 @@ pub fn build(b: *std.Build) !void {
|
|||||||
b.getInstallPath(.prefix, "share/ghostty"),
|
b.getInstallPath(.prefix, "share/ghostty"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
run_step.dependOn(&run_cmd.step);
|
||||||
break :run;
|
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);
|
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
|
// 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(.{
|
const test_exe = b.addTest(.{
|
||||||
.name = "ghostty-test",
|
.name = "ghostty-test",
|
||||||
.filters = if (test_filter) |v| &.{v} else &.{},
|
.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);
|
||||||
if (config.emit_test_exe) b.installArtifact(test_exe);
|
_ = try deps.add(test_exe);
|
||||||
_ = try deps.add(test_exe);
|
const test_run = b.addRunArtifact(test_exe);
|
||||||
const test_run = b.addRunArtifact(test_exe);
|
test_step.dependOn(&test_run.step);
|
||||||
test_step.dependOn(&test_run.step);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update-translations does what it sounds like and updates the "pot"
|
// update-translations does what it sounds like and updates the "pot"
|
||||||
// files. These should be committed to the repo.
|
// files. These should be committed to the repo.
|
||||||
{
|
translations_step.dependOn(i18n.update_step);
|
||||||
const step = b.step("update-translations", "Update translation files");
|
|
||||||
step.dependOn(i18n.update_step);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedRootGroup 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 */
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -612,7 +612,7 @@
|
|||||||
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
|
||||||
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
|
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
|
||||||
A54CD6ED299BEB14008C95BB /* Sources */,
|
A54CD6ED299BEB14008C95BB /* Sources */,
|
||||||
A54F45F42E1F047A0046BD5C /* GhosttyTests */,
|
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||||
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
A5D495A3299BECBA00DD1313 /* Frameworks */,
|
||||||
A5A1F8862A489D7400D1E8BC /* Resources */,
|
A5A1F8862A489D7400D1E8BC /* Resources */,
|
||||||
A5B30532299BEAAA0047F10C /* Products */,
|
A5B30532299BEAAA0047F10C /* Products */,
|
||||||
@ -712,7 +712,7 @@
|
|||||||
A54F45F82E1F047A0046BD5C /* PBXTargetDependency */,
|
A54F45F82E1F047A0046BD5C /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
fileSystemSynchronizedGroups = (
|
||||||
A54F45F42E1F047A0046BD5C /* GhosttyTests */,
|
A54F45F42E1F047A0046BD5C /* Tests */,
|
||||||
);
|
);
|
||||||
name = GhosttyTests;
|
name = GhosttyTests;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
@ -15,15 +15,23 @@ pub fn build(b: *std.Build) !void {
|
|||||||
});
|
});
|
||||||
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
const macos = b.dependency("macos", .{ .target = target, .optimize = optimize });
|
||||||
|
|
||||||
const module = b.addModule("harfbuzz", .{
|
const module = harfbuzz: {
|
||||||
.root_source_file = b.path("main.zig"),
|
const module = b.addModule("harfbuzz", .{
|
||||||
.target = target,
|
.root_source_file = b.path("main.zig"),
|
||||||
.optimize = optimize,
|
.target = target,
|
||||||
.imports = &.{
|
.optimize = optimize,
|
||||||
.{ .name = "freetype", .module = freetype.module("freetype") },
|
.imports = &.{
|
||||||
.{ .name = "macos", .module = macos.module("macos") },
|
.{ .name = "freetype", .module = freetype.module("freetype") },
|
||||||
},
|
.{ .name = "macos", .module = macos.module("macos") },
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
// For dynamic linking, we prefer dynamic linking and to search by
|
||||||
// mode first. Mode first will search all paths for a dynamic library
|
// mode first. Mode first will search all paths for a dynamic library
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
|
||||||
pub const c = @cImport({
|
pub const c = @cImport({
|
||||||
@cInclude("hb.h");
|
@cInclude("hb.h");
|
||||||
@cInclude("hb-ft.h");
|
if (build_options.freetype) @cInclude("hb-ft.h");
|
||||||
if (builtin.os.tag == .macos) @cInclude("hb-coretext.h");
|
if (build_options.coretext) @cInclude("hb-coretext.h");
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@ const XCFramework = @import("GhosttyXCFramework.zig");
|
|||||||
build: *std.Build.Step.Run,
|
build: *std.Build.Step.Run,
|
||||||
open: *std.Build.Step.Run,
|
open: *std.Build.Step.Run,
|
||||||
copy: *std.Build.Step.Run,
|
copy: *std.Build.Step.Run,
|
||||||
|
xctest: *std.Build.Step.Run,
|
||||||
|
|
||||||
pub const Deps = struct {
|
pub const Deps = struct {
|
||||||
xcframework: *const XCFramework,
|
xcframework: *const XCFramework,
|
||||||
@ -33,6 +34,21 @@ pub fn init(
|
|||||||
=> "Release",
|
=> "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});
|
const app_path = b.fmt("macos/build/{s}/Ghostty.app", .{xc_config});
|
||||||
|
|
||||||
// Our step to build the Ghostty macOS app.
|
// Our step to build the Ghostty macOS app.
|
||||||
@ -41,12 +57,13 @@ pub fn init(
|
|||||||
// we create a new empty environment.
|
// we create a new empty environment.
|
||||||
const env_map = try b.allocator.create(std.process.EnvMap);
|
const env_map = try b.allocator.create(std.process.EnvMap);
|
||||||
env_map.* = .init(b.allocator);
|
env_map.* = .init(b.allocator);
|
||||||
|
if (env.get("PATH")) |v| try env_map.put("PATH", v);
|
||||||
|
|
||||||
const build = RunStep.create(b, "xcodebuild");
|
const step = RunStep.create(b, "xcodebuild");
|
||||||
build.has_side_effects = true;
|
step.has_side_effects = true;
|
||||||
build.cwd = b.path("macos");
|
step.cwd = b.path("macos");
|
||||||
build.env_map = env_map;
|
step.env_map = env_map;
|
||||||
build.addArgs(&.{
|
step.addArgs(&.{
|
||||||
"xcodebuild",
|
"xcodebuild",
|
||||||
"-target",
|
"-target",
|
||||||
"Ghostty",
|
"Ghostty",
|
||||||
@ -54,36 +71,55 @@ pub fn init(
|
|||||||
xc_config,
|
xc_config,
|
||||||
});
|
});
|
||||||
|
|
||||||
switch (deps.xcframework.target) {
|
// If we have a specific architecture, we need to pass it
|
||||||
// Universal is our default target, so we don't have to
|
// to xcodebuild.
|
||||||
// add anything.
|
if (xc_arch) |arch| step.addArgs(&.{ "-arch", arch });
|
||||||
.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"),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need the xcframework
|
// We need the xcframework
|
||||||
deps.xcframework.addStepDependencies(&build.step);
|
deps.xcframework.addStepDependencies(&step.step);
|
||||||
|
|
||||||
// We also need all these resources because the xcode project
|
// We also need all these resources because the xcode project
|
||||||
// references them via symlinks.
|
// references them via symlinks.
|
||||||
deps.resources.addStepDependencies(&build.step);
|
deps.resources.addStepDependencies(&step.step);
|
||||||
deps.i18n.addStepDependencies(&build.step);
|
deps.i18n.addStepDependencies(&step.step);
|
||||||
deps.docs.installDummy(&build.step);
|
deps.docs.installDummy(&step.step);
|
||||||
|
|
||||||
// Expect success
|
// 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.
|
// Our step to open the resulting Ghostty app.
|
||||||
@ -143,6 +179,7 @@ pub fn init(
|
|||||||
.build = build,
|
.build = build,
|
||||||
.open = open,
|
.open = open,
|
||||||
.copy = copy,
|
.copy = copy,
|
||||||
|
.xctest = xctest,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,3 +192,10 @@ pub fn installXcframework(self: *const Ghostty) void {
|
|||||||
const b = self.build.step.owner;
|
const b = self.build.step.owner;
|
||||||
b.getInstallStep().dependOn(&self.build.step);
|
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", .{
|
if (b.lazyDependency("harfbuzz", .{
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.@"enable-freetype" = true,
|
.@"enable-freetype" = self.config.font_backend.hasFreetype(),
|
||||||
.@"enable-coretext" = self.config.font_backend.hasCoretext(),
|
.@"enable-coretext" = self.config.font_backend.hasCoretext(),
|
||||||
})) |harfbuzz_dep| {
|
})) |harfbuzz_dep| {
|
||||||
step.root_module.addImport(
|
step.root_module.addImport(
|
||||||
|
Reference in New Issue
Block a user