mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-18 13:30:29 +00:00
Run cmake configure and build on the extracted lib-vt tarball as part of distcheck to ensure the CMake wrapper works from the stripped archive. Keep dist/cmake/ and dist/libghostty-vt/ in the archive since the CMake build needs them.
258 lines
9.3 KiB
Zig
258 lines
9.3 KiB
Zig
const GhosttyDist = @This();
|
|
|
|
const std = @import("std");
|
|
const Config = @import("Config.zig");
|
|
const SharedDeps = @import("SharedDeps.zig");
|
|
const GhosttyFrameData = @import("GhosttyFrameData.zig");
|
|
|
|
/// The final source tarball.
|
|
archive: std.Build.LazyPath,
|
|
|
|
/// The step to install the tarball.
|
|
install_step: *std.Build.Step,
|
|
|
|
/// The step to depend on
|
|
archive_step: *std.Build.Step,
|
|
|
|
/// The step to depend on for checking the dist
|
|
check_step: *std.Build.Step,
|
|
|
|
pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
|
|
// The name prefix used for all paths in the archive.
|
|
const name = if (cfg.emit_lib_vt) "libghostty-vt" else "ghostty";
|
|
|
|
// Get the resources we're going to inject into the source tarball.
|
|
// lib-vt doesn't need GTK resources or frame data.
|
|
const alloc = b.allocator;
|
|
var resources: std.ArrayListUnmanaged(Resource) = .empty;
|
|
if (!cfg.emit_lib_vt) {
|
|
{
|
|
const gtk = SharedDeps.gtkNgDistResources(b);
|
|
try resources.append(alloc, gtk.resources_c);
|
|
try resources.append(alloc, gtk.resources_h);
|
|
}
|
|
{
|
|
const framedata = GhosttyFrameData.distResources(b);
|
|
try resources.append(alloc, framedata.framedata);
|
|
}
|
|
}
|
|
|
|
// git archive to create the final tarball. "git archive" is the
|
|
// easiest way I can find to create a tarball that ignores stuff
|
|
// from gitignore and also supports adding files as well as removing
|
|
// dist-only files (the "export-ignore" git attribute).
|
|
const git_archive = b.addSystemCommand(&.{
|
|
"git",
|
|
"archive",
|
|
"--format=tgz",
|
|
});
|
|
|
|
// embed the Ghostty version in the tarball
|
|
{
|
|
const version = b.addWriteFiles().add("VERSION", b.fmt("{f}", .{cfg.version}));
|
|
// --add-file uses the most recent --prefix to determine the path
|
|
// in the archive to copy the file (the directory only).
|
|
git_archive.addArg(b.fmt("--prefix={s}-{f}/", .{
|
|
name, cfg.version,
|
|
}));
|
|
git_archive.addPrefixedFileArg("--add-file=", version);
|
|
}
|
|
|
|
// Add all of our resources into the tarball.
|
|
for (resources.items) |resource| {
|
|
// Our dist path basename may not match our generated file basename,
|
|
// and git archive requires this. To be safe, we copy the file once
|
|
// to ensure the basename matches and then use that as the final
|
|
// generated file.
|
|
const copied = b.addWriteFiles().addCopyFile(
|
|
resource.generated,
|
|
std.fs.path.basename(resource.dist),
|
|
);
|
|
|
|
// --add-file uses the most recent --prefix to determine the path
|
|
// in the archive to copy the file (the directory only).
|
|
git_archive.addArg(b.fmt("--prefix={s}-{f}/{s}/", .{
|
|
name, cfg.version,
|
|
std.fs.path.dirname(resource.dist).?,
|
|
}));
|
|
git_archive.addPrefixedFileArg("--add-file=", copied);
|
|
}
|
|
|
|
// Add our output
|
|
git_archive.addArgs(&.{
|
|
// This is important. Standard source tarballs extract into
|
|
// a directory named `project-version`. This is expected by
|
|
// standard tooling such as debhelper and rpmbuild.
|
|
b.fmt("--prefix={s}-{f}/", .{ name, cfg.version }),
|
|
"-o",
|
|
});
|
|
const output = git_archive.addOutputFileArg(b.fmt(
|
|
"{s}-{f}.tar.gz",
|
|
.{ name, cfg.version },
|
|
));
|
|
git_archive.addArg("HEAD");
|
|
|
|
// When building for lib-vt only, exclude large directories that
|
|
// are not needed to build libghostty-vt. This significantly reduces
|
|
// the size of the resulting archive.
|
|
if (cfg.emit_lib_vt) {
|
|
for (lib_vt_excludes) |exclude| {
|
|
git_archive.addArg(b.fmt(":(exclude){s}", .{exclude}));
|
|
}
|
|
}
|
|
|
|
// The install step to put the dist into the build directory.
|
|
const install = b.addInstallFile(
|
|
output,
|
|
b.fmt("dist/{s}-{f}.tar.gz", .{ name, cfg.version }),
|
|
);
|
|
|
|
// The check step to ensure the archive works.
|
|
const check = b.addSystemCommand(&.{ "tar", "xvzf" });
|
|
check.addFileArg(output);
|
|
check.addArg("-C");
|
|
|
|
// This is the root Ghostty source dir of the extracted source tarball.
|
|
// i.e. this is way `build.zig` is.
|
|
const extract_dir = check
|
|
.addOutputDirectoryArg(name)
|
|
.path(b, b.fmt("{s}-{f}", .{ name, cfg.version }));
|
|
|
|
// Check that tests pass within the extracted directory. This isn't
|
|
// a fully hermetic test because we're sharing the Zig cache. In
|
|
// the future we could add an option to use a totally new cache but
|
|
// in the interest of speed we don't do that for now and hope other
|
|
// CI catches any issues.
|
|
const check_test = step: {
|
|
// For lib-vt, we run the lib-vt tests instead of the full test suite.
|
|
const check_cmd = if (cfg.emit_lib_vt)
|
|
&[_][]const u8{ "zig", "build", "test-lib-vt", "-Demit-lib-vt=true" }
|
|
else
|
|
&[_][]const u8{ "zig", "build", "test" };
|
|
const step = b.addSystemCommand(check_cmd);
|
|
step.setCwd(extract_dir);
|
|
|
|
// Must be set so that Zig knows that this command doesn't
|
|
// have side effects and is being run for its exit code check.
|
|
// Zig will cache depending on its extract dir.
|
|
step.expectExitCode(0);
|
|
|
|
// Capture stderr so it doesn't spew into the parent build.
|
|
// On the flip side, if the test fails we won't know why so
|
|
// that sucks but we should have already ran tests at this point.
|
|
// NOTE(mitchellh): temporarily disabled to diagnose heisenbug
|
|
//_ = step.captureStdErr();
|
|
|
|
break :step step;
|
|
};
|
|
|
|
// Check that all our dist resources are at the proper path.
|
|
for (resources.items) |resource| {
|
|
const path = extract_dir.path(b, resource.dist);
|
|
const check_path = b.addCheckFile(path, .{});
|
|
check_test.step.dependOn(&check_path.step);
|
|
}
|
|
|
|
// For lib-vt, also verify the CMake build works from the tarball.
|
|
if (cfg.emit_lib_vt) {
|
|
const cmake_build_dir = extract_dir.path(b, "cmake-build");
|
|
const cmake_configure = b.addSystemCommand(&.{ "cmake", "-B" });
|
|
cmake_configure.addDirectoryArg(cmake_build_dir);
|
|
cmake_configure.setCwd(extract_dir);
|
|
cmake_configure.expectExitCode(0);
|
|
cmake_configure.step.dependOn(&check.step);
|
|
|
|
const cmake_build = b.addSystemCommand(&.{ "cmake", "--build" });
|
|
cmake_build.addDirectoryArg(cmake_build_dir);
|
|
cmake_build.expectExitCode(0);
|
|
cmake_build.step.dependOn(&cmake_configure.step);
|
|
|
|
check_test.step.dependOn(&cmake_build.step);
|
|
}
|
|
|
|
return .{
|
|
.archive = output,
|
|
.install_step = &install.step,
|
|
.archive_step = &git_archive.step,
|
|
.check_step = &check_test.step,
|
|
};
|
|
}
|
|
|
|
/// Paths to exclude from the dist archive when building for lib-vt only.
|
|
/// These are large files and directories that are not needed to build or
|
|
/// test libghostty-vt, specified as git pathspec exclude patterns.
|
|
const lib_vt_excludes = &[_][]const u8{
|
|
// App and platform resources
|
|
"images",
|
|
"macos",
|
|
"dist/doxygen",
|
|
"dist/linux",
|
|
"dist/macos",
|
|
"dist/windows",
|
|
"flatpak",
|
|
"snap",
|
|
"po",
|
|
"example",
|
|
|
|
// Test corpus (lib-vt tests use embedded testdata within src/terminal/)
|
|
"test",
|
|
|
|
// Large binary assets
|
|
"src/font/res",
|
|
"src/crash/testdata",
|
|
"pkg/wuffs/src/too_big.jpg",
|
|
"pkg/wuffs/src/too_big.png",
|
|
"pkg/breakpad/vendor",
|
|
|
|
// Vendored libraries not used by lib-vt
|
|
"vendor",
|
|
};
|
|
|
|
/// A dist resource is a resource that is built and distributed as part
|
|
/// of the source tarball with Ghostty. These aren't committed to the Git
|
|
/// repository but are built as part of the `zig build dist` command.
|
|
/// The purpose is to limit the number of build-time dependencies required
|
|
/// for downstream users and packagers.
|
|
pub const Resource = struct {
|
|
/// The relative path in the source tree where the resource will be
|
|
/// if it was pre-built. These are not checksummed or anything because the
|
|
/// assumption is that the source tarball itself is checksummed and signed.
|
|
dist: []const u8,
|
|
|
|
/// The path to the generated resource in the build system. By depending
|
|
/// on this you'll force it to regenerate. This does NOT point to the
|
|
/// "path" above.
|
|
generated: std.Build.LazyPath,
|
|
|
|
/// Returns the path to use for this resource.
|
|
pub fn path(self: *const Resource, b: *std.Build) std.Build.LazyPath {
|
|
// If the dist path exists at build compile time then we use it.
|
|
if (self.exists(b)) {
|
|
return b.path(self.dist);
|
|
}
|
|
|
|
// Otherwise we use the generated path.
|
|
return self.generated;
|
|
}
|
|
|
|
/// Returns true if the dist path exists at build time.
|
|
pub fn exists(self: *const Resource, b: *std.Build) bool {
|
|
if (b.build_root.handle.access(self.dist, .{})) {
|
|
// If we have a ".git" directory then we're a git checkout
|
|
// and we never want to use the dist path. This shouldn't happen
|
|
// so show a warning to the user.
|
|
if (b.build_root.handle.access(".git", .{})) {
|
|
std.log.warn(
|
|
"dist resource '{s}' should not be in a git checkout",
|
|
.{self.dist},
|
|
);
|
|
return false;
|
|
} else |_| {}
|
|
|
|
return true;
|
|
} else |_| {
|
|
return false;
|
|
}
|
|
}
|
|
};
|