ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.35k stars 2.43k forks source link

Build system has no way to handle generated header files #10089

Open silversquirl opened 2 years ago

silversquirl commented 2 years ago

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 (though FileSource isn't really meant for generated directories, so maybe just something similar).

InKryption commented 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.

silversquirl commented 2 years ago

Yes, that's my point. FileSource cannot currently be used with addIncludeDir

InKryption commented 2 years ago

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.

silversquirl commented 2 years ago

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).

InKryption commented 2 years ago

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.

matu3ba commented 1 year ago

Related PR, but not closing issue yet: https://github.com/ziglang/zig/pull/13742

david-vanderson commented 1 year ago

See https://github.com/ziglang/zig/pull/14382

Ev1lT3rm1nal commented 1 year ago

Any update on this?

david-vanderson commented 1 year ago

@Ev1lT3rm1nal #13742 and #14382 got implemented. I think that means this issue is fixed. Do you have a use case not covered by those?