Zig NEWS

Cover image for Cool Zig Patterns - Paths in Build Scripts
Felix "xq" Queißner
Felix "xq" Queißner

Posted on

Cool Zig Patterns - Paths in Build Scripts

I'm using a pattern to have paths in build files that are relative to the build file instead of the build root folder.

This pattern looked like this:

/// DEPRECATED, DO NOT USE
fn sdkRoot() []const u8 {
    return std.fs.path.dirname(@src().file) orelse ".";
}

...
{
  var path = sdkRoot() ++ "/src/main.zig"; // get a nice path
}
...
Enter fullscreen mode Exit fullscreen mode

The problem with this is that with the new stage2 compiler, the ++ operator now has new semantics that make the operation above a runtime operation, and thus path a pointer-to-temporary, not a pointer-to-comptime-memory.

But there's a nice alternative one can use:

fn sdkPath(comptime suffix: []const u8) []const u8 {
    if (suffix[0] != '/') @compileError("relToPath requires an absolute path!");
    return comptime blk: {
        const root_dir = std.fs.path.dirname(@src().file) orelse ".";
        break :blk root_dir ++ suffix;
    };
}

...
{
  var path = sdkPath("/src/main.zig"); // get a nice path
}
...
Enter fullscreen mode Exit fullscreen mode

This way, it can trivially be a comptime return value, removing the need for a lot of comptime sdkRoot() calls.

Discussion (2)

Collapse
nairou profile image
Nairou

Very useful! Since you're using ++ in both examples, can you explain how they differ? Does the stage2 compiler require ++ use within an explicit comptime block for the result to be comptime?

Collapse
xq profile image
Felix "xq" Queißner Author

++ in the first example returns a pointer-to-temporary, whereas the second example returns a comptime known value that is guaranteed to put into the .rodata section and has a lifetime of the whole program life time