Open silversquirl opened 2 years ago
Isn't one of the members of FileSource
generated: *const GeneratedFile
? Wherein GeneratedFile
has a member step: *Step
, which I assume is meant to be used to, well, generate a file.
Yes, that's my point. FileSource
cannot currently be used with addIncludeDir
Alright, but that doesn't mean there is no way to handle generated header files as a build dependency; you would just need to define a step that depends on a file being generated (e.g., std.build.Step.dependOn(&generated_file.step)
), which holds a reference to said Step, and a reference to a LibExeObjStep
, and then in its make
function, does something like self.lib_exe_obj.addIncludeDir(self.file_source.path)
; you would of course also make the LibExeObjStep
depend on this step. I would try to write up an example, but I'm not in the best of circumstances to do so.
Or do you mean that the functionality provided in std.build
does not offer a direct way to do so like it does with addIncludeDir
? In which case you could propose to add such functionality.
Interesting workaround, I'll give that a shot. Would still be nice to be able to do it directly, like you can for most other things (eg. generated C sources are no problem, you can just call addCSourceFileSource
with a FileSource
).
I came up with a pretty simple general-ish solution that solves for this problem, and mayhaps others:
pub fn addClosureStep(b: *std.build.Builder, name: []const u8, comptime function: anytype, args: std.meta.Tuple(@typeInfo(@TypeOf(function)).Fn.args)) *ClosureStep(function) {
return ClosureStep(function).create(b.allocator, name, args) catch unreachable;
}
pub fn ClosureStep(comptime function: anytype) type {
const Function = @TypeOf(function);
const ArgsTuple = std.meta.ArgsTuple(Function);
return struct {
const Self = @This();
step: std.build.Step,
args: ArgsTuple,
pub fn create(allocator: *std.mem.Allocator, name: []const u8, args: ArgsTuple) !*Self {
const result = try allocator.create(Self);
errdefer allocator.destroy(result);
result.args = args;
result.step = std.build.Step.init(.custom, name, allocator, Self.make);
return result;
}
pub fn make(step: *std.build.Step) anyerror!void {
const self = @fieldParentPtr(Self, "step", step);
@call(.{}, function, self.args);
}
};
}
You could then do something like:
// ...
const translate_c_add = b.addTranslateC(.{ .path = b.pathFromRoot("c/add.h") });
const add_include_dir_of_file_source = addClosureStep(b, "add-include-dir", struct {
fn addIncludeDirOfFileSource(target: *std.build.LibExeObjStep, source: std.build.FileSource) void {
target.addIncludeDir(std.fs.path.dirname(file_source.getPath(target.builder)).?);
}
}.addIncludeDirOfFileSource, .{ .@"0" = exe, .@"1" = translate_c_add }); // ignore this, it's just a work around for '.{ exe, translate_c_add }' not coercing to 'std.meta.ArgsTuple(@TypeOf(function))' for whatever reason.
exe.step.dependOn(&add_include_dir_of_file_source.step);
// ...
I've tried it, and it certainly seems to work. Don't know if something like this is warranted in std.build
though, given that it really is simple enough to implement yourself.
Related PR, but not closing issue yet: https://github.com/ziglang/zig/pull/13742
Any update on this?
@Ev1lT3rm1nal #13742 and #14382 got implemented. I think that means this issue is fixed. Do you have a use case not covered by those?
Some software written in C generates header files at build time (eg. to embed a file using
xxd -i
). To be able to build this software properly, the Zig build system needs to handle this.It's possible to hardcode a path and always put the generated file in the same place, but ideally
FileSource
could be used (thoughFileSource
isn't really meant for generated directories, so maybe just something similar).