Commit 525c2eaf5d

Andrew Kelley <andrew@ziglang.org>
2019-02-25 19:34:25
building DLLs on Windows works better
1 parent e76ce2c
src/all_types.hpp
@@ -1743,6 +1743,7 @@ struct CodeGen {
     Buf triple_str;
     Buf global_asm;
     Buf *out_h_path;
+    Buf *out_lib_path;
     Buf artifact_dir;
     Buf output_file_path;
     Buf o_file_output_path;
src/codegen.cpp
@@ -175,6 +175,10 @@ void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
     g->out_h_path = h_path;
 }
 
+void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path) {
+    g->out_lib_path = lib_path;
+}
+
 void codegen_set_output_path(CodeGen *g, Buf *path) {
     g->wanted_output_file_path = path;
 }
@@ -8201,7 +8205,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
     args.append("-c");
     args.append(buf_ptr(c_source_file));
 
-    if (!g->disable_pic) {
+    if (!g->disable_pic && target_supports_fpic(g->zig_target)) {
         args.append("-fPIC");
     }
 
src/codegen.hpp
@@ -41,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
 void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
 void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
 void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
+void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
 void codegen_set_output_path(CodeGen *g, Buf *path);
 void codegen_add_time_event(CodeGen *g, const char *name);
 void codegen_print_timing_report(CodeGen *g, FILE *f);
src/link.cpp
@@ -554,6 +554,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
     bool is_library = g->out_type == OutTypeLib;
     switch (g->subsystem) {
         case TargetSubsystemAuto:
+            add_nt_link_args(lj, is_library);
             break;
         case TargetSubsystemConsole:
             lj->args.append("/SUBSYSTEM:console");
src/main.cpp
@@ -60,6 +60,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
         "  --name [name]                override output name\n"
         "  --output [file]              override destination path\n"
         "  --output-h [file]            generate header file\n"
+        "  --output-lib [file]          override import library path\n"
         "  --pkg-begin [name] [path]    make pkg available to import and push current pkg\n"
         "  --pkg-end                    pop current pkg\n"
         "  --release-fast               build with optimizations on and safety off\n"
@@ -375,6 +376,7 @@ int main(int argc, char **argv) {
     const char *in_file = nullptr;
     const char *out_file = nullptr;
     const char *out_file_h = nullptr;
+    const char *out_file_lib = nullptr;
     bool strip = false;
     bool is_static = false;
     OutType out_type = OutTypeUnknown;
@@ -661,6 +663,8 @@ int main(int argc, char **argv) {
                     out_file = argv[i];
                 } else if (strcmp(arg, "--output-h") == 0) {
                     out_file_h = argv[i];
+                } else if (strcmp(arg, "--output-lib") == 0) {
+                    out_file_lib = argv[i];
                 } else if (strcmp(arg, "--color") == 0) {
                     if (strcmp(argv[i], "auto") == 0) {
                         color = ErrColorAuto;
@@ -1094,6 +1098,8 @@ int main(int argc, char **argv) {
                 codegen_set_output_path(g, buf_create_from_str(out_file));
             if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
                 codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
+            if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
+                codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
 
 
             add_package(g, cur_pkg, g->root_package);
src/target.cpp
@@ -1049,3 +1049,9 @@ bool target_requires_libc(const ZigTarget *target) {
     // since this is the stable syscall interface.
     return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);
 }
+
+bool target_supports_fpic(const ZigTarget *target) {
+  // This is not whether the target supports Position Independent Code, but whether the -fPIC
+  // C compiler argument is valid.
+  return target->os != OsWindows;
+}
src/target.hpp
@@ -141,5 +141,6 @@ bool target_allows_addr_zero(const ZigTarget *target);
 bool target_has_valgrind_support(const ZigTarget *target);
 bool target_is_darwin(const ZigTarget *target);
 bool target_requires_libc(const ZigTarget *target);
+bool target_supports_fpic(const ZigTarget *target);
 
 #endif
std/build.zig
@@ -815,6 +815,7 @@ pub const LibExeObjStep = struct {
     linker_script: ?[]const u8,
     out_filename: []const u8,
     output_path: ?[]const u8,
+    output_lib_path: ?[]const u8,
     static: bool,
     version: Version,
     object_files: ArrayList([]const u8),
@@ -839,6 +840,7 @@ pub const LibExeObjStep = struct {
     root_src: ?[]const u8,
     output_h_path: ?[]const u8,
     out_h_filename: []const u8,
+    out_lib_filename: []const u8,
     assembly_files: ArrayList([]const u8),
     packages: ArrayList(Pkg),
     build_options_contents: std.Buffer,
@@ -901,10 +903,12 @@ pub const LibExeObjStep = struct {
             .frameworks = BufSet.init(builder.allocator),
             .step = Step.init(name, builder.allocator, make),
             .output_path = null,
+            .output_lib_path = null,
             .output_h_path = null,
             .version = ver,
             .out_filename = undefined,
             .out_h_filename = builder.fmt("{}.h", name),
+            .out_lib_filename = undefined,
             .major_only_filename = undefined,
             .name_only_filename = undefined,
             .object_files = ArrayList([]const u8).init(builder.allocator),
@@ -941,21 +945,32 @@ pub const LibExeObjStep = struct {
             },
             Kind.Lib => {
                 if (self.static) {
-                    self.out_filename = self.builder.fmt("lib{}.a", self.name);
+                    switch (self.target.getOs()) {
+                        builtin.Os.windows => {
+                            self.out_filename = self.builder.fmt("{}.lib", self.name);
+                        },
+                        else => {
+                            self.out_filename = self.builder.fmt("lib{}.a", self.name);
+                        },
+                    }
+                    self.out_lib_filename = self.out_filename;
                 } else {
                     switch (self.target.getOs()) {
                         builtin.Os.ios, builtin.Os.macosx => {
                             self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
                             self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
                             self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
+                            self.out_lib_filename = self.out_filename;
                         },
                         builtin.Os.windows => {
                             self.out_filename = self.builder.fmt("{}.dll", self.name);
+                            self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
                         },
                         else => {
                             self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
                             self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
                             self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
+                            self.out_lib_filename = self.out_filename;
                         },
                     }
                 }
@@ -990,7 +1005,11 @@ pub const LibExeObjStep = struct {
 
         self.step.dependOn(&lib.step);
 
-        self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
+        if (lib.static or self.target.isWindows()) {
+            self.object_files.append(lib.getOutputLibPath()) catch unreachable;
+        } else {
+            self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
+        }
 
         // TODO should be some kind of isolated directory that only has this header in it
         self.include_dirs.append(self.builder.cache_root) catch unreachable;
@@ -1060,6 +1079,22 @@ pub const LibExeObjStep = struct {
         ) catch unreachable;
     }
 
+    pub fn setOutputLibPath(self: *LibExeObjStep, file_path: []const u8) void {
+        assert(self.kind == Kind.Lib);
+        if (self.static)
+            return self.setOutputPath(file_path);
+
+        self.output_lib_path = file_path;
+    }
+
+    pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
+        assert(self.kind == Kind.Lib);
+        return if (self.output_lib_path) |output_lib_path| output_lib_path else os.path.join(
+            self.builder.allocator,
+            [][]const u8{ self.builder.cache_root, self.out_lib_filename },
+        ) catch unreachable;
+    }
+
     pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
         self.output_h_path = file_path;
 
@@ -1225,6 +1260,12 @@ pub const LibExeObjStep = struct {
         zig_args.append("--output") catch unreachable;
         zig_args.append(output_path) catch unreachable;
 
+        if (self.kind == Kind.Lib and !self.static) {
+            const output_lib_path = builder.pathFromRoot(self.getOutputLibPath());
+            zig_args.append("--output-lib") catch unreachable;
+            zig_args.append(output_lib_path) catch unreachable;
+        }
+
         if (self.kind != Kind.Exe) {
             const output_h_path = self.getOutputHPath();
             zig_args.append("--output-h") catch unreachable;
test/build_examples.zig
@@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
     cases.addC("example/hello_world/hello_libc.zig");
     cases.add("example/cat/main.zig");
     cases.add("example/guess_number/main.zig");
-    if (!is_windows) {
-        // TODO get this test passing on windows
-        // See https://github.com/ziglang/zig/issues/538
-        cases.addBuildFile("example/shared_library/build.zig");
-        cases.addBuildFile("example/mix_o_files/build.zig");
-    }
+    cases.addBuildFile("example/shared_library/build.zig");
+    cases.addBuildFile("example/mix_o_files/build.zig");
     if (builtin.os != builtin.Os.macosx) {
         // TODO https://github.com/ziglang/zig/issues/1126
         cases.addBuildFile("test/standalone/issue_339/build.zig");