C Header Injection into Dependancy's CSourceFiles?

Hi there,

I’m doing some experiments on implenting custom allocator functions for Raylib, specifically using Not-Nik’s bindings

I have successfully managed to use them, but I have to manually modify the raylib.h in the dependancy to include the exported functions from zig.

This feels a bit clunky and not very portable, is it possible to automate this process through the build system?

std.Build.Step.Compile has a defineCMacro, was hoping there was something along the line of includeCHeader equivalent

I found (I think?) gcc and clang has -include cmd argument to specify a header.h is it perhaps possible to call that from the main build script?

Search engines, aren’t much use these days so thought I would ask here

Hi @Mariuspersen
welcome to ziggit :slight_smile:

Why are you modifying raylib.h? (e.g. what is stopping you from adding the functions in another header file?)

Thanks!

I could do that too, the only thing I really care about is that raylib is using my allocator functions without manually modifiying the original dependancy

The question is how?

Ok, I managed to solve it.
There is probably already a built in way of doing this so this is probably entirely redundant

fn includeHeader(m: *std.Build.Module, sub_path: []const u8) void {
    const b = m.owner;
    const path = std.fs.cwd().realpathAlloc(b.allocator, sub_path) catch @panic("OOM");
    const string = b.fmt("-include{s}", .{path});

    for (m.link_objects.items) |lobj| {
        switch (lobj) {
            .c_source_file => updateFlags(
                std.Build.Module.CSourceFile,
                b,
                lobj.c_source_file,
                string,
            ),
            .c_source_files => updateFlags(
                std.Build.Module.CSourceFiles,
                b,
                lobj.c_source_files,
                string,
            ),
            else => {},
        }
    }
}

fn updateFlags(T: type, b: *std.Build, c_source_file: *T, path: []u8) void {
    if (T != std.Build.Module.CSourceFile and T != std.Build.Module.CSourceFiles) {
        @compileError("Needs to be CSourceFile or CSourceFiles");
    }
    const new_flags = b.allocator.alloc([]u8, c_source_file.flags.len + 1) catch @panic("OOM");
    for (new_flags[0..c_source_file.flags.len], c_source_file.flags) |*new_flag, old_flag| {
        new_flag.* = b.dupe(old_flag);
    }
    new_flags[new_flags.len - 1] = path;
    c_source_file.flags = new_flags;
}

So the build function ends up looking something like this:

pub fn build(b: *std.Build) !void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const raylib_dep = b.dependency("raylib-zig", .{
        .target = target,
        .optimize = optimize,
    });

    const raylib = raylib_dep.module("raylib");
    const raygui = raylib_dep.module("raygui");
    const raylib_artifact = raylib_dep.artifact("raylib");

    raylib_artifact.defineCMacro("SUPPORT_FILEFORMAT_JPG", null);
    //Added this
    includeHeader(&raylib_artifact.root_module, "src/memory.h");

    const exe = b.addExecutable(.{
        .name = "projectboat",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    exe.linkLibrary(raylib_artifact);
    exe.root_module.addImport("raylib", raylib);
    exe.root_module.addImport("raygui", raygui);

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}