Commit 8aa20227ed

LemonBoy <thatlemon@gmail.com>
2019-10-11 19:13:59
Fix cross-compilation to i386-windows-msvc
Use Mingw's .def files to build a .lib when possible and show an error otherwise.
1 parent 01b2c29
Changed files (2)
src/link.cpp
@@ -2098,6 +2098,60 @@ static bool is_linking_system_lib(CodeGen *g, const char *name) {
     return false;
 }
 
+static Error find_mingw_lib_def(LinkJob *lj, const char *name, Buf *out_path) {
+    CodeGen *g = lj->codegen;
+    Buf override_path = BUF_INIT;
+    Error err;
+
+    char const *lib_path = nullptr;
+    if (g->zig_target->arch == ZigLLVM_x86) {
+        lib_path = "lib32";
+    } else if (g->zig_target->arch == ZigLLVM_x86_64) {
+        lib_path = "lib64";
+    } else if (target_is_arm(g->zig_target)) {
+        const bool is_32 = target_arch_pointer_bit_width(g->zig_target->arch) == 32;
+        lib_path = is_32 ? "libarm32" : "libarm64";
+    } else {
+        zig_unreachable();
+    }
+
+    // Try the archtecture-specific path first
+    buf_resize(&override_path, 0);
+    buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), lib_path, name);
+
+    bool does_exist;
+    if ((err = os_file_exists(&override_path, &does_exist)) != ErrorNone) {
+        return err;
+    }
+
+    if (!does_exist) {
+        // Try the generic version
+        buf_resize(&override_path, 0);
+        buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "lib-common" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), name);
+
+        if ((err = os_file_exists(&override_path, &does_exist)) != ErrorNone) {
+            return err;
+        }
+    }
+
+    if (!does_exist) {
+        // Try the generic version and preprocess it
+        buf_resize(&override_path, 0);
+        buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "lib-common" OS_SEP "%s.def.in", buf_ptr(g->zig_lib_dir), name);
+
+        if ((err = os_file_exists(&override_path, &does_exist)) != ErrorNone) {
+            return err;
+        }
+    }
+
+    if (!does_exist) {
+        return ErrorFileNotFound;
+    }
+
+    buf_init_from_buf(out_path, &override_path);
+    return ErrorNone;
+}
+
 static void add_mingw_link_args(LinkJob *lj, bool is_library) {
     CodeGen *g = lj->codegen;
 
@@ -2125,55 +2179,18 @@ static void add_mingw_link_args(LinkJob *lj, bool is_library) {
         const char *name = mingw_def_list[def_i].name;
         const bool always_link = mingw_def_list[def_i].always_link;
 
-        Buf override_path = BUF_INIT;
+        Buf lib_path = BUF_INIT;
+        Error err = find_mingw_lib_def(lj, name, &lib_path);
 
-        char const *lib_path = nullptr;
-        if (g->zig_target->arch == ZigLLVM_x86) {
-            lib_path = "lib32";
-        } else if (g->zig_target->arch == ZigLLVM_x86_64) {
-            lib_path = "lib64";
-        } else if (target_is_arm(g->zig_target)) {
-            const bool is_32 = target_arch_pointer_bit_width(g->zig_target->arch) == 32;
-            lib_path = is_32 ? "libarm32" : "libarm64";
-        } else {
-            zig_unreachable();
-        }
-
-        // Try the archtecture-specific path first
-        buf_resize(&override_path, 0);
-        buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), lib_path, name);
-
-        bool does_exist;
-        if (os_file_exists(&override_path, &does_exist) != ErrorNone) {
-            zig_panic("link: unable to check if file exists: %s", buf_ptr(&override_path));
-        }
-
-        if (!does_exist) {
-            // Try the generic version
-            buf_resize(&override_path, 0);
-            buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "lib-common" OS_SEP "%s.def", buf_ptr(g->zig_lib_dir), name);
-
-            if (os_file_exists(&override_path, &does_exist) != ErrorNone) {
-                zig_panic("link: unable to check if file exists: %s", buf_ptr(&override_path));
-            }
-        }
-
-        if (!does_exist) {
-            // Try the generic version and preprocess it
-            buf_resize(&override_path, 0);
-            buf_appendf(&override_path, "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "lib-common" OS_SEP "%s.def.in", buf_ptr(g->zig_lib_dir), name);
-
-            if (os_file_exists(&override_path, &does_exist) != ErrorNone) {
-                zig_panic("link: unable to check if file exists: %s", buf_ptr(&override_path));
-            }
-        }
-
-        if (!does_exist) {
+        if (err == ErrorFileNotFound) {
             zig_panic("link: could not find .def file to build %s\n", name);
+        } else if (err != ErrorNone) {
+            zig_panic("link: unable to check if .def file for %s exists: %s",
+                      name, err_str(err));
         }
 
         if (always_link || is_linking_system_lib(g, name)) {
-            lj->args.append(get_def_lib(g, name, &override_path));
+            lj->args.append(get_def_lib(g, name, &lib_path));
         }
     }
 }
@@ -2307,8 +2324,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
         lj->args.append(buf_ptr(compiler_rt_o_path));
     }
 
-    Buf *def_contents = buf_alloc();
-    ZigList<const char *> gen_lib_args = {0};
     for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
         LinkLib *link_lib = g->link_libs_list.at(lib_i);
         if (buf_eql_str(link_lib->name, "c")) {
@@ -2331,36 +2346,27 @@ static void construct_linker_job_coff(LinkJob *lj) {
             continue;
         }
 
-        buf_resize(def_contents, 0);
-        buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
-        for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
-            Buf *symbol_name = link_lib->symbols.at(exp_i);
-            buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
-        }
-        buf_appendf(def_contents, "\n");
-
-        Buf *def_path = buf_alloc();
-        os_path_join(g->output_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
-        if ((err = os_write_file(def_path, def_contents))) {
-            zig_panic("error writing def file: %s", err_str(err));
-        }
+        // This library may be a system one and we may have a suitable .lib file
 
-        Buf *generated_lib_path = buf_alloc();
-        os_path_join(g->output_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
+        // Normalize the library name to lower case, the FS may be
+        // case-sensitive
+        char *name = strdup(buf_ptr(link_lib->name));
+        assert(name != nullptr);
+        for (char *ch = name; *ch; ++ch) *ch = tolower(*ch);
 
-        gen_lib_args.resize(0);
-        gen_lib_args.append("link");
+        Buf lib_path = BUF_INIT;
+        err = find_mingw_lib_def(lj, name, &lib_path);
 
-        coff_append_machine_arg(g, &gen_lib_args);
-        gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
-        gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
-        Buf diag = BUF_INIT;
-        ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target);
-        if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) {
-            fprintf(stderr, "%s\n", buf_ptr(&diag));
-            exit(1);
+        if (err == ErrorFileNotFound) {
+            zig_panic("link: could not find .def file to build %s\n", name);
+        } else if (err != ErrorNone) {
+            zig_panic("link: unable to check if .def file for %s exists: %s",
+                      name, err_str(err));
         }
-        lj->args.append(buf_ptr(generated_lib_path));
+
+        lj->args.append(get_def_lib(g, name, &lib_path));
+
+        free(name);
     }
 }
 
test/tests.zig
@@ -163,6 +163,16 @@ const test_targets = [_]TestTarget{
         .disable_native = true,
     },
 
+    TestTarget{
+        .target = Target{
+            .Cross = CrossTarget{
+                .os = .windows,
+                .arch = .i386,
+                .abi = .msvc,
+            },
+        },
+    },
+
     TestTarget{
         .target = Target{
             .Cross = CrossTarget{