Return error from main

Hello, I made a function that looks for an executable in PATH. If it does not find the exec, it returns an error:

pub fn findExecutable(exe_name: []const u8) !void {
    std.debug.print("Hello from find exec, {s}\n", .{exe_name});
    const allocator = std.heap.page_allocator;
    const path_var: []u8 = try std.process.getEnvVarOwned(allocator, "PATH");
    defer allocator.free(path_var);
    std.debug.print("{}\n", .{@TypeOf(path_var)});
    var path_segments = std.mem.tokenizeSequence(u8, path_var, ":");
    std.debug.print("{}\n", .{@TypeOf(path_segments)});
    var segment = path_segments.next();
    var found: bool = false;
    while (segment != null) {
        std.debug.print("got segment {s}\n", .{segment.?});
        defer segment = path_segments.next();
        var iter_dir = std.fs.cwd().openDir(
            segment.?,
            .{ .iterate = true },
        ) catch {
            std.debug.print("{s} not found, skipping\n", .{segment.?});
            continue;
        };
        defer {
            iter_dir.close();
        }
        var iter = iter_dir.iterate();
        while (try iter.next()) |entry| {
            if (entry.kind == .file) {
                std.debug.print("got file {s}\n", .{entry.name});
                if (std.mem.eql(u8, entry.name, exe_name)) {
                    std.debug.print("Found exe {s}\n", .{exe_name});
                    found = true;
                    break;
                }
            }
        }
        if (found) {
            break;
        }
    }
    if (!found) {
        return FindExecError.ExecutableNotFound;
    }
}

How can I handle this in my main (build.zig) function elegantly?
What I tried so far:

try findExecutable("looool") catch |err| switch(err) {
        error.ExecutableNotFound => {
            try std.io.getStdErr().writer().print("Executable not found, please install it.\n");
            return;
        },
        else => {
            return (err);
        },
    };

Not only is this bulky, it also does not compile:

build.zig:7:46: error: expected error union type, found 'void'
    try findExecutable("looool") catch |err| switch(err) {
                                             ^~~~~~

I don’t want to catch any error other than ExecutableNotFound explicitely. How can I do that?

1 Like

Make your main function able to return an error by adding ! to the return type:

pub fn main() !void {
    // ...
}

Also, don’t use try and catch together, you probably just want:

    findExecutable("looool") catch |err| switch(err) {
        error.ExecutableNotFound => {
            try std.io.getStdErr().writer().print("Executable not found, please install it.\n");
            return;
        },
        else => return err,
    };
3 Likes

My main was already pub fn build(b: *std.Build) !void, but removing try and adding an empty format to the print did the trick, thanks!

1 Like

You cannot have both try and catch.
try X; means the same as X catch |err| return err;

4 Likes