aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/build/GhosttyDist.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/build/GhosttyDist.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/build/GhosttyDist.zig')
-rw-r--r--vendor/libghostty-vt/src/build/GhosttyDist.zig257
1 files changed, 257 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/build/GhosttyDist.zig b/vendor/libghostty-vt/src/build/GhosttyDist.zig
new file mode 100644
index 00000000..448047f4
--- /dev/null
+++ b/vendor/libghostty-vt/src/build/GhosttyDist.zig
@@ -0,0 +1,257 @@
+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;
+ }
+ }
+};