Conditionally include main in a file

A small trick that made me smile! Turns out Zig has an equivalent of Python’s

if __name__ == "__main__":

idiom for including a main function in arbitray files:

pub usingnamespace if (@import("root") == @This()) struct {
    pub fn main() void { std.debug.print("you can run this file directly") }
} else struct {
    // But if you @import() it instead,
    // there won't be a useless `main` symbol available!
};
14 Likes

Nice one! I ran it from some other directories to make sure it wasn’t doing something weird with relative paths (at least in ubuntu) and it seems to work fine!

And just for the record, this is actually a very useful technique beyond just importing main. Detecting the root of your location is very important if you do something where your current working directory can change.

2 Likes

cursed, thanks for sharing

3 Likes

I think there may be cases where it is valid to run a main function exported from a lib and pretend it was run as an application directly, haven’t tried that so far, but it seems possible and there might be cases where it is useful. So I think always exporting it isn’t necessarily useless and could make it even more flexible to use.

One case might be if you want to compile a bunch of examples into one fat executable, that acts as a launcher for the different examples and distribute that as a single executable instead of a “real” launcher that starts separate processes, but also have the option of compiling the examples as standalone apps for different distributions of your code.
I think when compiling for wasm/browser such a fake-launcher could make sense.

This is where I use it at TigerBeetle:

I want to unit-test some code, but it does process.exit, so I need to run it in a different process. So I just let the file to compile&run itself from test blocks.

1 Like