forked from mirror/vulkan-zig
improve error handling of generator tool
This now also prints more detailed error messages, similar to the build step.
This commit is contained in:
@@ -1,23 +1,19 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const generator = @import("vulkan/generator.zig");
|
const generator = @import("vulkan/generator.zig");
|
||||||
|
|
||||||
const usage =
|
fn invalidUsage(prog_name: []const u8, comptime fmt: []const u8, args: anytype) noreturn {
|
||||||
\\Usage: {s} [options] <spec xml path> <output zig source>
|
std.log.err(fmt, args);
|
||||||
\\Options:
|
std.log.err("see {s} --help for usage", .{prog_name});
|
||||||
\\-h --help show this message and exit.
|
std.process.exit(1);
|
||||||
\\-a --api <api> Generate API for 'vulkan' or 'vulkansc'. Defaults to 'vulkan'.
|
}
|
||||||
\\
|
|
||||||
;
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
const stderr = std.io.getStdErr();
|
|
||||||
|
|
||||||
|
pub fn main() void {
|
||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||||
defer arena.deinit();
|
defer arena.deinit();
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
var args = try std.process.argsWithAllocator(allocator);
|
var args = try std.process.argsWithAllocator(allocator);
|
||||||
const prog_name = args.next() orelse return error.ExecutableNameMissing;
|
const prog_name = args.next() orelse "vulkan-zig-generator";
|
||||||
|
|
||||||
var maybe_xml_path: ?[]const u8 = null;
|
var maybe_xml_path: ?[]const u8 = null;
|
||||||
var maybe_out_path: ?[]const u8 = null;
|
var maybe_out_path: ?[]const u8 = null;
|
||||||
@@ -26,7 +22,7 @@ pub fn main() !void {
|
|||||||
while (args.next()) |arg| {
|
while (args.next()) |arg| {
|
||||||
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
if (std.mem.eql(u8, arg, "--help") or std.mem.eql(u8, arg, "-h")) {
|
||||||
@setEvalBranchQuota(2000);
|
@setEvalBranchQuota(2000);
|
||||||
try stderr.writer().print(
|
std.io.getStdOut().writer().print(
|
||||||
\\Utility to generate a Zig binding from the Vulkan XML API registry.
|
\\Utility to generate a Zig binding from the Vulkan XML API registry.
|
||||||
\\
|
\\
|
||||||
\\The most recent Vulkan XML API registry can be obtained from
|
\\The most recent Vulkan XML API registry can be obtained from
|
||||||
@@ -34,64 +30,98 @@ pub fn main() !void {
|
|||||||
\\and the most recent LunarG Vulkan SDK version can be found at
|
\\and the most recent LunarG Vulkan SDK version can be found at
|
||||||
\\$VULKAN_SDK/x86_64/share/vulkan/registry/vk.xml.
|
\\$VULKAN_SDK/x86_64/share/vulkan/registry/vk.xml.
|
||||||
\\
|
\\
|
||||||
|
\\Usage: {s} [options] <spec xml path> <output zig source>
|
||||||
|
\\Options:
|
||||||
|
\\-h --help show this message and exit.
|
||||||
|
\\-a --api <api> Generate API for 'vulkan' or 'vulkansc'. Defaults to 'vulkan'.
|
||||||
\\
|
\\
|
||||||
++ usage,
|
,
|
||||||
.{prog_name},
|
.{prog_name},
|
||||||
);
|
) catch |err| {
|
||||||
|
std.log.err("failed to write to stdout: {s}", .{@errorName(err)});
|
||||||
|
std.process.exit(1);
|
||||||
|
};
|
||||||
return;
|
return;
|
||||||
} else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--api")) {
|
} else if (std.mem.eql(u8, arg, "-a") or std.mem.eql(u8, arg, "--api")) {
|
||||||
const api_str = args.next() orelse {
|
const api_str = args.next() orelse {
|
||||||
try stderr.writer().print("Error: {s} expects argument <api>\n", .{arg});
|
invalidUsage(prog_name, "{s} expects argument <api>", .{arg});
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
api = std.meta.stringToEnum(generator.Api, api_str) orelse {
|
api = std.meta.stringToEnum(generator.Api, api_str) orelse {
|
||||||
try stderr.writer().print("Error: Invalid api '{s}'", .{api_str});
|
invalidUsage(prog_name, "invalid api '{s}'", .{api_str});
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
} else if (maybe_xml_path == null) {
|
} else if (maybe_xml_path == null) {
|
||||||
maybe_xml_path = arg;
|
maybe_xml_path = arg;
|
||||||
} else if (maybe_out_path == null) {
|
} else if (maybe_out_path == null) {
|
||||||
maybe_out_path = arg;
|
maybe_out_path = arg;
|
||||||
} else {
|
} else {
|
||||||
try stderr.writer().print("Error: Superficial argument '{s}'\n", .{arg});
|
invalidUsage(prog_name, "superficial argument '{s}'", .{arg});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const xml_path = maybe_xml_path orelse {
|
const xml_path = maybe_xml_path orelse {
|
||||||
try stderr.writer().print("Error: Missing required argument <spec xml path>\n" ++ usage, .{prog_name});
|
invalidUsage(prog_name, "missing required argument <spec xml path>", .{});
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const out_path = maybe_out_path orelse {
|
const out_path = maybe_out_path orelse {
|
||||||
try stderr.writer().print("Error: Missing required argument <output zig source>\n" ++ usage, .{prog_name});
|
invalidUsage(prog_name, "missing required argument <output zig source>", .{});
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const cwd = std.fs.cwd();
|
const cwd = std.fs.cwd();
|
||||||
const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| {
|
const xml_src = cwd.readFileAlloc(allocator, xml_path, std.math.maxInt(usize)) catch |err| {
|
||||||
try stderr.writer().print("Error: Failed to open input file '{s}' ({s})\n", .{ xml_path, @errorName(err) });
|
std.log.err("failed to open input file '{s}' ({s})", .{ xml_path, @errorName(err) });
|
||||||
return;
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
var out_buffer = std.ArrayList(u8).init(allocator);
|
var out_buffer = std.ArrayList(u8).init(allocator);
|
||||||
try generator.generate(allocator, api, xml_src, out_buffer.writer());
|
generator.generate(allocator, api, xml_src, out_buffer.writer()) catch |err| switch (err) {
|
||||||
try out_buffer.append(0);
|
error.InvalidXml => {
|
||||||
|
std.log.err("invalid vulkan registry - invalid xml", .{});
|
||||||
|
std.log.err("please check that the correct vk.xml file is passed", .{});
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
error.InvalidRegistry => {
|
||||||
|
std.log.err("invalid vulkan registry - registry is valid xml but contents are invalid", .{});
|
||||||
|
std.log.err("please check that the correct vk.xml file is passed", .{});
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
error.UnhandledBitfieldStruct => {
|
||||||
|
std.log.err("unhandled struct with bit fields detected in vk.xml", .{});
|
||||||
|
std.log.err("this is a bug in vulkan-zig", .{});
|
||||||
|
std.log.err("please make a bug report at https://github.com/Snektron/vulkan-zig/issues/", .{});
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
error.OutOfMemory => @panic("oom"),
|
||||||
|
};
|
||||||
|
|
||||||
|
out_buffer.append(0) catch @panic("oom");
|
||||||
|
|
||||||
const src = out_buffer.items[0 .. out_buffer.items.len - 1 :0];
|
const src = out_buffer.items[0 .. out_buffer.items.len - 1 :0];
|
||||||
const tree = try std.zig.Ast.parse(allocator, src, .zig);
|
const tree = std.zig.Ast.parse(allocator, src, .zig) catch |err| switch (err) {
|
||||||
const formatted = try tree.render(allocator);
|
error.OutOfMemory => @panic("oom"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tree.errors.len > 0) {
|
||||||
|
std.log.err("generated invalid zig code", .{});
|
||||||
|
std.log.err("this is a bug in vulkan-zig", .{});
|
||||||
|
std.log.err("please make a bug report at https://github.com/Snektron/vulkan-zig/issues/", .{});
|
||||||
|
|
||||||
|
std.process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = tree.render(allocator) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => @panic("oom"),
|
||||||
|
};
|
||||||
defer allocator.free(formatted);
|
defer allocator.free(formatted);
|
||||||
|
|
||||||
if (std.fs.path.dirname(out_path)) |dir| {
|
if (std.fs.path.dirname(out_path)) |dir| {
|
||||||
cwd.makePath(dir) catch |err| {
|
cwd.makePath(dir) catch |err| {
|
||||||
try stderr.writer().print("Error: Failed to create output directory '{s}' ({s})\n", .{ dir, @errorName(err) });
|
std.log.err("failed to create output directory '{s}' ({s})", .{ dir, @errorName(err) });
|
||||||
return;
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd.writeFile(out_path, formatted) catch |err| {
|
cwd.writeFile(out_path, formatted) catch |err| {
|
||||||
try stderr.writer().print("Error: Failed to write to output file '{s}' ({s})\n", .{ out_path, @errorName(err) });
|
std.log.err("failed to write to output file '{s}' ({s})", .{ out_path, @errorName(err) });
|
||||||
return;
|
std.process.exit(1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,7 +300,6 @@ fn lenToPointer(fields: Fields, len: []const u8) std.meta.Tuple(&.{ registry.Poi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.Element) !void {
|
fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.Element) !void {
|
||||||
|
|
||||||
var len_attribute_depth: usize = 0;
|
var len_attribute_depth: usize = 0;
|
||||||
|
|
||||||
if (elem.getAttribute("len")) |lens| {
|
if (elem.getAttribute("len")) |lens| {
|
||||||
@@ -327,7 +326,6 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var current_depth: usize = 0;
|
var current_depth: usize = 0;
|
||||||
|
|
||||||
if (elem.getAttribute("optional")) |optionals| {
|
if (elem.getAttribute("optional")) |optionals| {
|
||||||
@@ -342,8 +340,7 @@ fn parsePointerMeta(fields: Fields, type_info: *registry.TypeInfo, elem: *xml.El
|
|||||||
is_already_optional = current_type_info.pointer.is_optional;
|
is_already_optional = current_type_info.pointer.is_optional;
|
||||||
|
|
||||||
current_type_info.pointer.is_optional =
|
current_type_info.pointer.is_optional =
|
||||||
is_already_optional or mem.eql(u8, optional_str, "true");
|
is_already_optional or mem.eql(u8, optional_str, "true");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// There is no information for this pointer, probably incorrect.
|
// There is no information for this pointer, probably incorrect.
|
||||||
// Currently there is one definition where this is the case, VkCudaLaunchInfoNV.
|
// Currently there is one definition where this is the case, VkCudaLaunchInfoNV.
|
||||||
|
|||||||
Reference in New Issue
Block a user