I’m making a custom build step to execute godot --headless --dump-gdextension-interface and godot --headless --dump-extension-api which create files at the current working directory. They do not take an output file argument, nor will they output to stdout, so I can’t use std.Build.Step.Run. I made my own DumpGodotInterfaces step by referencing std/Build/Step/Run.zig and it does do what I want it to, and I can pass a LazyPath pointing to gdextension_interface.h to a TranslateC step.
Now my problem, I tried to make it cache, but it’s not, I guess. It outputs directly to a cache directory, and I can find it in there by running find -name "gdextension_interface.h" in the .zig-cache directory, but it still reruns the commands every build, so I can only assume I’m not using that manifest thing correctly.
Here is the make function whom I put many comments in for the sake of this post:
pub fn make(step: *std.Build.Step, options: std.Build.Step.MakeOptions) !void {
const b = step.owner;
const io = b.graph.io;
const self: *@This() = @fieldParentPtr("step", step);
_ = options;
// this is the only part I'm sure I'm supposed to do
var manifest = b.graph.cache.obtain();
defer manifest.deinit();
// version of godot being dumped, currently hard coded and not checked against :P
manifest.hash.add(std.SemanticVersion{ .major = 4, .minor = 7, .patch = 0 });
// not really sure what this does even after reading the code, but I get FileNotFound if this is not present or is anywhere else
const cached = try step.cacheHitAndWatch(&manifest);
// I already know where the files go at this point probably
const output_path = try b.cache_root.join(b.allocator, &.{ "o", &manifest.final() });
// the GeneratedFiles are just struct fields but theres also .interface_header: LazyPath and .api_schema: LazyPath whose .generated are these
self.interface_header_file.path = b.pathJoin(&.{ output_path, "gdextension_interface.h" });
self.api_schema_file.path = b.pathJoin(&.{ output_path, "extension_api.json" });
// this is never true I guess
if (cached) {
return;
}
// surely the cache directory already exists if it's cached, so this is after
b.cache_root.handle.createDirPath(io, output_path) catch |err| {
// I think I just took this stuff out of Build.Step.Run
return step.fail("unable to make path '{f}{s}': {s}", .{
b.cache_root, output_path, @errorName(err),
});
};
// these'll run at the same time
var child1 = try std.process.spawn(io, .{ .cwd = .{ .path = output_path }, .argv = &.{ "godot", "--headless", "--dump-gdextension-interface" } }); // creates ./gdextension_interface.h file
var child2 = try std.process.spawn(io, .{ .cwd = .{ .path = output_path }, .argv = &.{ "godot", "--headless", "--dump-extension-api" } }); // creates ./extension_api.json file
_ = try child1.wait(io);
_ = try child2.wait(io);
}
zig 0.16.0 btw. I would’ve just given this up and let it not cache if it weren’t for zls not giving me completions for it’s corresponding module.