From b48fe074f512822a780d75fb317c1dbeaa5884b7 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Wed, 25 Nov 2020 15:28:56 +0100 Subject: [PATCH] Add CLI interface --- README.md | 12 +++-- build.zig | 6 +++ generator/main.zig | 74 ++++++++++++++++++++++++++ generator/vulkan/build_integration.zig | 2 +- 4 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 generator/main.zig diff --git a/README.md b/README.md index e7e5e28..0f7c906 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,15 @@ vulkan-zig attempts to provide a better experience to programming Vulkan applica vulkan-zig is automatically tested against the latest vk.xml and zig, and supports vk.xml from version 1.x.141. ## Features +### CLI-interface +A CLI-interface is provided to generate vk.zig from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml), which is built by default when invoking `zig build` in the project root. To generate vk.zig, simply invoke the program as follows: +``` +$ zig-cache/bin/vulkan-zig-generator path/to/vk.xml output/path/to/vk.zig +``` +This reads the xml file, parses its contents, renders the Vulkan bindings, and formats file, before writing the result to the output path. While the intended usage of vulkan-zig is through direct generation from build.zig (see below), the CLI-interface can be used for one-off generation and vendoring the result. + ### Generation from build.zig -Vulkan bindings can be generated directly from the [Vulkan XML registry](https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml) build.zig at compiletime, by using the provided -vulkan generation step: +Vulkan bindings can be generated from the Vulkan XML registry at compile time with build.zig, by using the provided Vulkan generation step: ```zig const vkgen = @import("vulkan-zig/generator/index.zig"); @@ -236,5 +242,5 @@ Upon compilation, glslc is then invoked to compile each shader, and the result i A partial implementation of https://vulkan-tutorial.org is implemented in [examples/triangle.zig](examples/triangle.zig). This example can be ran by executing `zig build run-triangle` in vulkan-zig's root. ## See also -* (Outdated) implementation of https://vulkan-tutorial.org using translate-c: https://github.com/andrewrk/zig-vulkan-triangle. +* Implementation of https://vulkan-tutorial.org: https://github.com/andrewrk/zig-vulkan-triangle. * Alternative binding generator: https://github.com/SpexGuy/Zig-Vulkan-Headers diff --git a/build.zig b/build.zig index 6edc19c..98616a4 100644 --- a/build.zig +++ b/build.zig @@ -75,6 +75,12 @@ pub fn build(b: *Builder) void { const target = b.standardTargetOptions(.{}); const mode = b.standardReleaseOptions(); + + const generator_exe = b.addExecutable("vulkan-zig-generator", "generator/main.zig"); + generator_exe.setTarget(target); + generator_exe.setBuildMode(mode); + generator_exe.install(); + const triangle_exe = b.addExecutable("triangle", "examples/triangle.zig"); triangle_exe.setTarget(target); triangle_exe.setBuildMode(mode); diff --git a/generator/main.zig b/generator/main.zig new file mode 100644 index 0000000..4f6c0b9 --- /dev/null +++ b/generator/main.zig @@ -0,0 +1,74 @@ +const std = @import("std"); +const generate = @import("vulkan/generator.zig").generate; + +const usage = "Usage: {} [-h|--help] \n"; + +pub fn main() !void { + const stderr = std.io.getStdErr(); + const stdout = std.io.getStdOut(); + + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const allocator = &arena.allocator; + + var args = std.process.args(); + const prog_name = try args.next(allocator) orelse return error.ExecutableNameMissing; + + var maybe_xml_path: ?[]const u8 = null; + var maybe_out_path: ?[]const u8 = null; + + while (args.next(allocator)) |err_or_arg| { + const arg = try err_or_arg; + + if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) { + @setEvalBranchQuota(2000); + try stderr.writer().print( + \\Utility to generate a Zig binding from the Vulkan XML API registry. + \\ + \\The most recent Vulkan XML API registry can be obtained from + \\https://github.com/KhronosGroup/Vulkan-Docs/blob/master/xml/vk.xml, + \\and the most recent LunarG Vulkan SDK version can be found at + \\$VULKAN_SDK/x86_64/share/vulkan/registry/vk.xml. + \\ + \\ + ++ usage, + .{ prog_name }, + ); + return; + } else if (maybe_xml_path == null) { + maybe_xml_path = arg; + } else if (maybe_out_path == null) { + maybe_out_path = arg; + } else { + try stderr.writer().print("Error: Superficial argument '{}'\n", .{ arg }); + } + } + + const xml_path = maybe_xml_path orelse { + try stderr.writer().print("Error: Missing required argument \n" ++ usage, .{ prog_name }); + return; + }; + + const out_path = maybe_out_path orelse { + try stderr.writer().print("Error: Missing required argument \n" ++ usage, .{ prog_name }); + return; + }; + + const cwd = std.fs.cwd(); + const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| { + try stderr.writer().print("Error: Failed to open input file '{}' ({})\n", .{ xml_path, @errorName(err) }); + return; + }; + + const out_file = cwd.createFile(out_path, .{}) catch |err| { + try stderr.writer().print("Error: Failed to create output file '{}' ({})\n", .{ out_path, @errorName(err) }); + return; + }; + defer out_file.close(); + + var out_buffer = std.ArrayList(u8).init(allocator); + try generate(allocator, xml_src, out_buffer.writer()); + const tree = try std.zig.parse(allocator, out_buffer.items); + + _ = try std.zig.render(allocator, out_file.writer(), tree); +} diff --git a/generator/vulkan/build_integration.zig b/generator/vulkan/build_integration.zig index aaad5d2..8386b28 100644 --- a/generator/vulkan/build_integration.zig +++ b/generator/vulkan/build_integration.zig @@ -75,6 +75,6 @@ pub const GenerateStep = struct { try cwd.makePath(dir); const output_file = cwd.createFile(self.package.path, .{}) catch unreachable; defer output_file.close(); - _ = try std.zig.render(self.builder.allocator, output_file.outStream(), tree); + _ = try std.zig.render(self.builder.allocator, output_file.writer(), tree); } };