Commit 1f1082e36d

Alex Rønne Petersen <alex@alexrp.com>
2025-07-06 20:05:18
wasi: Build emulated libraries into libc.a
This matches what we do for small helper libraries like this in MinGW-w64. It simplifies the compiler a bit, and also means the build system doesn't have to treat these library names specially. Closes #24325.
1 parent b461d07
Changed files (4)
src/libs/wasi_libc.zig
@@ -10,43 +10,8 @@ pub const CrtFile = enum {
     crt1_reactor_o,
     crt1_command_o,
     libc_a,
-    libdl_a,
-    libwasi_emulated_process_clocks_a,
-    libwasi_emulated_getpid_a,
-    libwasi_emulated_mman_a,
-    libwasi_emulated_signal_a,
 };
 
-pub fn getEmulatedLibCrtFile(lib_name: []const u8) ?CrtFile {
-    if (mem.eql(u8, lib_name, "dl")) {
-        return .libdl_a;
-    }
-    if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {
-        return .libwasi_emulated_process_clocks_a;
-    }
-    if (mem.eql(u8, lib_name, "wasi-emulated-getpid")) {
-        return .libwasi_emulated_getpid_a;
-    }
-    if (mem.eql(u8, lib_name, "wasi-emulated-mman")) {
-        return .libwasi_emulated_mman_a;
-    }
-    if (mem.eql(u8, lib_name, "wasi-emulated-signal")) {
-        return .libwasi_emulated_signal_a;
-    }
-    return null;
-}
-
-pub fn emulatedLibCRFileLibName(crt_file: CrtFile) []const u8 {
-    return switch (crt_file) {
-        .libdl_a => "libdl.a",
-        .libwasi_emulated_process_clocks_a => "libwasi-emulated-process-clocks.a",
-        .libwasi_emulated_getpid_a => "libwasi-emulated-getpid.a",
-        .libwasi_emulated_mman_a => "libwasi-emulated-mman.a",
-        .libwasi_emulated_signal_a => "libwasi-emulated-signal.a",
-        else => unreachable,
-    };
-}
-
 pub fn execModelCrtFile(wasi_exec_model: std.builtin.WasiExecModel) CrtFile {
     return switch (wasi_exec_model) {
         .reactor => CrtFile.crt1_reactor_o,
@@ -157,87 +122,65 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                 }
             }
 
-            try comp.build_crt_file("c", .Lib, .@"wasi libc.a", prog_node, libc_sources.items, .{});
-        },
-
-        .libdl_a => {
-            var args = std.ArrayList([]const u8).init(arena);
-            try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
-            try addLibcBottomHalfIncludes(comp, arena, &args);
+            {
+                // Compile libdl.
+                var args = std.ArrayList([]const u8).init(arena);
+                try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
+                try addLibcBottomHalfIncludes(comp, arena, &args);
 
-            var emu_dl_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
-            for (emulated_dl_src_files) |file_path| {
-                try emu_dl_sources.append(.{
-                    .src_path = try comp.dirs.zig_lib.join(arena, &.{
-                        "libc", try sanitize(arena, file_path),
-                    }),
-                    .extra_flags = args.items,
-                    .owner = undefined,
-                });
+                for (emulated_dl_src_files) |file_path| {
+                    try libc_sources.append(.{
+                        .src_path = try comp.dirs.zig_lib.join(arena, &.{
+                            "libc", try sanitize(arena, file_path),
+                        }),
+                        .extra_flags = args.items,
+                        .owner = undefined,
+                    });
+                }
             }
-            try comp.build_crt_file("dl", .Lib, .@"wasi libdl.a", prog_node, emu_dl_sources.items, .{});
-        },
 
-        .libwasi_emulated_process_clocks_a => {
-            var args = std.ArrayList([]const u8).init(arena);
-            try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
-            try addLibcBottomHalfIncludes(comp, arena, &args);
+            {
+                // Compile libwasi-emulated-process-clocks.
+                var args = std.ArrayList([]const u8).init(arena);
+                try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
+                try addLibcBottomHalfIncludes(comp, arena, &args);
 
-            var emu_clocks_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
-            for (emulated_process_clocks_src_files) |file_path| {
-                try emu_clocks_sources.append(.{
-                    .src_path = try comp.dirs.zig_lib.join(arena, &.{
-                        "libc", try sanitize(arena, file_path),
-                    }),
-                    .extra_flags = args.items,
-                    .owner = undefined,
-                });
+                for (emulated_process_clocks_src_files) |file_path| {
+                    try libc_sources.append(.{
+                        .src_path = try comp.dirs.zig_lib.join(arena, &.{
+                            "libc", try sanitize(arena, file_path),
+                        }),
+                        .extra_flags = args.items,
+                        .owner = undefined,
+                    });
+                }
             }
-            try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, .@"libwasi-emulated-process-clocks.a", prog_node, emu_clocks_sources.items, .{});
-        },
-        .libwasi_emulated_getpid_a => {
-            var args = std.ArrayList([]const u8).init(arena);
-            try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
-            try addLibcBottomHalfIncludes(comp, arena, &args);
 
-            var emu_getpid_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
-            for (emulated_getpid_src_files) |file_path| {
-                try emu_getpid_sources.append(.{
-                    .src_path = try comp.dirs.zig_lib.join(arena, &.{
-                        "libc", try sanitize(arena, file_path),
-                    }),
-                    .extra_flags = args.items,
-                    .owner = undefined,
-                });
-            }
-            try comp.build_crt_file("wasi-emulated-getpid", .Lib, .@"libwasi-emulated-getpid.a", prog_node, emu_getpid_sources.items, .{});
-        },
-        .libwasi_emulated_mman_a => {
-            var args = std.ArrayList([]const u8).init(arena);
-            try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
-            try addLibcBottomHalfIncludes(comp, arena, &args);
+            {
+                // Compile libwasi-emulated-getpid.
+                var args = std.ArrayList([]const u8).init(arena);
+                try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
+                try addLibcBottomHalfIncludes(comp, arena, &args);
 
-            var emu_mman_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
-            for (emulated_mman_src_files) |file_path| {
-                try emu_mman_sources.append(.{
-                    .src_path = try comp.dirs.zig_lib.join(arena, &.{
-                        "libc", try sanitize(arena, file_path),
-                    }),
-                    .extra_flags = args.items,
-                    .owner = undefined,
-                });
+                for (emulated_getpid_src_files) |file_path| {
+                    try libc_sources.append(.{
+                        .src_path = try comp.dirs.zig_lib.join(arena, &.{
+                            "libc", try sanitize(arena, file_path),
+                        }),
+                        .extra_flags = args.items,
+                        .owner = undefined,
+                    });
+                }
             }
-            try comp.build_crt_file("wasi-emulated-mman", .Lib, .@"libwasi-emulated-mman.a", prog_node, emu_mman_sources.items, .{});
-        },
-        .libwasi_emulated_signal_a => {
-            var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
 
             {
+                // Compile libwasi-emulated-mman.
                 var args = std.ArrayList([]const u8).init(arena);
                 try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
+                try addLibcBottomHalfIncludes(comp, arena, &args);
 
-                for (emulated_signal_bottom_half_src_files) |file_path| {
-                    try emu_signal_sources.append(.{
+                for (emulated_mman_src_files) |file_path| {
+                    try libc_sources.append(.{
                         .src_path = try comp.dirs.zig_lib.join(arena, &.{
                             "libc", try sanitize(arena, file_path),
                         }),
@@ -248,23 +191,37 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
             }
 
             {
-                var args = std.ArrayList([]const u8).init(arena);
-                try addCCArgs(comp, arena, &args, .{ .want_O3 = true });
-                try addLibcTopHalfIncludes(comp, arena, &args);
-                try args.append("-D_WASI_EMULATED_SIGNAL");
+                // Compile libwasi-emulated-signal.
+                var bottom_args = std.ArrayList([]const u8).init(arena);
+                try addCCArgs(comp, arena, &bottom_args, .{ .want_O3 = true });
+
+                for (emulated_signal_bottom_half_src_files) |file_path| {
+                    try libc_sources.append(.{
+                        .src_path = try comp.dirs.zig_lib.join(arena, &.{
+                            "libc", try sanitize(arena, file_path),
+                        }),
+                        .extra_flags = bottom_args.items,
+                        .owner = undefined,
+                    });
+                }
+
+                var top_args = std.ArrayList([]const u8).init(arena);
+                try addCCArgs(comp, arena, &top_args, .{ .want_O3 = true });
+                try addLibcTopHalfIncludes(comp, arena, &top_args);
+                try top_args.append("-D_WASI_EMULATED_SIGNAL");
 
                 for (emulated_signal_top_half_src_files) |file_path| {
-                    try emu_signal_sources.append(.{
+                    try libc_sources.append(.{
                         .src_path = try comp.dirs.zig_lib.join(arena, &.{
                             "libc", try sanitize(arena, file_path),
                         }),
-                        .extra_flags = args.items,
+                        .extra_flags = top_args.items,
                         .owner = undefined,
                     });
                 }
             }
 
-            try comp.build_crt_file("wasi-emulated-signal", .Lib, .@"libwasi-emulated-signal.a", prog_node, emu_signal_sources.items, .{});
+            try comp.build_crt_file("c", .Lib, .@"wasi libc.a", prog_node, libc_sources.items, .{});
         },
     }
 }
src/link/Lld.zig
@@ -1539,13 +1539,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
 
         if (comp.config.link_libc and is_exe_or_dyn_lib) {
             if (target.os.tag == .wasi) {
-                for (comp.wasi_emulated_libs) |crt_file| {
-                    try argv.append(try comp.crtFileAsString(
-                        arena,
-                        wasi_libc.emulatedLibCRFileLibName(crt_file),
-                    ));
-                }
-
                 try argv.append(try comp.crtFileAsString(
                     arena,
                     wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model),
src/Compilation.zig
@@ -234,7 +234,6 @@ fuzzer_lib: ?CrtFile = null,
 glibc_so_files: ?glibc.BuiltSharedObjects = null,
 freebsd_so_files: ?freebsd.BuiltSharedObjects = null,
 netbsd_so_files: ?netbsd.BuiltSharedObjects = null,
-wasi_emulated_libs: []const wasi_libc.CrtFile,
 
 /// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
 /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
@@ -1567,12 +1566,6 @@ pub const CreateOptions = struct {
     framework_dirs: []const []const u8 = &[0][]const u8{},
     frameworks: []const Framework = &.{},
     windows_lib_names: []const []const u8 = &.{},
-    /// These correspond to the WASI libc emulated subcomponents including:
-    /// * process clocks
-    /// * getpid
-    /// * mman
-    /// * signal
-    wasi_emulated_libs: []const wasi_libc.CrtFile = &.{},
     /// This means that if the output mode is an executable it will be a
     /// Position Independent Executable. If the output mode is not an
     /// executable this field is ignored.
@@ -2055,7 +2048,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
             .function_sections = options.function_sections,
             .data_sections = options.data_sections,
             .native_system_include_paths = options.native_system_include_paths,
-            .wasi_emulated_libs = options.wasi_emulated_libs,
             .force_undefined_symbols = options.force_undefined_symbols,
             .link_eh_frame_hdr = link_eh_frame_hdr,
             .global_cc_argv = options.global_cc_argv,
@@ -2384,11 +2376,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
                 } else if (target.isWasiLibC()) {
                     if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable;
 
-                    for (comp.wasi_emulated_libs) |crt_file| {
-                        comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = true;
-                    }
-                    comp.link_task_queue.pending_prelink_tasks += @intCast(comp.wasi_emulated_libs.len);
-
                     comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.execModelCrtFile(comp.config.wasi_exec_model))] = true;
                     comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.CrtFile.libc_a)] = true;
                     comp.link_task_queue.pending_prelink_tasks += 2;
src/main.zig
@@ -972,8 +972,6 @@ fn buildOutputType(
         .windows_libs = .empty,
         .link_inputs = .empty,
 
-        .wasi_emulated_libs = .{},
-
         .c_source_files = .{},
         .rc_source_files = .{},
 
@@ -3406,7 +3404,6 @@ fn buildOutputType(
         .framework_dirs = create_module.framework_dirs.items,
         .frameworks = resolved_frameworks.items,
         .windows_lib_names = create_module.windows_libs.keys(),
-        .wasi_emulated_libs = create_module.wasi_emulated_libs.items,
         .want_compiler_rt = want_compiler_rt,
         .want_ubsan_rt = want_ubsan_rt,
         .hash_style = hash_style,
@@ -3687,8 +3684,6 @@ const CreateModule = struct {
     /// output. Allocated with gpa.
     link_inputs: std.ArrayListUnmanaged(link.Input),
 
-    wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CrtFile),
-
     c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
     rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
 
@@ -3819,14 +3814,6 @@ fn createModule(
             .name_query => |nq| {
                 const lib_name = nq.name;
 
-                if (target.os.tag == .wasi) {
-                    if (wasi_libc.getEmulatedLibCrtFile(lib_name)) |crt_file| {
-                        try create_module.wasi_emulated_libs.append(arena, crt_file);
-                        create_module.opts.link_libc = true;
-                        continue;
-                    }
-                }
-
                 if (std.zig.target.isLibCLibName(target, lib_name)) {
                     create_module.opts.link_libc = true;
                     continue;