Petition to link build.zig with libc (or how to do a simple file-exists check in build.zig)

TL;DR: what’s the easiest way to do a file-exists check in build.zig after the deprecation of std.fs?

Previously I had this in my build.zig:

const dot_emsc_exists = !std.meta.isError(std.fs.cwd().access(dot_emsc_path, .{}));

After trying to figure out how this would work with the new IO system, I’ll naturally need an IO system pointer - so next I tried to figure out if the build system exposes its own IO implementation, similar to b.allocator, but no luck.

My next idea was… hey, why not simply use std.c.access()… and that works wonderfully on macOS but breaks on Linux with:

error: dependency on libc must be explicitly specified in the build command

…naturally I don’t want that… std.posix.fstat on the other doesn’t seem to work on Windows, so I guess my only option is one of the std.IO stat functions. But for that I need an IO system, but at the same time I don’t want to infect the whole call chain down to this one really unimportant function which just needs to check if a file exists and absolutely nothing else.

Creating a function local IO system just for this one file-exists check seems like complete overkill and absolutely not how the IO system is supposed to be used (I guess).

Any other ideas? :slight_smile:

1 Like

I think what you want is runAllowFail with "ls" or "find".

It would be nice if build steps also had a way to deal with nonzero exit codes which allowed things to continue on a conditional basis too, actually. But that’s a separate ask.

!std.meta.isError(std.Io.Dir.access / accessAbsolute)` ?

1 Like

I think what you want is runAllowFail with "ls" or "find" .

So basically running a cmdline tool? That’s also not portable to Windows without a lot of hassle :confused:

Sorry I’m a chauvinist, I literally didn’t think of that.

Probably need to make a whole Io then. “does this file exist” would be a good thing for the build system to expose directly IMHO.

Yeah, but that needs an IO instance…

My current ‘non-viral hack’ is this and I hate it :wink:

fn fileExists(b: *Build, path: []const u8) !bool {
    var threaded: std.Io.Threaded = .init(b.allocator, .{});
    defer threaded.deinit();
    const io = threaded.io();
    return !std.meta.isError(std.Io.Dir.cwd().access(io, path, .{}));
}

…but as long as multiple Io.Threaded instances can live side by side that’s kinda good-enough for now…

I don’t see creating an ad-hoc Io as problematic, especially not in the build. You want to do some I/O, right? That’s how we do it now.

2 Likes

Yeah that’s what I do now (create a temp IO object)…

What I’m doing is a bit of a hack in the first place of course, because it happens in the ‘build-tree-construction phase’, not in the actual build phase. But that whole thing I’m doing there (installing the Emscripten SDK into the Zig cache) doesn’t really fit into the build system philosophy, so it’s a hack to make another hack work, but currently I see no other way to solve that problem…

1 Like

for this I’m sure std.Io.Threaded.init_single_threaded is fine too

3 Likes

std.Io.Threaded.init_single_threaded

Heh, I was looking for the an std.Io.SingleThreaded instead. Yeah that’s much better - but man, naming is hard :wink:

2 Likes

b.graph.io

7 Likes

Ah thanks! I looked in the Build type but didn’t think that the interesting stuff might be hidden under .graph :slight_smile: I simplified my build.zig to use the build system’s IO and it appears to work perfectly (also added the fallback for 0.15.2 back while at it).

2 Likes