From 6f6182a5f3a4b027bbff6405600fd21b3ef8b86c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 5 Jun 2021 01:08:47 +0200 Subject: [PATCH 1/6] zig,cc,wasi: include emulated libs in WASI libc This commit includes emulated libc sublibs that were not included in the compilation and caching of WASI libc that ships with Zig. The libs include (emulated): process clocks, getpid, mman, and signal. With this change, it is now possible to successfully cross-compile `wasm3` engine to WASI with `zig cc`. For the future though, it might be worth considering splitting WASI libc into libc-proper and modularised emulated libs as it is done in upstream, and then have them included only if the user specifically requests emulation/parts of it. --- src/wasi_libc.zig | 277 ++++++++++++++++++++++++++++------------------ 1 file changed, 168 insertions(+), 109 deletions(-) diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index 3c04203082..b7be6af82f 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -21,35 +21,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { // Compile crt sources. var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, false); - try args.appendSlice(&[_][]const u8{ - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "headers", - "private", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "cloudlibc", - "src", - "include", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "cloudlibc", - "src", - }), - }); + try addLibcBottomHalfIncludes(comp, arena, &args); var comp_sources = std.ArrayList(Compilation.CSourceFile).init(arena); for (crt_src_files) |file_path| { @@ -95,35 +67,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { // Compile libc-bottom-half. var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, true); - try args.appendSlice(&[_][]const u8{ - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "headers", - "private", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "cloudlibc", - "src", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-bottom-half", - "cloudlibc", - "src", - "include", - }), - }); + try addLibcBottomHalfIncludes(comp, arena, &args); for (libc_bottom_half_src_files) |file_path| { try comp_sources.append(.{ @@ -135,60 +79,77 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { } } + { + // Compile emulated sources depending only on libc-bottom-half. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcBottomHalfIncludes(comp, arena, &args); + + for (emulated_process_clocks_src_files) |file_path| { + try comp_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + + for (emulated_getpid_src_files) |file_path| { + try comp_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + + for (emulated_mman_src_files) |file_path| { + try comp_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + { + // Compile emulated signals (bottom-half). + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + + for (emulated_signal_bottom_half_src_files) |file_path| { + try comp_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + { + // Compile emulated signals (top-half). + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcTopHalfIncludes(comp, arena, &args); + try args.append("-D_WASI_EMULATED_SIGNAL"); + + for (emulated_signal_top_half_src_files) |file_path| { + try comp_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + { // Compile libc-top-half. var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, true); - try args.appendSlice(&[_][]const u8{ - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-top-half", - "musl", - "src", - "include", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-top-half", - "musl", - "src", - "internal", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-top-half", - "musl", - "arch", - "wasm32", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-top-half", - "musl", - "arch", - "generic", - }), - - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "libc-top-half", - "headers", - "private", - }), - }); + try addLibcTopHalfIncludes(comp, arena, &args); for (libc_top_half_src_files) |file_path| { try comp_sources.append(.{ @@ -251,6 +212,99 @@ fn addCCArgs( }); } +fn addLibcBottomHalfIncludes( + comp: *Compilation, + arena: *Allocator, + args: *std.ArrayList([]const u8), +) error{OutOfMemory}!void { + try args.appendSlice(&[_][]const u8{ + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-bottom-half", + "headers", + "private", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-bottom-half", + "cloudlibc", + "src", + "include", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-bottom-half", + "cloudlibc", + "src", + }), + }); +} + +fn addLibcTopHalfIncludes( + comp: *Compilation, + arena: *Allocator, + args: *std.ArrayList([]const u8), +) error{OutOfMemory}!void { + try args.appendSlice(&[_][]const u8{ + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-top-half", + "musl", + "src", + "include", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-top-half", + "musl", + "src", + "internal", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-top-half", + "musl", + "arch", + "wasm32", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-top-half", + "musl", + "arch", + "generic", + }), + + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "libc-top-half", + "headers", + "private", + }), + }); +} + const dlmalloc_src_files = [_][]const u8{ "wasi/dlmalloc/src/dlmalloc.c", }; @@ -1025,6 +1079,11 @@ const emulated_mman_src_files = &[_][]const u8{ "wasi/libc-bottom-half/mman/mman.c", }; -const emulated_signal_src_files = &[_][]const u8{ +const emulated_signal_bottom_half_src_files = &[_][]const u8{ "wasi/libc-bottom-half/signal/signal.c", }; + +const emulated_signal_top_half_src_files = &[_][]const u8{ + "wasi/libc-top-half/musl/src/signal/psignal.c", + "wasi/libc-top-half/musl/src/string/strsignal.c", +}; From 93a4403271ef62d8ae2cd10f58cc23d4b7bbdf4d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 7 Jun 2021 08:37:04 +0200 Subject: [PATCH 2/6] cc,wasi: package emulations as static archives This replicates the expected behavior when using `clang` with upstream `wasi-libc` sysroot: linking emulated subcomponents such as process clocks or signals requires an explicit link flag in the compiler invocation, for example: ``` zig cc -target wasm32-wasi -lwasi-emulated-process-clocks main.c -o main.wasm ``` --- src/link/Wasm.zig | 19 +++-- src/wasi_libc.zig | 173 ++++++++++++++++++++++++++-------------------- 2 files changed, 113 insertions(+), 79 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 77283384be..443ace855a 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -702,11 +702,20 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { try argv.append(try comp.get_libc_crt_file(arena, "crt.o")); } - if (!is_obj and self.base.options.link_libc) { - try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { - .Static => "libc.a", - .Dynamic => unreachable, - })); + if (!is_obj) { + const system_libs = self.base.options.system_libs.keys(); + for (system_libs) |link_lib| { + const full_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{link_lib}); + if (comp.crt_files.get(full_name)) |crt| { + try argv.append(crt.full_object_path); + } else { + try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); + } + } + + if (self.base.options.link_libc) { + try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); + } } // Positional arguments to the linker such as object files. diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index b7be6af82f..37e7f44488 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -23,21 +23,21 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { try addCCArgs(comp, arena, &args, false); try addLibcBottomHalfIncludes(comp, arena, &args); - var comp_sources = std.ArrayList(Compilation.CSourceFile).init(arena); + var crt_sources = std.ArrayList(Compilation.CSourceFile).init(arena); for (crt_src_files) |file_path| { - try comp_sources.append(.{ + try crt_sources.append(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, }); } - try comp.build_crt_file("crt", .Obj, comp_sources.items); + try comp.build_crt_file("crt", .Obj, crt_sources.items); } { // Compile WASI libc (sysroot). - var comp_sources = std.ArrayList(Compilation.CSourceFile).init(arena); + var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena); { // Compile dlmalloc. @@ -54,7 +54,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { }); for (dlmalloc_src_files) |file_path| { - try comp_sources.append(.{ + try libc_sources.append(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), @@ -70,73 +70,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { try addLibcBottomHalfIncludes(comp, arena, &args); for (libc_bottom_half_src_files) |file_path| { - try comp_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - } - - { - // Compile emulated sources depending only on libc-bottom-half. - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, true); - try addLibcBottomHalfIncludes(comp, arena, &args); - - for (emulated_process_clocks_src_files) |file_path| { - try comp_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - - for (emulated_getpid_src_files) |file_path| { - try comp_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - - for (emulated_mman_src_files) |file_path| { - try comp_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - } - - { - // Compile emulated signals (bottom-half). - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, true); - - for (emulated_signal_bottom_half_src_files) |file_path| { - try comp_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - } - - { - // Compile emulated signals (top-half). - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, true); - try addLibcTopHalfIncludes(comp, arena, &args); - try args.append("-D_WASI_EMULATED_SIGNAL"); - - for (emulated_signal_top_half_src_files) |file_path| { - try comp_sources.append(.{ + try libc_sources.append(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), @@ -152,7 +86,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { try addLibcTopHalfIncludes(comp, arena, &args); for (libc_top_half_src_files) |file_path| { - try comp_sources.append(.{ + try libc_sources.append(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), @@ -161,7 +95,98 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { } } - try comp.build_crt_file("c", .Lib, comp_sources.items); + try comp.build_crt_file("c", .Lib, libc_sources.items); + } + + { + // Compile emulated process clocks. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items); + } + + { + // Compile emulated getpid. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items); + } + + { + // Compile emulated mman. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items); + } + + { + // Compile emulated signals. + var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena); + + { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + + for (emulated_signal_bottom_half_src_files) |file_path| { + try emu_signal_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcTopHalfIncludes(comp, arena, &args); + try args.append("-D_WASI_EMULATED_SIGNAL"); + + for (emulated_signal_top_half_src_files) |file_path| { + try emu_signal_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items); } } From 4e4722a65e3bc3d6bb4518df3082ffea7c2a7c5d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 7 Jun 2021 11:02:11 +0200 Subject: [PATCH 3/6] cc,wasi: build referenced-only emulated components Move parsing of system libs into `main.zig` next to where we decide if we should link libC, and, if targeting WASI, if the specified libname equals one of the emulated components, save it on the side and remove it from the system libs. Then, build *only* those parts of WASI libc that were preserved in the previous step. This also fixes building of different crt1 bits needed to support reactors and commands. --- src/Compilation.zig | 43 ++++-- src/link.zig | 1 + src/link/Wasm.zig | 15 ++- src/main.zig | 12 ++ src/wasi_libc.zig | 318 +++++++++++++++++++++++++------------------- 5 files changed, 231 insertions(+), 158 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 4c015cb58f..444e69c557 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -203,8 +203,8 @@ const Job = union(enum) { /// needed when not linking libc and using LLVM for code generation because it generates /// calls to, for example, memcpy and memset. zig_libc: void, - /// WASI libc sysroot - wasi_libc_sysroot: void, + /// one of WASI libc static objects + wasi_libc_crt_file: wasi_libc.CRTFile, /// Use stage1 C++ code to compile zig code into an object file. stage1_module: void, @@ -279,7 +279,7 @@ pub const MiscTask = enum { libcxx, libcxxabi, libtsan, - wasi_libc_sysroot, + wasi_libc_crt_file, compiler_rt, libssp, zig_libc, @@ -646,6 +646,12 @@ pub const InitOptions = struct { framework_dirs: []const []const u8 = &[0][]const u8{}, frameworks: []const []const u8 = &[0][]const u8{}, system_libs: []const []const u8 = &[0][]const u8{}, + /// These correspond to the WASI libc emulated subcomponents including: + /// * process clocks + /// * getpid + /// * mman + /// * signal + wasi_emulated_libs: []const []const u8 = &[0][]const u8{}, link_libc: bool = false, link_libcpp: bool = false, link_libunwind: bool = false, @@ -1286,6 +1292,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .framework_dirs = options.framework_dirs, .system_libs = system_libs, .syslibroot = darwin_options.syslibroot, + .wasi_emulated_libs = options.wasi_emulated_libs, .lib_dirs = options.lib_dirs, .rpath_list = options.rpath_list, .strip = strip, @@ -1426,8 +1433,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { }, }); } - if (comp.wantBuildWasiLibcSysrootFromSource()) { - try comp.work_queue.write(&[_]Job{.{ .wasi_libc_sysroot = {} }}); + if (comp.wantBuildWasiLibcFromSource()) { + try comp.work_queue.ensureUnusedCapacity(6); // worst-case we need all components + const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; + for (wasi_emulated_libs) |lib_name| { + comp.work_queue.writeItemAssumeCapacity(.{ + .wasi_libc_crt_file = wasi_libc.getEmulatedLibCRTFile(lib_name).?, + }); + } + // TODO add logic deciding which crt1 we want here. + comp.work_queue.writeAssumeCapacity(&[_]Job{ + .{ .wasi_libc_crt_file = .crt1_o }, + .{ .wasi_libc_crt_file = .libc_a }, + }); } if (comp.wantBuildMinGWFromSource()) { const static_lib_jobs = [_]Job{ @@ -2169,12 +2187,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor ); }; }, - .wasi_libc_sysroot => { - wasi_libc.buildWasiLibcSysroot(self) catch |err| { + .wasi_libc_crt_file => |crt_file| { + wasi_libc.buildCRTFile(self, crt_file) catch |err| { // TODO Surface more error details. try self.setMiscFailure( - .wasi_libc_sysroot, - "unable to build WASI libc sysroot: {s}", + .wasi_libc_crt_file, + "unable to build WASI libc CRT file: {s}", .{@errorName(err)}, ); }; @@ -3303,7 +3321,7 @@ pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []cons if (comp.wantBuildGLibCFromSource() or comp.wantBuildMuslFromSource() or comp.wantBuildMinGWFromSource() or - comp.wantBuildWasiLibcSysrootFromSource()) + comp.wantBuildWasiLibcFromSource()) { return comp.crt_files.get(basename).?.full_object_path; } @@ -3343,8 +3361,9 @@ fn wantBuildMuslFromSource(comp: Compilation) bool { !comp.getTarget().isWasm(); } -fn wantBuildWasiLibcSysrootFromSource(comp: Compilation) bool { - return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm(); +fn wantBuildWasiLibcFromSource(comp: Compilation) bool { + return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and + comp.getTarget().os.tag == .wasi; } fn wantBuildMinGWFromSource(comp: Compilation) bool { diff --git a/src/link.zig b/src/link.zig index fcb263f03e..c013db4947 100644 --- a/src/link.zig +++ b/src/link.zig @@ -110,6 +110,7 @@ pub const Options = struct { framework_dirs: []const []const u8, frameworks: []const []const u8, system_libs: std.StringArrayHashMapUnmanaged(void), + wasi_emulated_libs: []const []const u8, lib_dirs: []const []const u8, rpath_list: []const []const u8, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 443ace855a..0168028354 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -699,18 +699,19 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { if (link_in_crt) { // TODO work out if we want standard crt, a reactor or a command - try argv.append(try comp.get_libc_crt_file(arena, "crt.o")); + try argv.append(try comp.get_libc_crt_file(arena, "crt1.o")); } if (!is_obj) { const system_libs = self.base.options.system_libs.keys(); for (system_libs) |link_lib| { - const full_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{link_lib}); - if (comp.crt_files.get(full_name)) |crt| { - try argv.append(crt.full_object_path); - } else { - try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); - } + try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); + } + + const wasi_emulated_libs = self.base.options.wasi_emulated_libs; + for (wasi_emulated_libs) |lib_name| { + const full_lib_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}); + try argv.append(try comp.get_libc_crt_file(arena, full_lib_name)); } if (self.base.options.link_libc) { diff --git a/src/main.zig b/src/main.zig index 9245f5fd8a..1e4ec0183f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -15,6 +15,7 @@ const Package = @import("Package.zig"); const build_options = @import("build_options"); const introspect = @import("introspect.zig"); const LibCInstallation = @import("libc_installation.zig").LibCInstallation; +const wasi_libc = @import("wasi_libc.zig"); const translate_c = @import("translate_c.zig"); const Cache = @import("Cache.zig"); const target_util = @import("target.zig"); @@ -616,6 +617,9 @@ fn buildOutputType( var system_libs = std.ArrayList([]const u8).init(gpa); defer system_libs.deinit(); + var wasi_emulated_libs = std.ArrayList([]const u8).init(gpa); + defer wasi_emulated_libs.deinit(); + var clang_argv = std.ArrayList([]const u8).init(gpa); defer clang_argv.deinit(); @@ -1586,6 +1590,13 @@ fn buildOutputType( if (std.fs.path.isAbsolute(lib_name)) { fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } + if (target_info.target.os.tag == .wasi) { + if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |_| { + try wasi_emulated_libs.append(lib_name); + _ = system_libs.orderedRemove(i); + continue; + } + } i += 1; } } @@ -1895,6 +1906,7 @@ fn buildOutputType( .framework_dirs = framework_dirs.items, .frameworks = frameworks.items, .system_libs = system_libs.items, + .wasi_emulated_libs = wasi_emulated_libs.items, .link_libc = link_libc, .link_libcpp = link_libcpp, .link_libunwind = link_libunwind, diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index 37e7f44488..0c178891c7 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const mem = std.mem; const path = std.fs.path; const Allocator = std.mem.Allocator; @@ -7,7 +8,34 @@ const build_options = @import("build_options"); const target_util = @import("target.zig"); const musl = @import("musl.zig"); -pub fn buildWasiLibcSysroot(comp: *Compilation) !void { +pub const CRTFile = enum { + crt1_o, + crt1_reactor_o, + crt1_command_o, + libc_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, "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 buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { if (!build_options.have_llvm) { return error.ZigCompilerNotBuiltWithLLVMExtensions; } @@ -17,176 +45,190 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void { defer arena_allocator.deinit(); const arena = &arena_allocator.allocator; - { - // Compile crt sources. - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, false); - try addLibcBottomHalfIncludes(comp, arena, &args); - - var crt_sources = std.ArrayList(Compilation.CSourceFile).init(arena); - for (crt_src_files) |file_path| { - try crt_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - try comp.build_crt_file("crt", .Obj, crt_sources.items); - } - - { - // Compile WASI libc (sysroot). - var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena); - - { - // Compile dlmalloc. + switch (crt_file) { + .crt1_o => { var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, true); - try args.appendSlice(&[_][]const u8{ - "-I", - try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", - "wasi", - "dlmalloc", - "include", - }), - }); - - for (dlmalloc_src_files) |file_path| { - try libc_sources.append(.{ + try addCCArgs(comp, arena, &args, false); + try addLibcBottomHalfIncludes(comp, arena, &args); + return comp.build_crt_file("crt1", .Obj, &[1]Compilation.CSourceFile{ + .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), + "libc", try sanitize(arena, crt1_src_file), }), .extra_flags = args.items, - }); - } - } + }, + }); + }, + .crt1_reactor_o => { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, false); + try addLibcBottomHalfIncludes(comp, arena, &args); + return comp.build_crt_file("crt1-reactor", .Obj, &[1]Compilation.CSourceFile{ + .{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, crt1_reactor_src_file), + }), + .extra_flags = args.items, + }, + }); + }, + .crt1_command_o => { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, false); + try addLibcBottomHalfIncludes(comp, arena, &args); + return comp.build_crt_file("crt1-command", .Obj, &[1]Compilation.CSourceFile{ + .{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, crt1_command_src_file), + }), + .extra_flags = args.items, + }, + }); + }, + .libc_a => { + var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena); - { - // Compile libc-bottom-half. + { + // Compile dlmalloc. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try args.appendSlice(&[_][]const u8{ + "-I", + try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", + "wasi", + "dlmalloc", + "include", + }), + }); + + for (dlmalloc_src_files) |file_path| { + try libc_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + { + // Compile libc-bottom-half. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcBottomHalfIncludes(comp, arena, &args); + + for (libc_bottom_half_src_files) |file_path| { + try libc_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + { + // Compile libc-top-half. + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcTopHalfIncludes(comp, arena, &args); + + for (libc_top_half_src_files) |file_path| { + try libc_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + try comp.build_crt_file("c", .Lib, libc_sources.items); + }, + .libwasi_emulated_process_clocks_a => { var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, true); try addLibcBottomHalfIncludes(comp, arena, &args); - for (libc_bottom_half_src_files) |file_path| { - try libc_sources.append(.{ + 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.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, }); } - } - - { - // Compile libc-top-half. + try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items); + }, + .libwasi_emulated_getpid_a => { var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, true); - try addLibcTopHalfIncludes(comp, arena, &args); + try addLibcBottomHalfIncludes(comp, arena, &args); - for (libc_top_half_src_files) |file_path| { - try libc_sources.append(.{ + 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.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, }); } - } - - try comp.build_crt_file("c", .Lib, libc_sources.items); - } - - { - // Compile emulated process clocks. - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items); - } - - { - // Compile emulated getpid. - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items); - } - - { - // Compile emulated mman. - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, 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.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); - } - try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items); - } - - { - // Compile emulated signals. - var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena); - - { + try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items); + }, + .libwasi_emulated_mman_a => { var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, true); + try addLibcBottomHalfIncludes(comp, arena, &args); - for (emulated_signal_bottom_half_src_files) |file_path| { - try emu_signal_sources.append(.{ + 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.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, }); } - } + try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items); + }, + .libwasi_emulated_signal_a => { + var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena); - { - var args = std.ArrayList([]const u8).init(arena); - try addCCArgs(comp, arena, &args, true); - try addLibcTopHalfIncludes(comp, arena, &args); - try args.append("-D_WASI_EMULATED_SIGNAL"); + { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); - for (emulated_signal_top_half_src_files) |file_path| { - try emu_signal_sources.append(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ - "libc", try sanitize(arena, file_path), - }), - .extra_flags = args.items, - }); + for (emulated_signal_bottom_half_src_files) |file_path| { + try emu_signal_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } } - } - try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items); + { + var args = std.ArrayList([]const u8).init(arena); + try addCCArgs(comp, arena, &args, true); + try addLibcTopHalfIncludes(comp, arena, &args); + try args.append("-D_WASI_EMULATED_SIGNAL"); + + for (emulated_signal_top_half_src_files) |file_path| { + try emu_signal_sources.append(.{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ + "libc", try sanitize(arena, file_path), + }), + .extra_flags = args.items, + }); + } + } + + try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items); + }, } } @@ -1084,11 +1126,9 @@ const libc_top_half_src_files = [_][]const u8{ "wasi/libc-top-half/sources/arc4random.c", }; -const crt_src_files = &[_][]const u8{ - "wasi/libc-bottom-half/crt/crt1.c", - "wasi/libc-bottom-half/crt/crt1-command.c", - "wasi/libc-bottom-half/crt/crt1-reactor.c", -}; +const crt1_src_file = "wasi/libc-bottom-half/crt/crt1.c"; +const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c"; +const crt1_reactor_src_file = "wasi/libc-bottom-half/crt/crt1-reactor.c"; const emulated_process_clocks_src_files = &[_][]const u8{ "wasi/libc-bottom-half/clocks/clock.c", From 95745f77da6cd3ca30aea6aa47253c1e0a4f5a75 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 7 Jun 2021 16:08:43 +0200 Subject: [PATCH 4/6] wasi: skip adding wasi_snapshot_preview1 as lib dep in stage1 --- src/Compilation.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Compilation.zig b/src/Compilation.zig index 444e69c557..1d85182f06 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4157,6 +4157,12 @@ pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void { if (comp.bin_file.options.skip_linker_dependencies) return; // This happens when an `extern "foo"` function is referenced by the stage1 backend. + if (comp.getTarget().os.tag == .wasi and mem.eql(u8, "wasi_snapshot_preview1", lib_name)) { + // Any referenced symbol from this lib, will be undefined until + // runtime as this lib is provided directly by the runtime. + return; + } + // If we haven't seen this library yet and we're targeting Windows, we need to queue up // a work item to produce the DLL import library for this. const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name); From dd84ccda5daf63373b2b5df3ac02025017b7efbf Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 7 Jun 2021 17:03:29 +0200 Subject: [PATCH 5/6] wasi: clean up linking logic Do not try to link WASI libc or emulated subcomponents when not targeting WASI; e.g., when targeting `wasm32-freestanding`. --- src/link/Wasm.zig | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 0168028354..39f1f13e60 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -574,7 +574,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { null; const target = self.base.options.target; - const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe; const id_symlink_basename = "lld.id"; @@ -653,8 +652,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); } } else { - const is_obj = self.base.options.output_mode == .Obj; - // Create an LLD command line and invoke it. var argv = std.ArrayList([]const u8).init(self.base.allocator); defer argv.deinit(); @@ -662,10 +659,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { // This is necessary because LLD does not behave properly as a library - // it calls exit() and does not reset all global data between invocations. try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" }); - if (is_obj) { - try argv.append("-r"); - } - try argv.append("-error-limit=0"); if (self.base.options.lto) { @@ -697,25 +690,29 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { full_out_path, }); - if (link_in_crt) { - // TODO work out if we want standard crt, a reactor or a command - try argv.append(try comp.get_libc_crt_file(arena, "crt1.o")); - } - - if (!is_obj) { - const system_libs = self.base.options.system_libs.keys(); - for (system_libs) |link_lib| { - try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); + if (target.os.tag == .wasi) { + if (self.base.options.link_libc and self.base.options.output_mode == .Exe) { + // TODO work out if we want standard crt, a reactor or a command + try argv.append(try comp.get_libc_crt_file(arena, "crt1.o")); } - const wasi_emulated_libs = self.base.options.wasi_emulated_libs; - for (wasi_emulated_libs) |lib_name| { - const full_lib_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}); - try argv.append(try comp.get_libc_crt_file(arena, full_lib_name)); - } + const is_exe_or_dyn_lib = self.base.options.output_mode == .Exe or + (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic); + if (is_exe_or_dyn_lib) { + const system_libs = self.base.options.system_libs.keys(); + for (system_libs) |link_lib| { + try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); + } - if (self.base.options.link_libc) { - try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); + const wasi_emulated_libs = self.base.options.wasi_emulated_libs; + for (wasi_emulated_libs) |lib_name| { + const full_lib_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}); + try argv.append(try comp.get_libc_crt_file(arena, full_lib_name)); + } + + if (self.base.options.link_libc) { + try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); + } } } From 2ee1f7898b27447bb9b21d284842415c7459db4b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 9 Jun 2021 01:23:05 +0200 Subject: [PATCH 6/6] cc,wasi: store CRTFile enum in wasi_emulated_libs * then, in `link/Wasm.zig` map `CRTFile` to full emulated libs name * move logic for removing any mention of WASI snapshot `wasi_snapshot_preview1` from `Compilation.zig` into `link/Wasm.zig` --- src/Compilation.zig | 14 ++++---------- src/link.zig | 3 ++- src/link/Wasm.zig | 15 ++++++++++++--- src/main.zig | 6 +++--- src/wasi_libc.zig | 10 ++++++++++ 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 1d85182f06..371bcdaf18 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -651,7 +651,7 @@ pub const InitOptions = struct { /// * getpid /// * mman /// * signal - wasi_emulated_libs: []const []const u8 = &[0][]const u8{}, + wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{}, link_libc: bool = false, link_libcpp: bool = false, link_libunwind: bool = false, @@ -1434,11 +1434,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { }); } if (comp.wantBuildWasiLibcFromSource()) { - try comp.work_queue.ensureUnusedCapacity(6); // worst-case we need all components const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; - for (wasi_emulated_libs) |lib_name| { + try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components + for (wasi_emulated_libs) |crt_file| { comp.work_queue.writeItemAssumeCapacity(.{ - .wasi_libc_crt_file = wasi_libc.getEmulatedLibCRTFile(lib_name).?, + .wasi_libc_crt_file = crt_file, }); } // TODO add logic deciding which crt1 we want here. @@ -4157,12 +4157,6 @@ pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void { if (comp.bin_file.options.skip_linker_dependencies) return; // This happens when an `extern "foo"` function is referenced by the stage1 backend. - if (comp.getTarget().os.tag == .wasi and mem.eql(u8, "wasi_snapshot_preview1", lib_name)) { - // Any referenced symbol from this lib, will be undefined until - // runtime as this lib is provided directly by the runtime. - return; - } - // If we haven't seen this library yet and we're targeting Windows, we need to queue up // a work item to produce the DLL import library for this. const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name); diff --git a/src/link.zig b/src/link.zig index c013db4947..4072e90ca3 100644 --- a/src/link.zig +++ b/src/link.zig @@ -13,6 +13,7 @@ const Type = @import("type.zig").Type; const Cache = @import("Cache.zig"); const build_options = @import("build_options"); const LibCInstallation = @import("libc_installation.zig").LibCInstallation; +const wasi_libc = @import("wasi_libc.zig"); pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; @@ -110,7 +111,7 @@ pub const Options = struct { framework_dirs: []const []const u8, frameworks: []const []const u8, system_libs: std.StringArrayHashMapUnmanaged(void), - wasi_emulated_libs: []const []const u8, + wasi_emulated_libs: []const wasi_libc.CRTFile, lib_dirs: []const []const u8, rpath_list: []const []const u8, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 39f1f13e60..21bb9d826c 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -15,6 +15,7 @@ const codegen = @import("../codegen/wasm.zig"); const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const build_options = @import("build_options"); +const wasi_libc = @import("../wasi_libc.zig"); const Cache = @import("../Cache.zig"); const TypedValue = @import("../TypedValue.zig"); @@ -700,14 +701,22 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic); if (is_exe_or_dyn_lib) { const system_libs = self.base.options.system_libs.keys(); + for (system_libs) |link_lib| { + if (mem.eql(u8, "wasi_snapshot_preview1", link_lib)) { + // Any referenced symbol from this lib, will be undefined until + // runtime as this lib is provided directly by the runtime. + continue; + } try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); } const wasi_emulated_libs = self.base.options.wasi_emulated_libs; - for (wasi_emulated_libs) |lib_name| { - const full_lib_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}); - try argv.append(try comp.get_libc_crt_file(arena, full_lib_name)); + for (wasi_emulated_libs) |crt_file| { + try argv.append(try comp.get_libc_crt_file( + arena, + wasi_libc.emulatedLibCRFileLibName(crt_file), + )); } if (self.base.options.link_libc) { diff --git a/src/main.zig b/src/main.zig index 1e4ec0183f..0b93f97726 100644 --- a/src/main.zig +++ b/src/main.zig @@ -617,7 +617,7 @@ fn buildOutputType( var system_libs = std.ArrayList([]const u8).init(gpa); defer system_libs.deinit(); - var wasi_emulated_libs = std.ArrayList([]const u8).init(gpa); + var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(gpa); defer wasi_emulated_libs.deinit(); var clang_argv = std.ArrayList([]const u8).init(gpa); @@ -1591,8 +1591,8 @@ fn buildOutputType( fatal("cannot use absolute path as a system library: {s}", .{lib_name}); } if (target_info.target.os.tag == .wasi) { - if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |_| { - try wasi_emulated_libs.append(lib_name); + if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| { + try wasi_emulated_libs.append(crt_file); _ = system_libs.orderedRemove(i); continue; } diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index 0c178891c7..b61ba5091c 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -35,6 +35,16 @@ pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile { return null; } +pub fn emulatedLibCRFileLibName(crt_file: CRTFile) []const u8 { + return switch (crt_file) { + .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 buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { if (!build_options.have_llvm) { return error.ZigCompilerNotBuiltWithLLVMExtensions;