Custom build steps?

I am trying to achieve the following:

  • build executable
  • build assets for example: glsl to pvs in temp folder
  • install build assets
  • remove temp folder

As a start I tried making custom steps depending on each other like so:

in the main build fn

    const build_step: *std.Build.Step = try b.allocator.create(std.Build.Step);
    build_step.* = std.Build.Step.init(.{
        .id = std.Build.Step.Id.custom,
        .name = "build assets",
        .owner = exe.step.owner,
        .makeFn = buildAssets,

    const cleanup_step: *std.Build.Step = try b.allocator.create(std.Build.Step);

    cleanup_step.* = std.Build.Step.init(.{
        .id = std.Build.Step.Id.custom,
        .name = "cleanup temp assets",
        .owner = build_step.owner,
        .makeFn = cleanupTempFiles,


these are the 2 functions to run for each step:

fn cleanupTempFiles(step: *std.Build.Step, node: *std.Progress.Node) anyerror!void {
    _ = node; // autofix
    _ = step; // autofix
    std.log.debug("cleanup", .{});

fn buildAssets(step: *std.Build.Step, node: *std.Progress.Node) anyerror!void {
    _ = node; // autofix
    _ = step; // autofix
    std.log.debug("build", .{});

However I think I might have created a cyclic dependency as I get the error:

The paging file is too small for this operation to complete.



Is this the correct direction for what I am trying to achieve? And if so, how can I get the cleanup to run after the build step that runs after the build exe step?
I find it quite hard to find any information about this.

The out of memory error is resolved by allocating the steps. was a lifetime related issue. edited the code to reflect that change. The issue now is however that only the build step is called and not the cleanup step.

Ah too bad, I was just about to point that out. Well great that you figured it out on your own!
By the way I think you should consider calling b.step("name", "description") instead of manually allocating it. Then your name and description will be shown in the help menu, and it’s ensured that you don’t accidentally mess with some internal assumptions.

As for the question why cleanup isn’t called: None of your build steps depend on it. So either you have to call it from the build command zig build cleanup_temp_assets or you add a dependency: