main build.zig
Eric Bower  ·  2026-06-12
  1const std = @import("std");
  2
  3const linux_targets: []const std.Target.Query = &.{
  4    .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl },
  5    .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .musl },
  6};
  7
  8const macos_targets: []const std.Target.Query = &.{
  9    .{ .cpu_arch = .x86_64, .os_tag = .macos },
 10    .{ .cpu_arch = .aarch64, .os_tag = .macos },
 11};
 12
 13pub fn build(b: *std.Build) void {
 14    const target = b.standardTargetOptions(.{});
 15    const is_macos = target.result.os.tag == .macos;
 16    const optimize = b.standardOptimizeOption(.{});
 17    const version = b.option([]const u8, "version", "Version string for release") orelse
 18        @as([]const u8, @import("build.zig.zon").version);
 19
 20    const options = b.addOptions();
 21    options.addOption([]const u8, "version", version);
 22    const ghostty_ver = @import("build.zig.zon").dependencies.ghostty.hash;
 23    options.addOption([]const u8, "ghostty_version", ghostty_ver);
 24
 25    const exe_mod = b.createModule(.{
 26        .root_source_file = b.path("src/main.zig"),
 27        .target = target,
 28        .optimize = optimize,
 29    });
 30    exe_mod.addOptions("build_options", options);
 31
 32    const dep = b.dependency("ghostty", .{
 33        .target = target,
 34        .optimize = optimize,
 35    });
 36    exe_mod.addImport(
 37        "ghostty-vt",
 38        dep.module("ghostty-vt"),
 39    );
 40
 41    // Run
 42    {
 43        const run_step = b.step("run", "Run the app");
 44        const exe = b.addExecutable(.{
 45            .name = "zmx",
 46            .use_llvm = true,
 47            .use_lld = !is_macos,
 48            .root_module = exe_mod,
 49        });
 50        exe.linkLibC();
 51        b.installArtifact(exe);
 52        const run_cmd = b.addRunArtifact(exe);
 53        run_cmd.step.dependOn(b.getInstallStep());
 54        if (b.args) |args| run_cmd.addArgs(args);
 55        run_step.dependOn(&run_cmd.step);
 56    }
 57
 58    // Test
 59    {
 60        const test_step = b.step("test", "Run unit tests");
 61        const test_module = b.addModule("test", .{
 62            .root_source_file = b.path("src/test.zig"),
 63            .target = target,
 64            .optimize = optimize,
 65        });
 66        const test_dep = b.dependency("ghostty", .{
 67            .target = target,
 68            .optimize = optimize,
 69        });
 70        test_module.addImport(
 71            "ghostty-vt",
 72            test_dep.module("ghostty-vt"),
 73        );
 74        const exe_unit_tests = b.addTest(.{
 75            .root_module = test_module,
 76            .use_llvm = true,
 77            .use_lld = !is_macos,
 78        });
 79        exe_unit_tests.linkLibC();
 80        const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
 81        test_step.dependOn(&run_exe_unit_tests.step);
 82    }
 83
 84    // Check for LSP integration
 85    {
 86        const check = b.step("check", "Check if zmx compiles");
 87        const exe_check = b.addExecutable(.{
 88            .name = "zmx",
 89            .use_llvm = true,
 90            .use_lld = !is_macos,
 91            .root_module = exe_mod,
 92        });
 93        exe_check.linkLibC();
 94
 95        // Finally we add the "check" step which will be detected
 96        // by ZLS and automatically enable Build-On-Save.
 97        // If you copy this into your `build.zig`, make sure to rename 'foo'
 98        check.dependOn(&exe_check.step);
 99    }
100
101    // Release step - cross-compile to all targets from any host
102    {
103        const release_step = b.step(
104            "release",
105            "Build release binaries for all platforms",
106        );
107        const release_targets = linux_targets ++ macos_targets;
108        for (release_targets) |release_target| {
109            const resolved = b.resolveTargetQuery(release_target);
110            const release_mod = b.createModule(.{
111                .root_source_file = b.path("src/main.zig"),
112                .target = resolved,
113                .optimize = .ReleaseSafe,
114            });
115            release_mod.addOptions("build_options", options);
116
117            if (b.lazyDependency("ghostty", .{
118                .target = resolved,
119                .optimize = .ReleaseSafe,
120            })) |release_dep| {
121                release_mod.addImport("ghostty-vt", release_dep.module("ghostty-vt"));
122            }
123
124            const is_local_macos = resolved.result.os.tag == .macos;
125            const release_exe = b.addExecutable(.{
126                .name = "zmx",
127                .use_llvm = true,
128                .use_lld = !is_local_macos,
129                .root_module = release_mod,
130            });
131            release_exe.linkLibC();
132
133            const os_name = @tagName(release_target.os_tag orelse .linux);
134            const arch_name = @tagName(release_target.cpu_arch orelse .x86_64);
135            const tarball_name = b.fmt("zmx-{s}-{s}-{s}.tar.gz", .{ version, os_name, arch_name });
136
137            const tar = b.addSystemCommand(&.{ "tar", "-czf" });
138
139            const tarball = tar.addOutputFileArg(tarball_name);
140            tar.addArg("-C");
141            tar.addDirectoryArg(release_exe.getEmittedBinDirectory());
142            tar.addArg("zmx");
143
144            const shasum = b.addSystemCommand(&.{"sha256sum"});
145            shasum.addFileArg(tarball);
146            const shasum_output = shasum.captureStdOut();
147
148            const install_tar = b.addInstallFile(tarball, b.fmt("dist/{s}", .{tarball_name}));
149            const install_sha = b.addInstallFile(
150                shasum_output,
151                b.fmt("dist/{s}.sha256", .{tarball_name}),
152            );
153            release_step.dependOn(&install_tar.step);
154            release_step.dependOn(&install_sha.step);
155        }
156    }
157}