diff --git a/src/all_types.hpp b/src/all_types.hpp index baa0267238..8099f99f48 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/codegen.cpp b/src/codegen.cpp index f14749bb28..3edff93be8 100644 --- a/src/codegen.cpp +++ b/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"); } diff --git a/src/codegen.hpp b/src/codegen.hpp index 035b759ec5..4f62cc4cbc 100644 --- a/src/codegen.hpp +++ b/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); diff --git a/src/link.cpp b/src/link.cpp index 2068b8efb0..5f611ae5a6 100644 --- a/src/link.cpp +++ b/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"); diff --git a/src/main.cpp b/src/main.cpp index a7f6e0b95d..1c154250ff 100644 --- a/src/main.cpp +++ b/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); diff --git a/src/target.cpp b/src/target.cpp index 01e8b90cea..49a1742945 100644 --- a/src/target.cpp +++ b/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; +} diff --git a/src/target.hpp b/src/target.hpp index 620c9b2664..dceeee2eca 100644 --- a/src/target.hpp +++ b/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 diff --git a/std/build.zig b/std/build.zig index 4386b730cd..0d03b0325f 100644 --- a/std/build.zig +++ b/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; diff --git a/test/build_examples.zig b/test/build_examples.zig index 66a6ecda17..c8a47bb093 100644 --- a/test/build_examples.zig +++ b/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");