Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
silversquirl opened this issue Nov 1, 2021 · 9 comments
Open

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

silversquirl opened this issue Nov 1, 2021 · 9 comments
Labels
zig build system std.Build, the build runner, `zig build` subcommand, package management
Milestone

Comments

@silversquirl
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor Author

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

@InKryption
Copy link
Contributor

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
Copy link
Contributor Author

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
Copy link
Contributor

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.

@jayschwa jayschwa added the zig build system std.Build, the build runner, `zig build` subcommand, package management label Nov 8, 2021
@andrewrk andrewrk added this to the 0.10.0 milestone Nov 20, 2021
@matu3ba
Copy link
Contributor

matu3ba commented Jan 3, 2023

Related PR, but not closing issue yet: #13742

@david-vanderson
Copy link
Contributor

See #14382

@Ev1lT3rm1nal
Copy link

Any update on this?

@david-vanderson
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
zig build system std.Build, the build runner, `zig build` subcommand, package management
Projects
None yet
Development

No branches or pull requests

7 participants