forked from mirror/vulkan-zig
Merge pull request #82 from praschke/refresh-build
Update for zig build changes
This commit is contained in:
@@ -308,8 +308,6 @@ pub const ${name} align(@alignOf(u32)) = @embedFile("${path}").*;
|
|||||||
See [build.zig](build.zig) for a working example.
|
See [build.zig](build.zig) for a working example.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
* Currently, the self-hosted version of Zig's cache-hash API is not yet ready for usage, which means that the bindings are regenerated every time an executable is built.
|
|
||||||
|
|
||||||
* vulkan-zig has as of yet no functionality for selecting feature levels and extensions when generating bindings. This is because when an extension is promoted to Vulkan core, its fields and commands are renamed to lose the extensions author tag (for example, VkSemaphoreWaitFlagsKHR was renamed to VkSemaphoreWaitFlags when it was promoted from an extension to Vulkan 1.2 core). This leads to inconsistencies when only items from up to a certain feature level is included, as these promoted items then need to re-gain a tag.
|
* vulkan-zig has as of yet no functionality for selecting feature levels and extensions when generating bindings. This is because when an extension is promoted to Vulkan core, its fields and commands are renamed to lose the extensions author tag (for example, VkSemaphoreWaitFlagsKHR was renamed to VkSemaphoreWaitFlags when it was promoted from an extension to Vulkan 1.2 core). This leads to inconsistencies when only items from up to a certain feature level is included, as these promoted items then need to re-gain a tag.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vkgen = @import("generator/index.zig");
|
const vkgen = @import("generator/index.zig");
|
||||||
const Step = std.build.Step;
|
|
||||||
|
|
||||||
pub const ShaderCompileStep = vkgen.ShaderCompileStep;
|
pub const ShaderCompileStep = vkgen.ShaderCompileStep;
|
||||||
pub const VkGenerateStep = vkgen.VkGenerateStep;
|
pub const VkGenerateStep = vkgen.VkGenerateStep;
|
||||||
@@ -62,7 +61,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
const triangle_run_cmd = b.addRunArtifact(triangle_exe);
|
const triangle_run_cmd = b.addRunArtifact(triangle_exe);
|
||||||
triangle_run_cmd.step.dependOn(b.getInstallStep());
|
triangle_run_cmd.step.dependOn(b.getInstallStep());
|
||||||
triangle_run_cmd.condition = .always;
|
|
||||||
|
|
||||||
const triangle_run_step = b.step("run-triangle", "Run the triangle example");
|
const triangle_run_step = b.step("run-triangle", "Run the triangle example");
|
||||||
triangle_run_step.dependOn(&triangle_run_cmd.step);
|
triangle_run_step.dependOn(&triangle_run_cmd.step);
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const path = std.fs.path;
|
const Build = std.Build;
|
||||||
const Builder = std.build.Builder;
|
|
||||||
const Step = std.build.Step;
|
|
||||||
const GeneratedFile = std.build.GeneratedFile;
|
|
||||||
|
|
||||||
/// Utility functionality to help with compiling shaders from build.zig.
|
/// Utility functionality to help with compiling shaders from build.zig.
|
||||||
/// Invokes a shader compile command (e.g., glslc ...) for each shader
|
/// Invokes a shader compile command (e.g., glslc ...) for each shader
|
||||||
@@ -23,7 +20,7 @@ pub const ShaderCompileStep = struct {
|
|||||||
|
|
||||||
/// To ensure that if compilation options change, the shader is recompiled
|
/// To ensure that if compilation options change, the shader is recompiled
|
||||||
/// properly.
|
/// properly.
|
||||||
fn hash(self: ShaderOptions, b: *Builder, hasher: anytype) !void {
|
fn hash(self: ShaderOptions, b: *Build, hasher: anytype) !void {
|
||||||
for (self.args) |arg| {
|
for (self.args) |arg| {
|
||||||
hasher.update(arg);
|
hasher.update(arg);
|
||||||
}
|
}
|
||||||
@@ -59,8 +56,7 @@ pub const ShaderCompileStep = struct {
|
|||||||
options: ShaderOptions,
|
options: ShaderOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
step: Step,
|
step: Build.Step,
|
||||||
b: *Builder,
|
|
||||||
|
|
||||||
/// The command and optional arguments used to invoke the shader compiler.
|
/// The command and optional arguments used to invoke the shader compiler.
|
||||||
compile_command: []const []const u8,
|
compile_command: []const []const u8,
|
||||||
@@ -73,17 +69,21 @@ pub const ShaderCompileStep = struct {
|
|||||||
|
|
||||||
/// The main Zig file that contains all the shaders. Each shader is included as
|
/// The main Zig file that contains all the shaders. Each shader is included as
|
||||||
/// `pub const ${name} align(@alignOf(u32))= @embedFile("${path").*;`
|
/// `pub const ${name} align(@alignOf(u32))= @embedFile("${path").*;`
|
||||||
generated_file: GeneratedFile,
|
generated_file: Build.GeneratedFile,
|
||||||
|
|
||||||
/// Create a ShaderCompileStep for `builder`. When this step is invoked by the build
|
/// Create a ShaderCompileStep for `builder`. When this step is invoked by the build
|
||||||
/// system, `<compile_command...> <shader_source> <output_flag> <path>` is invoked for each shader.
|
/// system, `<compile_command...> <shader_source> <output_flag> <path>` is invoked for each shader.
|
||||||
/// For example, if one calls this with `create(b, "glslc", "-o")` and then
|
/// For example, if one calls this with `create(b, "glslc", "-o")` and then
|
||||||
/// `c.addShader("vertex", "vertex.glsl", .{})`, the command will be `glslc vertex.glsl -o <path>`
|
/// `c.addShader("vertex", "vertex.glsl", .{})`, the command will be `glslc vertex.glsl -o <path>`
|
||||||
pub fn create(builder: *Builder, compile_command: []const []const u8, output_flag: []const u8) *ShaderCompileStep {
|
pub fn create(builder: *Build, compile_command: []const []const u8, output_flag: []const u8) *ShaderCompileStep {
|
||||||
const self = builder.allocator.create(ShaderCompileStep) catch unreachable;
|
const self = builder.allocator.create(ShaderCompileStep) catch unreachable;
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.step = Step.init(.custom, "shaders", builder.allocator, make),
|
.step = Build.Step.init(.{
|
||||||
.b = builder,
|
.id = .custom,
|
||||||
|
.name = "shaders",
|
||||||
|
.owner = builder,
|
||||||
|
.makeFn = make,
|
||||||
|
}),
|
||||||
.compile_command = builder.dupeStrings(compile_command),
|
.compile_command = builder.dupeStrings(compile_command),
|
||||||
.output_flag = builder.dupe(output_flag),
|
.output_flag = builder.dupe(output_flag),
|
||||||
.shaders = std.ArrayList(Shader).init(builder.allocator),
|
.shaders = std.ArrayList(Shader).init(builder.allocator),
|
||||||
@@ -94,14 +94,14 @@ pub const ShaderCompileStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the shaders module with name.
|
/// Returns the shaders module with name.
|
||||||
pub fn getModule(self: *ShaderCompileStep) *std.build.Module {
|
pub fn getModule(self: *ShaderCompileStep) *Build.Module {
|
||||||
return self.b.createModule(.{
|
return self.step.owner.createModule(.{
|
||||||
.source_file = self.getSource(),
|
.source_file = self.getSource(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the file source for the generated shader resource code.
|
/// Returns the file source for the generated shader resource code.
|
||||||
pub fn getSource(self: *ShaderCompileStep) std.build.FileSource {
|
pub fn getSource(self: *ShaderCompileStep) Build.FileSource {
|
||||||
return .{ .generated = &self.generated_file };
|
return .{ .generated = &self.generated_file };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,8 @@ pub const ShaderCompileStep = struct {
|
|||||||
/// This path can then be used to include the binary into an executable, for example by passing it
|
/// This path can then be used to include the binary into an executable, for example by passing it
|
||||||
/// to @embedFile via an additional generated file.
|
/// to @embedFile via an additional generated file.
|
||||||
pub fn add(self: *ShaderCompileStep, name: []const u8, src: []const u8, options: ShaderOptions) void {
|
pub fn add(self: *ShaderCompileStep, name: []const u8, src: []const u8, options: ShaderOptions) void {
|
||||||
const full_source_path = self.b.build_root.join(self.b.allocator, &.{src}) catch unreachable;
|
const b = self.step.owner;
|
||||||
|
const full_source_path = b.build_root.join(b.allocator, &.{src}) catch unreachable;
|
||||||
self.shaders.append(.{
|
self.shaders.append(.{
|
||||||
.name = name,
|
.name = name,
|
||||||
.source_path = full_source_path,
|
.source_path = full_source_path,
|
||||||
@@ -120,8 +121,9 @@ pub const ShaderCompileStep = struct {
|
|||||||
|
|
||||||
/// Create a hash of a shader's source contents.
|
/// Create a hash of a shader's source contents.
|
||||||
fn hashShaderToFileName(self: *ShaderCompileStep, shader: Shader) ![64]u8 {
|
fn hashShaderToFileName(self: *ShaderCompileStep, shader: Shader) ![64]u8 {
|
||||||
|
const b = self.step.owner;
|
||||||
const source = std.fs.cwd().readFileAlloc(
|
const source = std.fs.cwd().readFileAlloc(
|
||||||
self.b.allocator,
|
b.allocator,
|
||||||
shader.source_path,
|
shader.source_path,
|
||||||
std.math.maxInt(usize),
|
std.math.maxInt(usize),
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
@@ -140,7 +142,7 @@ pub const ShaderCompileStep = struct {
|
|||||||
hasher.update(source);
|
hasher.update(source);
|
||||||
// Not only the shader source must be the same to ensure uniqueness -
|
// Not only the shader source must be the same to ensure uniqueness -
|
||||||
// the compilation options must be the same as well!
|
// the compilation options must be the same as well!
|
||||||
try shader.options.hash(self.b, &hasher);
|
try shader.options.hash(b, &hasher);
|
||||||
// And the compile command, too.
|
// And the compile command, too.
|
||||||
for (self.compile_command) |cmd| {
|
for (self.compile_command) |cmd| {
|
||||||
hasher.update(cmd);
|
hasher.update(cmd);
|
||||||
@@ -159,26 +161,28 @@ pub const ShaderCompileStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Internal build function.
|
/// Internal build function.
|
||||||
fn make(step: *Step) !void {
|
fn make(step: *Build.Step, progress: *std.Progress.Node) !void {
|
||||||
|
_ = progress;
|
||||||
|
const b = step.owner;
|
||||||
const self = @fieldParentPtr(ShaderCompileStep, "step", step);
|
const self = @fieldParentPtr(ShaderCompileStep, "step", step);
|
||||||
const cwd = std.fs.cwd();
|
const cwd = std.fs.cwd();
|
||||||
|
|
||||||
var cmd = std.ArrayList([]const u8).init(self.b.allocator);
|
var cmd = std.ArrayList([]const u8).init(b.allocator);
|
||||||
try cmd.appendSlice(self.compile_command);
|
try cmd.appendSlice(self.compile_command);
|
||||||
const base_cmd_len = cmd.items.len;
|
const base_cmd_len = cmd.items.len;
|
||||||
|
|
||||||
var shaders_file_contents = std.ArrayList(u8).init(self.b.allocator);
|
var shaders_file_contents = std.ArrayList(u8).init(b.allocator);
|
||||||
const shaders_out = shaders_file_contents.writer();
|
const shaders_out = shaders_file_contents.writer();
|
||||||
|
|
||||||
const shaders_dir = try self.b.cache_root.join(
|
const shaders_dir = try b.cache_root.join(
|
||||||
self.b.allocator,
|
b.allocator,
|
||||||
&.{cache_dir},
|
&.{cache_dir},
|
||||||
);
|
);
|
||||||
try cwd.makePath(shaders_dir);
|
try cwd.makePath(shaders_dir);
|
||||||
|
|
||||||
for (self.shaders.items) |shader| {
|
for (self.shaders.items) |shader| {
|
||||||
const shader_basename = try self.hashShaderToFileName(shader);
|
const shader_basename = try self.hashShaderToFileName(shader);
|
||||||
const shader_out_path = try std.fs.path.join(self.b.allocator, &.{
|
const shader_out_path = try std.fs.path.join(b.allocator, &.{
|
||||||
shaders_dir,
|
shaders_dir,
|
||||||
&shader_basename,
|
&shader_basename,
|
||||||
});
|
});
|
||||||
@@ -203,7 +207,7 @@ pub const ShaderCompileStep = struct {
|
|||||||
|
|
||||||
try cmd.appendSlice(shader.options.args);
|
try cmd.appendSlice(shader.options.args);
|
||||||
try cmd.appendSlice(&.{ shader.source_path, self.output_flag, shader_out_path });
|
try cmd.appendSlice(&.{ shader.source_path, self.output_flag, shader_out_path });
|
||||||
try self.b.spawnChild(cmd.items);
|
try step.evalChildProcess(cmd.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a file name for the shaders zig source based on the contents of shaders_file_contents.
|
// Generate a file name for the shaders zig source based on the contents of shaders_file_contents.
|
||||||
@@ -214,7 +218,7 @@ pub const ShaderCompileStep = struct {
|
|||||||
hasher.update(shaders_file_contents.items);
|
hasher.update(shaders_file_contents.items);
|
||||||
|
|
||||||
const shaders_path = try std.fs.path.join(
|
const shaders_path = try std.fs.path.join(
|
||||||
self.b.allocator,
|
b.allocator,
|
||||||
&.{ shaders_dir, &digest(&hasher) },
|
&.{ shaders_dir, &digest(&hasher) },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const generator = @import("generator.zig");
|
const generator = @import("generator.zig");
|
||||||
const path = std.fs.path;
|
|
||||||
const Build = std.Build;
|
const Build = std.Build;
|
||||||
const Step = Build.Step;
|
|
||||||
|
|
||||||
/// build.zig integration for Vulkan binding generation. This step can be used to generate
|
/// build.zig integration for Vulkan binding generation. This step can be used to generate
|
||||||
/// Vulkan bindings at compiletime from vk.xml, by providing the path to vk.xml and the output
|
/// Vulkan bindings at compiletime from vk.xml, by providing the path to vk.xml and the output
|
||||||
/// path relative to zig-cache. The final package can then be obtained by `package()`, the result
|
/// path relative to zig-cache. The final package can then be obtained by `package()`, the result
|
||||||
/// of which can be added to the project using `std.Build.addModule`.
|
/// of which can be added to the project using `std.Build.addModule`.
|
||||||
pub const GenerateStep = struct {
|
pub const GenerateStep = struct {
|
||||||
step: Step,
|
step: Build.Step,
|
||||||
builder: *Build,
|
generated_file: Build.GeneratedFile,
|
||||||
generated_file: std.build.GeneratedFile,
|
|
||||||
/// The path to vk.xml
|
/// The path to vk.xml
|
||||||
spec_path: []const u8,
|
spec_path: []const u8,
|
||||||
/// The API to generate for.
|
/// The API to generate for.
|
||||||
@@ -25,8 +22,12 @@ pub const GenerateStep = struct {
|
|||||||
pub fn create(builder: *Build, spec_path: []const u8) *GenerateStep {
|
pub fn create(builder: *Build, spec_path: []const u8) *GenerateStep {
|
||||||
const self = builder.allocator.create(GenerateStep) catch unreachable;
|
const self = builder.allocator.create(GenerateStep) catch unreachable;
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.step = Step.init(.custom, "vulkan-generate", builder.allocator, make),
|
.step = Build.Step.init(.{
|
||||||
.builder = builder,
|
.id = .custom,
|
||||||
|
.name = "vulkan-generate",
|
||||||
|
.owner = builder,
|
||||||
|
.makeFn = make,
|
||||||
|
}),
|
||||||
.generated_file = .{
|
.generated_file = .{
|
||||||
.step = &self.step,
|
.step = &self.step,
|
||||||
},
|
},
|
||||||
@@ -54,14 +55,14 @@ pub const GenerateStep = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the module with the generated budings, with name `module_name`.
|
/// Returns the module with the generated budings, with name `module_name`.
|
||||||
pub fn getModule(self: *GenerateStep) *std.build.Module {
|
pub fn getModule(self: *GenerateStep) *Build.Module {
|
||||||
return self.builder.createModule(.{
|
return self.step.owner.createModule(.{
|
||||||
.source_file = self.getSource(),
|
.source_file = self.getSource(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the file source for the generated bindings.
|
/// Returns the file source for the generated bindings.
|
||||||
pub fn getSource(self: *GenerateStep) std.build.FileSource {
|
pub fn getSource(self: *GenerateStep) Build.FileSource {
|
||||||
return .{ .generated = &self.generated_file };
|
return .{ .generated = &self.generated_file };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,34 +70,31 @@ pub const GenerateStep = struct {
|
|||||||
/// the final bindings. The resulting generated bindings are not formatted, which is why an ArrayList
|
/// the final bindings. 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
|
/// 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.
|
/// by parsing it and rendering with `std.zig.parse` and `std.zig.render` respectively.
|
||||||
fn make(step: *Step) !void {
|
fn make(step: *Build.Step, progress: *std.Progress.Node) !void {
|
||||||
|
_ = progress;
|
||||||
|
const b = step.owner;
|
||||||
const self = @fieldParentPtr(GenerateStep, "step", step);
|
const self = @fieldParentPtr(GenerateStep, "step", step);
|
||||||
const cwd = std.fs.cwd();
|
const cwd = std.fs.cwd();
|
||||||
|
|
||||||
var man = self.builder.cache.obtain();
|
var man = b.cache.obtain();
|
||||||
defer man.deinit();
|
defer man.deinit();
|
||||||
|
|
||||||
const spec = try cwd.readFileAlloc(self.builder.allocator, self.spec_path, std.math.maxInt(usize));
|
const spec = try cwd.readFileAlloc(b.allocator, self.spec_path, std.math.maxInt(usize));
|
||||||
// TODO: Look into whether this is the right way to be doing
|
// TODO: Look into whether this is the right way to be doing
|
||||||
// this - maybe the file-level caching API has some benefits I
|
// this - maybe the file-level caching API has some benefits I
|
||||||
// don't understand.
|
// don't understand.
|
||||||
man.hash.addBytes(spec);
|
man.hash.addBytes(spec);
|
||||||
|
|
||||||
const already_exists = man.hit() catch |err| @panic(switch (err) {
|
const already_exists = try step.cacheHit(&man);
|
||||||
inline else => |e| "Cache error: " ++ @errorName(e),
|
|
||||||
});
|
|
||||||
const digest = man.final();
|
const digest = man.final();
|
||||||
const output_file_path = try self.builder.cache_root.join(
|
const output_file_path = try b.cache_root.join(b.allocator, &.{ "o", &digest, "vk.zig" });
|
||||||
self.builder.allocator,
|
|
||||||
&.{ "o", &digest, "vk.zig" },
|
|
||||||
);
|
|
||||||
if (already_exists) {
|
if (already_exists) {
|
||||||
self.generated_file.path = output_file_path;
|
self.generated_file.path = output_file_path;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var out_buffer = std.ArrayList(u8).init(self.builder.allocator);
|
var out_buffer = std.ArrayList(u8).init(b.allocator);
|
||||||
generator.generate(self.builder.allocator, self.api, spec, out_buffer.writer()) catch |err| switch (err) {
|
generator.generate(b.allocator, self.api, spec, out_buffer.writer()) catch |err| switch (err) {
|
||||||
error.InvalidXml => {
|
error.InvalidXml => {
|
||||||
std.log.err("invalid vulkan registry - invalid xml", .{});
|
std.log.err("invalid vulkan registry - invalid xml", .{});
|
||||||
std.log.err("please check that the correct vk.xml file is passed", .{});
|
std.log.err("please check that the correct vk.xml file is passed", .{});
|
||||||
@@ -118,10 +116,10 @@ pub const GenerateStep = struct {
|
|||||||
try out_buffer.append(0);
|
try out_buffer.append(0);
|
||||||
|
|
||||||
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(self.builder.allocator, src, .zig);
|
const tree = try std.zig.Ast.parse(b.allocator, src, .zig);
|
||||||
std.debug.assert(tree.errors.len == 0); // If this triggers, vulkan-zig produced invalid code.
|
std.debug.assert(tree.errors.len == 0); // If this triggers, vulkan-zig produced invalid code.
|
||||||
|
|
||||||
const formatted = try tree.render(self.builder.allocator);
|
const formatted = try tree.render(b.allocator);
|
||||||
|
|
||||||
const output_dir_path = std.fs.path.dirname(output_file_path).?;
|
const output_dir_path = std.fs.path.dirname(output_file_path).?;
|
||||||
cwd.makePath(output_dir_path) catch |err| {
|
cwd.makePath(output_dir_path) catch |err| {
|
||||||
@@ -131,6 +129,6 @@ pub const GenerateStep = struct {
|
|||||||
|
|
||||||
try cwd.writeFile(output_file_path, formatted);
|
try cwd.writeFile(output_file_path, formatted);
|
||||||
self.generated_file.path = output_file_path;
|
self.generated_file.path = output_file_path;
|
||||||
try man.writeManifest();
|
try step.writeManifest(&man);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user