master
  1const std = @import("std");
  2const mem = std.mem;
  3const LibCInstallation = std.zig.LibCInstallation;
  4
  5const usage_libc =
  6    \\Usage: zig libc
  7    \\
  8    \\    Detect the native libc installation and print the resulting
  9    \\    paths to stdout. You can save this into a file and then edit
 10    \\    the paths to create a cross compilation libc kit. Then you
 11    \\    can pass `--libc [file]` for Zig to use it.
 12    \\
 13    \\Usage: zig libc [paths_file]
 14    \\
 15    \\    Parse a libc installation text file and validate it.
 16    \\
 17    \\Options:
 18    \\  -h, --help             Print this help and exit
 19    \\  -target [name]         <arch><sub>-<os>-<abi> see the targets command
 20    \\  -includes              Print the libc include directories for the target
 21    \\
 22;
 23
 24var stdout_buffer: [4096]u8 = undefined;
 25
 26pub fn main() !void {
 27    var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
 28    defer arena_instance.deinit();
 29    const arena = arena_instance.allocator();
 30    const gpa = arena;
 31
 32    var threaded: std.Io.Threaded = .init(gpa);
 33    defer threaded.deinit();
 34    const io = threaded.io();
 35
 36    const args = try std.process.argsAlloc(arena);
 37    const zig_lib_directory = args[1];
 38
 39    var input_file: ?[]const u8 = null;
 40    var target_arch_os_abi: []const u8 = "native";
 41    var print_includes: bool = false;
 42    var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
 43    const stdout = &stdout_writer.interface;
 44    {
 45        var i: usize = 2;
 46        while (i < args.len) : (i += 1) {
 47            const arg = args[i];
 48            if (mem.startsWith(u8, arg, "-")) {
 49                if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
 50                    try stdout.writeAll(usage_libc);
 51                    try stdout.flush();
 52                    return std.process.cleanExit();
 53                } else if (mem.eql(u8, arg, "-target")) {
 54                    if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg});
 55                    i += 1;
 56                    target_arch_os_abi = args[i];
 57                } else if (mem.eql(u8, arg, "-includes")) {
 58                    print_includes = true;
 59                } else {
 60                    fatal("unrecognized parameter: '{s}'", .{arg});
 61                }
 62            } else if (input_file != null) {
 63                fatal("unexpected extra parameter: '{s}'", .{arg});
 64            } else {
 65                input_file = arg;
 66            }
 67        }
 68    }
 69
 70    const target_query = std.zig.parseTargetQueryOrReportFatalError(gpa, .{
 71        .arch_os_abi = target_arch_os_abi,
 72    });
 73    const target = std.zig.resolveTargetQueryOrFatal(io, target_query);
 74
 75    if (print_includes) {
 76        const libc_installation: ?*LibCInstallation = libc: {
 77            if (input_file) |libc_file| {
 78                const libc = try arena.create(LibCInstallation);
 79                libc.* = LibCInstallation.parse(arena, libc_file, &target) catch |err| {
 80                    fatal("unable to parse libc file at path {s}: {s}", .{ libc_file, @errorName(err) });
 81                };
 82                break :libc libc;
 83            } else {
 84                break :libc null;
 85            }
 86        };
 87
 88        const is_native_abi = target_query.isNativeAbi();
 89
 90        const libc_dirs = std.zig.LibCDirs.detect(
 91            arena,
 92            zig_lib_directory,
 93            &target,
 94            is_native_abi,
 95            true,
 96            libc_installation,
 97        ) catch |err| {
 98            const zig_target = try target.zigTriple(arena);
 99            fatal("unable to detect libc for target {s}: {s}", .{ zig_target, @errorName(err) });
100        };
101
102        if (libc_dirs.libc_include_dir_list.len == 0) {
103            const zig_target = try target.zigTriple(arena);
104            fatal("no include dirs detected for target {s}", .{zig_target});
105        }
106
107        for (libc_dirs.libc_include_dir_list) |include_dir| {
108            try stdout.writeAll(include_dir);
109            try stdout.writeByte('\n');
110        }
111        try stdout.flush();
112        return std.process.cleanExit();
113    }
114
115    if (input_file) |libc_file| {
116        var libc = LibCInstallation.parse(gpa, libc_file, &target) catch |err| {
117            fatal("unable to parse libc file at path {s}: {s}", .{ libc_file, @errorName(err) });
118        };
119        defer libc.deinit(gpa);
120    } else {
121        if (!target_query.canDetectLibC()) {
122            fatal("unable to detect libc for non-native target", .{});
123        }
124        var libc = LibCInstallation.findNative(.{
125            .allocator = gpa,
126            .verbose = true,
127            .target = &target,
128        }) catch |err| {
129            fatal("unable to detect native libc: {s}", .{@errorName(err)});
130        };
131        defer libc.deinit(gpa);
132
133        try libc.render(stdout);
134        try stdout.flush();
135    }
136}
137
138fn fatal(comptime format: []const u8, args: anytype) noreturn {
139    std.log.err(format, args);
140    std.process.exit(1);
141}