Alternative to @src() for obtaining the current source file path

i want to obtain the full path to my current source file – which i’d like to retain in a top-level const, so presumably i can’t use @src() directly…

since i’m ONLY interested in the file path (and not the line number), i suppose i could have some dummy function elsewhere in the same source file, which itself returns the file obtained through @src()

is there a more straightforward way to obtain the current source file path???

I know I’ll probably regret asking this, but why do you want this?

To answer the question, I believe the only way to do this would be to put the path to the root module in a generated file and use that as the base to generate the path for every file in the module. You could easily do this with a build option.

1 Like

i’m a little old-school, but i like having my “logical” hierarchy of software modules match the “physical” organization of the source files… back in java, the class my.pkg.Counter was found in the source file my/pkg/Counter.java

while this requirement has fallen away in many newer languages, i’ve continued to follow that pattern in my own code…

i’m creating a zig-based “framework” in which i’d like to enforce these (and many other) stylistic constraints… most of these can actually be expressed in zig through asserts, comptime checks, etc…

since my framework provisionally requires each module to declare its fully-qualified name, i just want to ensure this logical name aligns with the source file’s physical path…

in low-level terms, i’[m looking for the moral equivalent of the __FILE__ macro in C/C++…

It’s five lines; and it’s ugly. (Displays “src” for “src/main.zig”.)

const std = @import("std");

const name = struct {
    fn filename() []const u8 {
        return std.fs.path.dirname(@src().file) orelse "";
    }
}.filename();

pub fn main() void {
    std.debug.print("{s}\n", .{name});
}

Implementing this as a separate linter application might lead to better results and would free you from limitations of what is possible with comptime. If the name declaration has one imposed syntactical form it should be fairly easy to scan through the source files and find it.

Personally I think comptime isn’t meant to replace all needs for meta programming and some advanced forms of meta programming are probably easier, in the long term, if they make use of at least some custom build steps, that could for example do something like linting, instead of trying to fit everything into comptime.

Even if some things can be done with comptime, I think some things may be better as build steps.

your suggestion is spot-on… i’m already building such a tool (written in zig) that actually compiles that same sources used in my downstream app…

the “runtime” of this upstream linter program makes extensive use of reflection to perform additional semantic validation… and since all of this is NOT happening at comptime, i can print meaningful messages as well as easily accumulate information using std lists and maps…

but this begs the original question… if my linter is implemented by a “self-reflective” upstream execution of my app, how can i obtain the path to the source file corresponding the current top-level container under inspection…

@dimdin proposed a solution that works – but you wouldn’t want to those five lines of code repeated in every source file… and it isn’t obvious how to automatically “inject” this each source – unless that’s an explicit pre-build step that adds some “don’t edit below this line” to a file otherwise being actively editied…

I was suggesting to statically process the source files themselves as files, instead of running them in any way (neither reflective, nor comptime), either by using a problem specific parser for that narrow expected declaration, or possibly by trying to reuse Zigs parser for more advanced uses.

Usually linters work on syntax and a bunch of rules and apply that to source files, not trying to run, or execute those source files.