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}