Commit 14cdb01f35

Andrew Kelley <andrew@ziglang.org>
2019-05-15 22:20:16
improvements to zig's implementation of libc and WebAssembly
* rename std/special/builtin.zig to std/special/c.zig not to be confused with @import("builtin") which is entirely different, this is zig's multi-target libc implementation. * WebAssembly: build-exe is for executables which have a main(). build-lib is for building libraries of functions to use from, for example, a web browser environment. - for now pass --export-all for libraries when there are any C objects because we have no way to detect the list of exports when compiling C code. - stop passing --no-entry for executables. if you want --no-entry then use build-lib. * make the "musl" ABI the default ABI for wasm32-freestanding. * zig provides libc for wasm32-freestanding-musl.
1 parent 3aa43dc
Changed files (4)
src/link.cpp
@@ -776,8 +776,8 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
 
 static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) {
     // The Mach-O LLD code is not well maintained, and trips an assertion
-    // when we link compiler_rt and builtin as libraries rather than objects.
-    // Here we workaround this by having compiler_rt and builtin be objects.
+    // when we link compiler_rt and libc.zig as libraries rather than objects.
+    // Here we workaround this by having compiler_rt and libc.zig be objects.
     // TODO write our own linker. https://github.com/ziglang/zig/issues/1535
     if (parent_gen->zig_target->os == OsMacOSX) {
         child_out_type = OutTypeObj;
@@ -787,7 +787,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path,
             parent_gen->libc);
     codegen_set_out_name(child_gen, buf_create_from_str(aname));
 
-    // This is so that compiler_rt and builtin libraries know whether they
+    // This is so that compiler_rt and libc.zig libraries know whether they
     // will eventually be linked with libc. They make different decisions
     // about what to export depending on whether libc is linked.
     if (parent_gen->libc_link_lib != nullptr) {
@@ -1002,8 +1002,8 @@ static void construct_linker_job_elf(LinkJob *lj) {
 
     if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
         if (g->libc_link_lib == nullptr) {
-            Buf *builtin_a_path = build_a(g, "builtin");
-            lj->args.append(buf_ptr(builtin_a_path));
+            Buf *libc_a_path = build_a(g, "c");
+            lj->args.append(buf_ptr(libc_a_path));
         }
 
         Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
@@ -1092,30 +1092,33 @@ static void construct_linker_job_wasm(LinkJob *lj) {
 
     lj->args.append("-error-limit=0");
 
-    if (g->zig_target->os != OsWASI) {
-	    lj->args.append("--no-entry");  // So lld doesn't look for _start.
+    if (g->out_type != OutTypeExe) {
+	    lj->args.append("--no-entry"); // So lld doesn't look for _start.
+
+        // If there are any C source files we cannot rely on individual exports.
+        if (g->c_source_files.length != 0) {
+            lj->args.append("--export-all");
+        } else {
+            auto export_it = g->exported_symbol_names.entry_iterator();
+            decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
+            while ((curr_entry = export_it.next()) != nullptr) {
+                Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key));
+                lj->args.append(buf_ptr(arg));
+            }
+        }
     }
     lj->args.append("--allow-undefined");
     lj->args.append("-o");
     lj->args.append(buf_ptr(&g->output_file_path));
 
-    auto export_it = g->exported_symbol_names.entry_iterator();
-    decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
-    while ((curr_entry = export_it.next()) != nullptr) {
-        Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key));
-        lj->args.append(buf_ptr(arg));
-    }
-
     // .o files
     for (size_t i = 0; i < g->link_objects.length; i += 1) {
         lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
     }
 
-    if (g->out_type == OutTypeExe) {
-        if (g->libc_link_lib == nullptr) {
-            Buf *builtin_a_path = build_a(g, "builtin");
-            lj->args.append(buf_ptr(builtin_a_path));
-        }
+    if (g->out_type != OutTypeObj) {
+        Buf *libc_a_path = build_a(g, "c");
+        lj->args.append(buf_ptr(libc_a_path));
 
         Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
         lj->args.append(buf_ptr(compiler_rt_o_path));
@@ -1356,8 +1359,8 @@ static void construct_linker_job_coff(LinkJob *lj) {
 
     if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {
         if (g->libc_link_lib == nullptr && !g->is_dummy_so) {
-            Buf *builtin_a_path = build_a(g, "builtin");
-            lj->args.append(buf_ptr(builtin_a_path));
+            Buf *libc_a_path = build_a(g, "c");
+            lj->args.append(buf_ptr(libc_a_path));
         }
 
         // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
src/target.cpp
@@ -1376,6 +1376,9 @@ bool target_is_single_threaded(const ZigTarget *target) {
 }
 
 ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
+    if (arch == ZigLLVM_wasm32 || arch == ZigLLVM_wasm64) {
+        return ZigLLVM_Musl;
+    }
     switch (os) {
         case OsFreestanding:
         case OsAnanas:
@@ -1490,6 +1493,7 @@ static const AvailableLibC libcs_available[] = {
     {ZigLLVM_systemz, OsLinux, ZigLLVM_Musl},
     {ZigLLVM_sparc, OsLinux, ZigLLVM_GNU},
     {ZigLLVM_sparcv9, OsLinux, ZigLLVM_GNU},
+    {ZigLLVM_wasm32, OsFreestanding, ZigLLVM_Musl},
     {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNU},
     {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNUX32},
     {ZigLLVM_x86_64, OsLinux, ZigLLVM_Musl},
@@ -1508,7 +1512,6 @@ bool target_can_build_libc(const ZigTarget *target) {
 }
 
 const char *target_libc_generic_name(const ZigTarget *target) {
-    assert(target->os == OsLinux);
     switch (target->abi) {
         case ZigLLVM_GNU:
         case ZigLLVM_GNUABIN32:
@@ -1520,6 +1523,7 @@ const char *target_libc_generic_name(const ZigTarget *target) {
         case ZigLLVM_Musl:
         case ZigLLVM_MuslEABI:
         case ZigLLVM_MuslEABIHF:
+        case ZigLLVM_UnknownEnvironment:
             return "musl";
         case ZigLLVM_CODE16:
         case ZigLLVM_EABI:
@@ -1530,7 +1534,6 @@ const char *target_libc_generic_name(const ZigTarget *target) {
         case ZigLLVM_Cygnus:
         case ZigLLVM_CoreCLR:
         case ZigLLVM_Simulator:
-        case ZigLLVM_UnknownEnvironment:
             zig_unreachable();
     }
     zig_unreachable();
std/special/builtin.zig → std/special/c.zig
@@ -1,10 +1,26 @@
-// These functions are provided when not linking against libc because LLVM
-// sometimes generates code that calls them.
+// This is Zig's multi-target implementation of libc.
+// When builtin.link_libc is true, we need to export all the functions and
+// provide an entire C API.
+// Otherwise, only the functions which LLVM generates calls to need to be generated,
+// such as memcpy, memset, and some math functions.
 
 const std = @import("std");
 const builtin = @import("builtin");
 const maxInt = std.math.maxInt;
 
+const is_wasm = switch (builtin.arch) { .wasm32, .wasm64 => true, else => false};
+const is_freestanding = switch (builtin.os) { .freestanding => true, else => false };
+comptime {
+    if (is_freestanding and is_wasm) {
+        @export("_start", wasm_start, .Strong);
+    }
+}
+
+extern fn main(argc: c_int, argv: [*][*]u8) c_int;
+extern fn wasm_start() c_int {
+    return main(0, undefined);
+}
+
 // Avoid dragging in the runtime safety mechanisms into this .o file,
 // unless we're trying to test this file.
 pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
CMakeLists.txt
@@ -643,7 +643,7 @@ set(ZIG_STD_FILES
     "special/bootstrap_lib.zig"
     "special/bootstrap_windows_tls.zig"
     "special/build_runner.zig"
-    "special/builtin.zig"
+    "special/c.zig"
     "special/compiler_rt.zig"
     "special/compiler_rt/stack_probe.zig"
     "special/compiler_rt/arm/aeabi_fcmp.zig"