Better way to patch file with zig?

Hoi.

In my first Zig project I needed to patch the header file of miniaudio with some « anyopaque » pointer since otherwise zig would not correctly understand I can pass a struct pointer to the right place (it’s a bug already reported).

For that I use this code to run the patch command and create inside of the build system a patched version. But I have now the issue Windows don’t have a native patch command.

fn prepareMiniaudio(b: *std.Build) std.Build.LazyPath {
    if (builtin.os.tag == .windows) {
        const tool_run = b.addSystemCommand(&.{"C:/Program Files/Git/usr/bin/patch"});
        tool_run.addFileArg(b.path("src/miniaudio/miniaudio.h"));

        tool_run.addArg("-o");
        const ret = tool_run.addOutputFileArg("miniaudio.h");
        tool_run.addFileArg(b.path("src/miniaudio/zig_18247.patch"));
        b.getInstallStep().dependOn(&tool_run.step);
        return ret;
    }

    const tool_run = b.addSystemCommand(&.{"patch"});
    tool_run.addFileArg(b.path("src/miniaudio/miniaudio.h"));

    tool_run.addArg("-o");
    const ret = tool_run.addOutputFileArg("miniaudio.h");
    tool_run.addFileArg(b.path("src/miniaudio/zig_18247.patch"));
    b.getInstallStep().dependOn(&tool_run.step);
    return ret;
}

Do anyone have an idea on how to improve windows ? I have some ideas of using the zig package manager to download a version of gnu patch windows for directly using it inside of the build pipeline but my issues are this build is very old and so ask Windows administrators permission (yeah I know it’s a patch command) but also downloading arbitrary programs on the internet to execute feel odd.

For now I did use a temporary absolute path but maybe I should just add as requirements to have a patch.exe in the path.

For ziglua I apply a small patch with the build system to the Lua 5.1 sources using a Zig program I wrote. It’s not the best code, and it is only enough to apply a small patch file in my specific case. But the code could be improved and made to work for all patch files.

patch.zig: ziglua/build/lua.zig at d9a158505912396f304b89c0e688effe5aeb4918 · natecraddock/ziglua · GitHub

Used here: ziglua/build/lua.zig at d9a158505912396f304b89c0e688effe5aeb4918 · natecraddock/ziglua · GitHub

The idea is you can compile an executable as part of the build process. Then run that executable and the output can be used as an input file

// Patch ldo.c for Lua 5.1
if (lang == .lua51) {
    const patched = patchFile(b, target, lib, upstream.path("src/ldo.c"), b.path("build/lua-5.1.patch"));
    lib.addCSourceFile(.{ .file = patched, .flags = &flags });
}

If you don’t want to download pre-built executables, add as a dependency a repository that contains a source version of an implementation of patch, build it yourself in as part the build pipeline and then execute it with b.runArtifact

2 Likes

Oh yes I didn’t think about this route, I was thinking the best thing was maybe to recreate an equivalent of GNU patch in zig but I can just fetch a zip of the source of GNU patch and build it in the Windows build path ^^

After I still think your tiny version of patch in zig would work for me. But I will first try the kristoff solution ^^

GNU software sometimes is pretty annoying to build, if you discover that it has a bunch of dependencies then pivoting to something else might not be a bad idea.

But if you do end up writing a build.zig for patch, consider gifting the repo to All Your Codebase · GitHub :^)

I wonder if git-apply can be used instead of a dedicated patch tool:

The user most likely got the code to build via git, so the tool must exist and is most likely also in the path.

I never tried manually applying patches via git though.

1 Like

There’s a Zig port of DiffMatchPatch called diffz. I’m linking to my fork, because I completed the match and patch parts, and the pull request for that work is not yet merged.

I use it in ohsnap to provide a visible diff of snapshots which don’t pass, so it’s out in the wild, if you will.

It does pass the test suite with complete line coverage, which is not a guarantee of correctness: as Djikstra famously observed, tests can prove the presence of bugs, but not their absence. But it may be effective for your use case.

3 Likes