summary refs log tree commit diff
path: root/build.zig
blob: 2c5dcbbf4f2f6bbc3e1d1e65a3f2ad0abbeb91b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Build recipe
// SPDX-FileCopyrightText: 2025 Nguyễn Gia Phong
// SPDX-License-Identifier: GPL-3.0-or-later

const Build = std.Build;
const Module = Build.Module;
const NativePaths = std.zig.system.NativePaths;
const getStdOut = std.io.getStdOut;
const openDirAbsolute = std.fs.openDirAbsolute;
const std = @import("std");
const tokenize = std.mem.tokenizeScalar;

const supported_languages = @embedFile("src/supported-languages");

/// Generates the "language" module.
pub fn main() !void {
    const stdout = getStdOut().writer();
    try stdout.writeAll(
        \\const Language = @import("tree-sitter").Language;
        \\pub const Create = *const fn () callconv(.c) *const Language;
    );
    var language_names = tokenize(u8, supported_languages, '\n');
    while (language_names.next()) |name|
        try stdout.print(
            \\pub const {s} = @extern(Create, .{{ .name = "tree_sitter_{s}" }});
        , .{ name, name });
}

fn linkTreeSitterGrammars(b: *Build, module: *Module) !void {
    const target = module.resolved_target.?;
    const native_paths = try NativePaths.detect(b.allocator, target.result);
    for (native_paths.lib_dirs.items) |lib_dir| {
        // Guix somehow puts the shared objects in $output/lib/tree-sitter/.
        const tree_sitter_dir = b.pathJoin(&.{ lib_dir, "tree-sitter" });
        var dir = openDirAbsolute(tree_sitter_dir, .{}) catch continue;
        dir.close();
        module.addLibraryPath(.{ .cwd_relative = tree_sitter_dir });
    }
    var language_names = tokenize(u8, supported_languages, '\n');
    while (language_names.next()) |name|
        module.linkSystemLibrary(b.fmt("tree-sitter-{s}", .{ name }), .{});

    const languages = b.createModule(.{
        .root_source_file =  b.addRunArtifact(b.addExecutable(.{
            .name = "extern-tree-sitter-grammars",
            .root_source_file = b.path(@src().file), // main function above
            .target = b.graph.host,
        })).captureStdOut(),
        .target = target,
        .optimize = module.optimize.?,
    });
    const lib = "tree-sitter";
    languages.addImport(lib, b.dependency(lib, .{}).module(lib));
    module.addImport("languages", languages);
}

pub fn build(b: *Build) !void {
    const mod = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = b.standardTargetOptions(.{}),
        .optimize = b.standardOptimizeOption(.{}),
    });
    inline for (.{ "known-folders", "tree-sitter", "vaxis", "zsanett" }) |lib|
        mod.addImport(lib, b.dependency(lib, .{}).module(lib));
    try linkTreeSitterGrammars(b, mod);

    const unit_tests = b.addTest(.{ .root_module = mod });
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&b.addRunArtifact(unit_tests).step);

    const exe = b.addExecutable(.{ .name = "kay", .root_module = 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 the app");
    run_step.dependOn(&run_cmd.step);
}