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(); } };