From 10bd6cad759fa37d2b6c127ad97635f83261c4ac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 24 Jun 2026 21:27:04 -0700 Subject: [PATCH] implement zig libc inside maker process The jitcmd mechanism is handy but let's not go overboard. There is overhead when users have to wait for each subcommand independently. We can save time by combining some stuff together. --- lib/compiler/Maker.zig | 128 ++++++++++++++++++++++++++++- lib/compiler/libc.zig | 140 -------------------------------- lib/compiler/resinator/main.zig | 4 +- lib/std/zig/LibCDirs.zig | 47 ++++------- src/Compilation.zig | 2 +- src/main.zig | 9 +- 6 files changed, 147 insertions(+), 183 deletions(-) delete mode 100644 lib/compiler/libc.zig diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index cb252f1509713ecf1ae6fc88f8f7783cf3bd4d24..8e5bcf2474983422f72b753a866d638439503979 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -187,9 +187,10 @@ pub fn main(init: process.Init.Minimal) !void { .random_seed = parseRandomSeed(seed_arg), }; - const cmd = stringToEnum(enum { init, fetch, build }, cmd_name) orelse + const cmd = stringToEnum(enum { libc, init, fetch, build }, cmd_name) orelse fatal("bad command name: {q}", .{cmd_name}); switch (cmd) { + .libc => return cmdLibC(gpa, &graph, args[arg_i..]), .init => return cmdInit(gpa, &graph, args[arg_i..]), .fetch => return cmdFetch(gpa, &graph, args[arg_i..]), .build => {}, @@ -1746,6 +1747,25 @@ const usage_init = \\ ; +const usage_libc = + \\Usage: zig libc + \\ + \\ Detect the native libc installation and print the resulting + \\ paths to stdout. You can save this into a file and then edit + \\ the paths to create a cross compilation libc kit. Then you + \\ can pass `--libc [file]` for Zig to use it. + \\ + \\Usage: zig libc [paths_file] + \\ + \\ Parse a libc installation text file and validate it. + \\ + \\Options: + \\ -h, --help Print this help and exit + \\ -target [name] -- see the targets command + \\ -includes Print the libc include directories for the target + \\ +; + fn cmdInit(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { const arena = graph.arena; const io = graph.io; @@ -1851,6 +1871,112 @@ fn cmdInit(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { } } +fn cmdLibC(gpa: Allocator, graph: *Graph, args: []const []const u8) !void { + const environ_map = &graph.environ_map; + const io = graph.io; + const arena = graph.arena; + const LibCInstallation = std.zig.LibCInstallation; + + var input_file: ?[]const u8 = null; + var target_arch_os_abi: []const u8 = "native"; + var print_includes: bool = false; + const stdout = initStdoutWriter(io); + { + var i: usize = 0; + while (i < args.len) : (i += 1) { + const arg = args[i]; + if (mem.startsWith(u8, arg, "-")) { + if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { + try stdout.writeAll(usage_libc); + try stdout.flush(); + return std.process.cleanExit(io); + } else if (mem.eql(u8, arg, "-target")) { + if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); + i += 1; + target_arch_os_abi = args[i]; + } else if (mem.eql(u8, arg, "-includes")) { + print_includes = true; + } else { + fatal("unrecognized parameter: '{s}'", .{arg}); + } + } else if (input_file != null) { + fatal("unexpected extra parameter: '{s}'", .{arg}); + } else { + input_file = arg; + } + } + } + + const target_query = std.zig.parseTargetQueryOrReportFatalError(gpa, .{ + .arch_os_abi = target_arch_os_abi, + }); + const target = std.zig.resolveTargetQueryOrFatal(io, target_query); + + if (print_includes) { + const libc_installation: ?*LibCInstallation = libc: { + if (input_file) |libc_file| { + const libc = try arena.create(LibCInstallation); + libc.* = LibCInstallation.parse(arena, io, libc_file, &target) catch |err| { + fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); + }; + break :libc libc; + } else { + break :libc null; + } + }; + + const is_native_abi = target_query.isNativeAbi(); + + const libc_dirs = std.zig.LibCDirs.detect( + arena, + io, + .{ .root_dir = graph.zig_lib_directory }, + &target, + is_native_abi, + true, + libc_installation, + environ_map, + ) catch |err| { + const zig_target = try target.zigTriple(arena); + fatal("unable to detect libc for target {s}: {t}", .{ zig_target, err }); + }; + + if (libc_dirs.libc_include_dir_list.len == 0) { + const zig_target = try target.zigTriple(arena); + fatal("no include dirs detected for target {s}", .{zig_target}); + } + + for (libc_dirs.libc_include_dir_list) |include_dir| { + try stdout.writeAll(include_dir); + try stdout.writeByte('\n'); + } + try stdout.flush(); + return std.process.cleanExit(io); + } + + if (input_file) |libc_file| { + var libc = LibCInstallation.parse(gpa, io, libc_file, &target) catch |err| { + fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); + }; + defer libc.deinit(gpa); + } else { + if (!target_query.canDetectLibC()) { + fatal("unable to detect libc for non-native target", .{}); + } + var libc = LibCInstallation.findNative(gpa, io, .{ + .verbose = true, + .target = &target, + .environ_map = environ_map, + }) catch |err| { + fatal("unable to detect native libc: {t}", .{err}); + }; + defer libc.deinit(gpa); + + try libc.render(stdout); + try stdout.flush(); + } +} + fn markFailedStepsDirty(maker: *Maker) void { const all_steps = maker.step_stack.keys(); diff --git a/lib/compiler/libc.zig b/lib/compiler/libc.zig deleted file mode 100644 index 8ca53fefc905c01527c7157bee4c0d10575e582e..0000000000000000000000000000000000000000 --- a/lib/compiler/libc.zig +++ /dev/null @@ -1,140 +0,0 @@ -const std = @import("std"); -const Io = std.Io; -const mem = std.mem; -const LibCInstallation = std.zig.LibCInstallation; - -const usage_libc = - \\Usage: zig libc - \\ - \\ Detect the native libc installation and print the resulting - \\ paths to stdout. You can save this into a file and then edit - \\ the paths to create a cross compilation libc kit. Then you - \\ can pass `--libc [file]` for Zig to use it. - \\ - \\Usage: zig libc [paths_file] - \\ - \\ Parse a libc installation text file and validate it. - \\ - \\Options: - \\ -h, --help Print this help and exit - \\ -target [name] -- see the targets command - \\ -includes Print the libc include directories for the target - \\ -; - -var stdout_buffer: [4096]u8 = undefined; - -pub fn main(init: std.process.Init) !void { - const arena = init.arena.allocator(); - const gpa = init.gpa; - const io = init.io; - const args = try init.minimal.args.toSlice(arena); - const environ_map = init.environ_map; - - const zig_lib_directory = args[1]; - - var input_file: ?[]const u8 = null; - var target_arch_os_abi: []const u8 = "native"; - var print_includes: bool = false; - var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); - const stdout = &stdout_writer.interface; - { - var i: usize = 2; - while (i < args.len) : (i += 1) { - const arg = args[i]; - if (mem.startsWith(u8, arg, "-")) { - if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - try stdout.writeAll(usage_libc); - try stdout.flush(); - return std.process.cleanExit(io); - } else if (mem.eql(u8, arg, "-target")) { - if (i + 1 >= args.len) fatal("expected parameter after {s}", .{arg}); - i += 1; - target_arch_os_abi = args[i]; - } else if (mem.eql(u8, arg, "-includes")) { - print_includes = true; - } else { - fatal("unrecognized parameter: '{s}'", .{arg}); - } - } else if (input_file != null) { - fatal("unexpected extra parameter: '{s}'", .{arg}); - } else { - input_file = arg; - } - } - } - - const target_query = std.zig.parseTargetQueryOrReportFatalError(gpa, .{ - .arch_os_abi = target_arch_os_abi, - }); - const target = std.zig.resolveTargetQueryOrFatal(io, target_query); - - if (print_includes) { - const libc_installation: ?*LibCInstallation = libc: { - if (input_file) |libc_file| { - const libc = try arena.create(LibCInstallation); - libc.* = LibCInstallation.parse(arena, io, libc_file, &target) catch |err| { - fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); - }; - break :libc libc; - } else { - break :libc null; - } - }; - - const is_native_abi = target_query.isNativeAbi(); - - const libc_dirs = std.zig.LibCDirs.detect( - arena, - io, - zig_lib_directory, - &target, - is_native_abi, - true, - libc_installation, - environ_map, - ) catch |err| { - const zig_target = try target.zigTriple(arena); - fatal("unable to detect libc for target {s}: {t}", .{ zig_target, err }); - }; - - if (libc_dirs.libc_include_dir_list.len == 0) { - const zig_target = try target.zigTriple(arena); - fatal("no include dirs detected for target {s}", .{zig_target}); - } - - for (libc_dirs.libc_include_dir_list) |include_dir| { - try stdout.writeAll(include_dir); - try stdout.writeByte('\n'); - } - try stdout.flush(); - return std.process.cleanExit(io); - } - - if (input_file) |libc_file| { - var libc = LibCInstallation.parse(gpa, io, libc_file, &target) catch |err| { - fatal("unable to parse libc file at path {s}: {t}", .{ libc_file, err }); - }; - defer libc.deinit(gpa); - } else { - if (!target_query.canDetectLibC()) { - fatal("unable to detect libc for non-native target", .{}); - } - var libc = LibCInstallation.findNative(gpa, io, .{ - .verbose = true, - .target = &target, - .environ_map = environ_map, - }) catch |err| { - fatal("unable to detect native libc: {t}", .{err}); - }; - defer libc.deinit(gpa); - - try libc.render(stdout); - try stdout.flush(); - } -} - -fn fatal(comptime format: []const u8, args: anytype) noreturn { - std.log.err(format, args); - std.process.exit(1); -} diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index e962177015641502fdce3bcd6d9b6adf1195d0e3..170a6c02d3606a93c43c85901157da4c967bb0d3 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -639,7 +639,7 @@ fn getIncludePaths( }; const target = std.zig.resolveTargetQueryOrFatal(io, target_query); const is_native_abi = target_query.isNativeAbi(); - const detected_libc = std.zig.LibCDirs.detect(arena, io, zig_lib_dir, &target, is_native_abi, true, null, environ_map) catch { + const detected_libc = std.zig.LibCDirs.detect(arena, io, .{ .root_dir = .cwd, .sub_path = zig_lib_dir }, &target, is_native_abi, true, null, environ_map) catch { if (includes == .any) { // fall back to mingw includes = .gnu; @@ -668,7 +668,7 @@ fn getIncludePaths( const detected_libc = std.zig.LibCDirs.detect( arena, io, - zig_lib_dir, + .{ .root_dir = .cwd, .sub_path = zig_lib_dir }, &target, is_native_abi, true, diff --git a/lib/std/zig/LibCDirs.zig b/lib/std/zig/LibCDirs.zig index 04c61af0bedab6728309db7c00c975ef4229a57d..84002241bf9ea4fb1dbf5f8702a4723c05a01694 100644 --- a/lib/std/zig/LibCDirs.zig +++ b/lib/std/zig/LibCDirs.zig @@ -5,6 +5,7 @@ const std = @import("../std.zig"); const Io = std.Io; const LibCInstallation = std.zig.LibCInstallation; const Allocator = std.mem.Allocator; +const Path = std.Build.Cache.Path; libc_include_dir_list: []const []const u8, libc_installation: ?*const LibCInstallation, @@ -23,7 +24,7 @@ pub const DarwinSdkLayout = enum { pub fn detect( arena: Allocator, io: Io, - zig_lib_dir: []const u8, + zig_lib_dir: Path, target: *const std.Target, is_native_abi: bool, link_libc: bool, @@ -166,20 +167,12 @@ fn detectFromInstallation(arena: Allocator, target: *const std.Target, lci: *con }; } -pub fn detectFromBuilding( - arena: Allocator, - zig_lib_dir: []const u8, - target: *const std.Target, -) !LibCDirs { +pub fn detectFromBuilding(arena: Allocator, zig_lib_dir: Path, target: *const std.Target) !LibCDirs { const s = std.fs.path.sep_str; if (target.os.tag.isDarwin()) { const list = try arena.alloc([]const u8, 1); - list[0] = try std.fmt.allocPrint( - arena, - "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-darwin-any", - .{zig_lib_dir}, - ); + list[0] = try arena.print("{f}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-darwin-any", .{zig_lib_dir}); return .{ .libc_include_dir_list = list, .libc_installation = null, @@ -212,27 +205,19 @@ pub fn detectFromBuilding( std.zig.target.netbsdAbiNameHeaders(target.abi) else @tagName(target.abi); - const arch_include_dir = try std.fmt.allocPrint( - arena, - "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}", - .{ zig_lib_dir, arch_name, os_name, abi_name }, - ); - const generic_include_dir = try std.fmt.allocPrint( - arena, - "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}", - .{ zig_lib_dir, generic_name }, - ); + const arch_include_dir = try arena.print("{f}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}", .{ + zig_lib_dir, arch_name, os_name, abi_name, + }); + const generic_include_dir = try arena.print("{f}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}", .{ + zig_lib_dir, generic_name, + }); const generic_arch_name = std.zig.target.osArchName(target); - const arch_os_include_dir = try std.fmt.allocPrint( - arena, - "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any", - .{ zig_lib_dir, generic_arch_name, os_name }, - ); - const generic_os_include_dir = try std.fmt.allocPrint( - arena, - "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any", - .{ zig_lib_dir, os_name }, - ); + const arch_os_include_dir = try arena.print("{f}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any", .{ + zig_lib_dir, generic_arch_name, os_name, + }); + const generic_os_include_dir = try arena.print("{f}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any", .{ + zig_lib_dir, os_name, + }); const list = try arena.alloc([]const u8, 4); list[0] = arch_include_dir; diff --git a/src/Compilation.zig b/src/Compilation.zig index 3bdc049c3e3ba307a1430027567d50e39b346e1f..1e9b81d493d62ceea21fb74b3786677b119eb9b4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1729,7 +1729,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, const libc_dirs = std.zig.LibCDirs.detect( arena, io, - options.dirs.zig_lib.path.?, + .{ .root_dir = options.dirs.zig_lib }, target, options.root_mod.resolved_target.is_native_abi, link_libc, diff --git a/src/main.zig b/src/main.zig index 2213920e32ac4402c401f9b1cdf7b8abe9c75c8b..47bf6d2f49517e235cb86ded97a665d8c5c5192e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -352,7 +352,7 @@ fn mainArgs( dev.check(.ar_command); return process.exit(try llvmArMain(arena, args)); }, - .build, .fetch, .init => { + .build, .fetch, .init, .libc => { return jitCmd(gpa, arena, io, cmd_args, environ_map, .{ .cmd_name = "maker", .root_src_path = "Maker.zig", @@ -409,13 +409,6 @@ fn mainArgs( .root_src_path = "objdump.zig", }); }, - .libc => { - return jitCmd(gpa, arena, io, cmd_args, environ_map, .{ - .cmd_name = "libc", - .root_src_path = "libc.zig", - .prepend_zig_lib_dir_path = true, - }); - }, .std => { return jitCmd(gpa, arena, io, cmd_args, environ_map, .{ .cmd_name = "std", -- 2.54.0