diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-04-04 19:22:04 +0300 |
|---|---|---|
| committer | Can Celik <ogulcancelik@gmail.com> | 2026-04-05 01:23:06 +0300 |
| commit | 41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch) | |
| tree | 3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/build/GhosttyDist.zig | |
| parent | 55c138263e190a1e79d4b997bfb9397306c0ec1f (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.zig | 257 |
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; + } + } +}; |
