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
}
...
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
}
...
This way, it can trivially be a comptime
return value, removing the need for a lot of comptime sdkRoot()
calls.
Top comments (11)
I'm new to the zig language so my knowledge isn't huge. But I see a lot the pattern of returning something at comptime using the break keyword + a label + a return object.
Wouldn't be in this case more readable writing something like:
Edit: TIL, Isn't duable, was working only because the return was referring to the function. The only way to return a value from a block is by labeling it and using the break syntax, doc. I think that the only way to get rid of the break labeled if we want is to do something like that:
Yeah, it's not the only way, but the one i came up with. I guess we can return from comptime blocks, but i honestly never tried to do so, because it kinda means i'm returning at comptime.
Your second solution requires a second function to be put into the scope which is something i want to avoid, as
sdkPath
isn't portable between files.Wdym with “isn’t portable between files“?
It will always return paths to the file the function is contained in. Calling it from another file will then return a path relativ to the imported file, wherever it may be
Ok that’s clear, but I do not understand why creating two functions go against that intent. If they aren’t public what’s the difference between one or two?
I think is only a matter of style (and yeah, I also prefer the break, is more concise for that specific case). Please let me know if I’m wrong and is also semantically different.
Sorry for the questions I’m just trying to fill the gaps in my zig knowledge
You will have another symbol in your scope that isn't general purpose, so you pollute your namespace. That's all. Keep symbol count low unless you really need the stuff twice is what i'm trying to do
Super cool! Thanks for the reply. But by not being public couldn’t the compiler inline the function and avoid producing a symbol? By the end the compiler should know that the only point where the function is called is inside that source (if you place the pub keyword that’s a different story)
Isn’t it?
I'm talking about a semantic symbol/name in a scope, not what's emitted in the binary. You cannot call something else in that file
concatenate
for example, even if you might need itGot it! Thank you a lot for your kind replies
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?
++
in the first example returns a pointer-to-temporary, whereas the second example returns acomptime
known value that is guaranteed to put into the.rodata
section and has a lifetime of the whole program life time