Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

findNativeIncludeDirPosix

LibCInstallation.findNativeIncludeDirPosix
fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void

File

lib/std/zig/LibCInstallation.zig:247

Code

fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
    // Detect infinite loops.
    var environ_map = try args.environ_map.clone(gpa);
    defer environ_map.deinit();
    const skip_cc_env_var = if (environ_map.get(inf_loop_env_key)) |phase| blk: {
        if (std.mem.eql(u8, phase, "1")) {
            try environ_map.put(inf_loop_env_key, "2");
            break :blk true;
        } else {
            return error.ZigIsTheCCompiler;
        }
    } else blk: {
        try environ_map.put(inf_loop_env_key, "1");
        break :blk false;
    };

    const dev_null = if (is_windows) "nul" else "/dev/null";

    var argv = std.array_list.Managed([]const u8).init(gpa);
    defer argv.deinit();

    try appendCcExe(&argv, skip_cc_env_var, &environ_map);
    try argv.appendSlice(&.{
        "-E",
        "-Wp,-v",
        "-xc",
        dev_null,
    });

    const run_res = std.process.run(gpa, io, .{
        .stdout_limit = .limited(1024 * 1024),
        .stderr_limit = .limited(1024 * 1024),
        .argv = argv.items,
        .environ_map = &environ_map,
        // Some C compilers, such as Clang, are known to rely on argv[0] to find the path
        // to their own executable, without even bothering to resolve PATH. This results in the message:
        // error: unable to execute command: Executable "" doesn't exist!
        // So we use the expandArg0 variant of ChildProcess to give them a helping hand.
        .expand_arg0 = .expand,
    }) catch |err| switch (err) {
        error.OutOfMemory => |e| return e,
        else => {
            printVerboseInvocation(argv.items, null, args.verbose, null);
            return error.UnableToSpawnCCompiler;
        },
    };
    defer {
        gpa.free(run_res.stdout);
        gpa.free(run_res.stderr);
    }
    switch (run_res.term) {
        .exited => |code| if (code != 0) {
            printVerboseInvocation(argv.items, null, args.verbose, run_res.stderr);
            return error.CCompilerExitCode;
        },
        else => {
            printVerboseInvocation(argv.items, null, args.verbose, run_res.stderr);
            return error.CCompilerCrashed;
        },
    }

    var it = std.mem.tokenizeAny(u8, run_res.stderr, "\n\r");
    var search_paths = std.array_list.Managed([]const u8).init(gpa);
    defer search_paths.deinit();
    while (it.next()) |line| {
        if (line.len != 0 and line[0] == ' ') {
            try search_paths.append(line);
        }
    }
    if (search_paths.items.len == 0) {
        return error.CCompilerCannotFindHeaders;
    }

    const include_dir_example_file = if (is_haiku) "posix/stdlib.h" else "stdlib.h";
    const sys_include_dir_example_file = if (is_windows)
        "sys\\types.h"
    else if (is_haiku or is_serenity)
        "errno.h"
    else
        "sys/errno.h";

    var path_i: usize = 0;
    while (path_i < search_paths.items.len) : (path_i += 1) {
        // search in reverse order
        const search_path_untrimmed = search_paths.items[search_paths.items.len - path_i - 1];
        const search_path = std.mem.trimStart(u8, search_path_untrimmed, " ");
        var search_dir = Io.Dir.cwd().openDir(io, search_path, .{}) catch |err| switch (err) {
            error.FileNotFound,
            error.NotDir,
            error.NoDevice,
            => continue,

            else => return error.FileSystem,
        };
        defer search_dir.close(io);

        if (self.include_dir == null) {
            if (search_dir.access(io, include_dir_example_file, .{})) |_| {
                self.include_dir = try gpa.dupe(u8, search_path);
            } else |err| switch (err) {
                error.FileNotFound => {},
                else => return error.FileSystem,
            }
        }

        if (self.sys_include_dir == null) {
            if (search_dir.access(io, sys_include_dir_example_file, .{})) |_| {
                self.sys_include_dir = try gpa.dupe(u8, search_path);
            } else |err| switch (err) {
                error.FileNotFound => {},
                else => return error.FileSystem,
            }
        }

        if (self.include_dir != null and self.sys_include_dir != null) {
            // Success.
            return;
        }
    }

    return error.LibCStdLibHeaderNotFound;
}