a73x

build.zig

Ref:   Size: 8.7 KiB

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    const config_mod = b.createModule(.{
        .root_source_file = b.path("src/config.zig"),
        .target = target,
        .optimize = optimize,
    });

    const scale_tracker_mod = b.createModule(.{
        .root_source_file = b.path("src/scale_tracker.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Lazy-fetch the ghostty dependency. On the first invocation this
    // materializes the package; subsequent builds use the local cache.
    const ghostty_dep = b.lazyDependency("ghostty", .{});

    // zig-wayland scanner — generates protocol bindings at build time
    const wayland_dep = b.dependency("wayland", .{});
    const Scanner = @import("wayland").Scanner;
    const scanner = Scanner.create(b, .{});
    scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml");
    scanner.generate("wl_compositor", 6);
    scanner.generate("wl_seat", 9);
    scanner.generate("wl_data_device_manager", 3);
    scanner.generate("wl_output", 4);
    scanner.generate("xdg_wm_base", 6);

    // wayland module — generated bindings + our Connection wrapper
    const wayland_generated_mod = b.createModule(.{
        .root_source_file = scanner.result,
        .target = target,
        .optimize = optimize,
    });

    const wayland_mod = b.createModule(.{
        .root_source_file = b.path("src/wayland.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    wayland_mod.addImport("wayland", wayland_generated_mod);
    wayland_mod.addImport("scale_tracker", scale_tracker_mod);
    wayland_mod.linkSystemLibrary("wayland-client", .{});
    wayland_mod.linkSystemLibrary("xkbcommon", .{});
    _ = wayland_dep; // referenced via Scanner

    // vt module — wraps ghostty-vt
    const vt_mod = b.createModule(.{
        .root_source_file = b.path("src/vt.zig"),
        .target = target,
        .optimize = optimize,
    });
    if (ghostty_dep) |dep| {
        vt_mod.addImport("ghostty-vt", dep.module("ghostty-vt"));
    }

    // Main executable module
    const exe_mod = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    exe_mod.addImport("vt", vt_mod);
    exe_mod.addImport("wayland-client", wayland_mod);
    exe_mod.addImport("config", config_mod);

    const exe = b.addExecutable(.{
        .name = "waystty",
        .root_module = exe_mod,
    });

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| run_cmd.addArgs(args);

    const run_step = b.step("run", "Run waystty");
    run_step.dependOn(&run_cmd.step);

    // pty module — forkpty-based PTY spawn
    const pty_mod = b.createModule(.{
        .root_source_file = b.path("src/pty.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    pty_mod.linkSystemLibrary("util", .{});
    exe_mod.addImport("pty", pty_mod);

    const test_step = b.step("test", "Run unit tests");

    // Test pty.zig
    const pty_test_mod = b.createModule(.{
        .root_source_file = b.path("src/pty.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    pty_test_mod.linkSystemLibrary("util", .{});
    const pty_tests = b.addTest(.{
        .root_module = pty_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(pty_tests).step);

    // Test scale_tracker.zig
    const scale_tracker_test_mod = b.createModule(.{
        .root_source_file = b.path("src/scale_tracker.zig"),
        .target = target,
        .optimize = optimize,
    });
    const scale_tracker_tests = b.addTest(.{
        .root_module = scale_tracker_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(scale_tracker_tests).step);

    // Test wayland.zig
    const wayland_test_mod = b.createModule(.{
        .root_source_file = b.path("src/wayland.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    wayland_test_mod.addImport("wayland", wayland_generated_mod);
    wayland_test_mod.addImport("scale_tracker", scale_tracker_mod);
    wayland_test_mod.linkSystemLibrary("wayland-client", .{});
    wayland_test_mod.linkSystemLibrary("xkbcommon", .{});
    const wayland_tests = b.addTest(.{
        .root_module = wayland_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(wayland_tests).step);

    // Test main.zig (and transitively vt.zig via its import)
    const main_test_mod = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    main_test_mod.addImport("vt", vt_mod);
    main_test_mod.addImport("wayland-client", wayland_mod);
    main_test_mod.addImport("config", config_mod);
    const main_tests = b.addTest(.{
        .root_module = main_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(main_tests).step);

    // Test vt.zig directly (runs the ghostty-vt smoke test)
    const vt_test_mod = b.createModule(.{
        .root_source_file = b.path("src/vt.zig"),
        .target = target,
        .optimize = optimize,
    });
    if (ghostty_dep) |dep| {
        vt_test_mod.addImport("ghostty-vt", dep.module("ghostty-vt"));
    }
    const vt_tests = b.addTest(.{
        .root_module = vt_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(vt_tests).step);

    // font module — fontconfig lookup + freetype rasterization + glyph atlas
    const font_mod = b.createModule(.{
        .root_source_file = b.path("src/font.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    font_mod.addImport("config", config_mod);
    font_mod.linkSystemLibrary("fontconfig", .{});
    font_mod.linkSystemLibrary("freetype2", .{});
    exe_mod.addImport("font", font_mod);

    // Test font.zig
    const font_test_mod = b.createModule(.{
        .root_source_file = b.path("src/font.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    font_test_mod.addImport("config", config_mod);
    font_test_mod.linkSystemLibrary("fontconfig", .{});
    font_test_mod.linkSystemLibrary("freetype2", .{});
    const font_tests = b.addTest(.{
        .root_module = font_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(font_tests).step);

    // vulkan-zig — generate Vulkan bindings from vk.xml
    const vulkan_headers_dep = b.dependency("vulkan_headers", .{});
    const vulkan_zig_dep = b.dependency("vulkan", .{
        .registry = vulkan_headers_dep.path("registry/vk.xml"),
    });
    const vulkan_module = vulkan_zig_dep.module("vulkan-zig");

    // Compile cell shaders to SPIR-V via glslc
    const glslc_vert = b.addSystemCommand(&.{ "glslc", "--target-env=vulkan1.2" });
    glslc_vert.addFileArg(b.path("shaders/cell.vert"));
    glslc_vert.addArg("-o");
    const cell_vert_spv = glslc_vert.addOutputFileArg("cell.vert.spv");

    const glslc_frag = b.addSystemCommand(&.{ "glslc", "--target-env=vulkan1.2" });
    glslc_frag.addFileArg(b.path("shaders/cell.frag"));
    glslc_frag.addArg("-o");
    const cell_frag_spv = glslc_frag.addOutputFileArg("cell.frag.spv");

    // Collect renderer.zig + both SPV blobs into one WriteFiles directory so
    // that @embedFile("cell.vert.spv") resolves correctly relative to renderer.zig.
    const renderer_dir = b.addWriteFiles();
    const renderer_zig_path = renderer_dir.addCopyFile(b.path("src/renderer.zig"), "renderer.zig");
    _ = renderer_dir.addCopyFile(cell_vert_spv, "cell.vert.spv");
    _ = renderer_dir.addCopyFile(cell_frag_spv, "cell.frag.spv");

    // renderer module
    const renderer_mod = b.createModule(.{
        .root_source_file = renderer_zig_path,
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    renderer_mod.addImport("vulkan", vulkan_module);
    renderer_mod.linkSystemLibrary("dl", .{});
    exe_mod.addImport("vulkan", vulkan_module);
    exe_mod.addImport("renderer", renderer_mod);
    main_test_mod.addImport("vulkan", vulkan_module);
    main_test_mod.addImport("renderer", renderer_mod);
    main_test_mod.addImport("font", font_mod);

    // Test renderer.zig
    const renderer_test_mod = b.createModule(.{
        .root_source_file = renderer_zig_path,
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    renderer_test_mod.addImport("vulkan", vulkan_module);
    renderer_test_mod.linkSystemLibrary("dl", .{});
    const renderer_tests = b.addTest(.{
        .root_module = renderer_test_mod,
    });
    test_step.dependOn(&b.addRunArtifact(renderer_tests).step);
}