summaryrefslogtreecommitdiffstats
path: root/lib/diligent/build_integration.zig
blob: 49727b37b0b06539c8b0837b8cb0952eed9fea5f (plain)
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const std = @import("std");
const generate = @import("generator.zig").generate;
const path = std.fs.path;
const bufPrint = std.fmt.bufPrint;
const Builder = std.build.Builder;
const Step = std.build.Step;
const RunStep = std.build.RunStep;
const LibExeObjStep = std.build.LibExeObjStep;

const modules = [_][]const u8{ "DiligentCore", "DiligentFX", "DiligentTools" };

/// build.zig integration for Diligent binding generation. This step can be used to generate
/// bindings at compiletime from header files. The final package can then be obtained by
/// `package()`, the result of which can be added to the project using `std.build.Builder.addPackage`.
pub const GenerateStep = struct {
    step: Step,
    builder: *Builder,

    /// base path for the DiligentCore repository
    diligent_path: []const u8,

    /// The package representing the generated bindings. The generated bindings will be placed
    /// in `package.path`. When using this step, this member should be passed to
    /// `std.build.Builder.addPackage`, which causes the bindings to become available under the
    /// name `diligent`.
    package: std.build.Pkg,

    generator_exe: *LibExeObjStep,
    run_step: *RunStep,

    /// Add runtime dependencies to a parent build step
    pub fn addDeps(self: *GenerateStep, step: *LibExeObjStep, diligent_build_type: []const u8) void {
        var buffer = [_]u8{0} ** 1024;

        const vulkan_include = bufPrint(
            buffer[0..],
            "{}/DiligentCore/ThirdParty/Vulkan-Headers/include",
            .{self.diligent_path},
        ) catch unreachable;
        step.addIncludeDir(vulkan_include);

        inline for (modules) |module| {
            const module_path = bufPrint(
                buffer[0..],
                "{}/build/install/include/{}",
                .{ self.diligent_path, module },
            ) catch unreachable;
            step.addIncludeDir(module_path);

            const lib_path = bufPrint(
                buffer[0..],
                "{}/build/install/lib/{}/{}",
                .{ self.diligent_path, module, diligent_build_type },
            ) catch unreachable;
            step.addLibPath(lib_path);
        }

        step.step.dependOn(&self.run_step.step);
        step.addPackage(self.package);
    }

    /// Initialize a Vulkan generation step, for `builder`. `interfaces` are the paths
    /// to interface headers, relative to the project root. The generated bindings will be placed at
    /// `out_path`, which is relative to the zig-cache directory.
    pub fn init(builder: *Builder, diligent_path: []const u8, out_path: []const u8) *GenerateStep {
        const self = builder.allocator.create(GenerateStep) catch unreachable;
        const full_out_path = path.join(builder.allocator, &[_][]const u8{
            builder.build_root,
            builder.cache_root,
            out_path,
        }) catch unreachable;

        const generator_exe = builder.addExecutable("dg-gen", "lib/diligent/generator.zig");
        var buffer = [_]u8{0} ** 1024;

        const vulkan_include = bufPrint(
            buffer[0..],
            "{}/DiligentCore/ThirdParty/Vulkan-Headers/include",
            .{diligent_path},
        ) catch unreachable;
        generator_exe.addIncludeDir(vulkan_include);

        inline for (modules) |module| {
            const module_path = bufPrint(
                buffer[0..],
                "{}/build/install/include/{}",
                .{ diligent_path, module },
            ) catch unreachable;
            generator_exe.addIncludeDir(module_path);
        }

        const run_step = generator_exe.run();
        run_step.addArg(full_out_path);

        generator_exe.linkSystemLibrary("c");

        self.* = .{
            .step = Step.init(.Custom, "diligent-generate", builder.allocator, make),
            .builder = builder,
            .diligent_path = builder.dupe(diligent_path),
            .package = .{
                .name = "diligent",
                .path = full_out_path,
                .dependencies = null,
            },
            .generator_exe = generator_exe,
            .run_step = run_step,
        };
        return self;
    }

    /// Internal build function. The resulting generated bindings are not formatted, which is why an
    /// ArrayList writer is passed instead of a file writer. This is then formatted into standard
    /// formatting by parsing it and rendering with `std.zig.parse` and `std.zig.render` respectively.
    fn make(step: *Step) !void {
        const self = @fieldParentPtr(GenerateStep, "step", step);
        try self.run_step.step.make();
    }
};