authorgravatar for kkartaltepe@gmail.comKurt Kartaltepe <kkartaltepe@gmail.com> 2021-07-09 20:41:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-24 17:14:20-07:00
loga950cb42bdf7b3f339071868c6675e7dcc892bae
treeddf75e85213e2b1ea0d8accb78471b6d25d01b60
parentfdcac5ecbd324170f7281f6704ead18b7d904e72

Coff linker: Add IMPLIB support

Allow --out-implib and -implib as passed by cmake and meson to be correctly passed through to the linker to generate import libraries.

4 files changed, 40 insertions(+), 1 deletions(-)

src/Compilation.zig+5-1
...@@ -767,6 +767,8 @@ pub const InitOptions = struct {...@@ -767,6 +767,8 @@ pub const InitOptions = struct {
767 test_filter: ?[]const u8 = null,767 test_filter: ?[]const u8 = null,
768 test_name_prefix: ?[]const u8 = null,768 test_name_prefix: ?[]const u8 = null,
769 subsystem: ?std.Target.SubSystem = null,769 subsystem: ?std.Target.SubSystem = null,
770 /// Windows/PE only. Where to output the import library, can contain directories.
771 out_implib: ?[]const u8 = null,
770 /// WASI-only. Type of WASI execution model ("command" or "reactor").772 /// WASI-only. Type of WASI execution model ("command" or "reactor").
771 wasi_exec_model: ?std.builtin.WasiExecModel = null,773 wasi_exec_model: ?std.builtin.WasiExecModel = null,
772 /// (Zig compiler development) Enable dumping linker's state as JSON.774 /// (Zig compiler development) Enable dumping linker's state as JSON.
...@@ -946,7 +948,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -946,7 +948,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
946 options.output_mode == .Lib or948 options.output_mode == .Lib or
947 options.lld_argv.len != 0 or949 options.lld_argv.len != 0 or
948 options.image_base_override != null or950 options.image_base_override != null or
949 options.linker_script != null or options.version_script != null)951 options.linker_script != null or options.version_script != null or
952 options.out_implib != null)
950 {953 {
951 break :blk true;954 break :blk true;
952 }955 }
...@@ -1461,6 +1464,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1461,6 +1464,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1461 .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os,1464 .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os,
1462 .disable_lld_caching = options.disable_lld_caching,1465 .disable_lld_caching = options.disable_lld_caching,
1463 .subsystem = options.subsystem,1466 .subsystem = options.subsystem,
1467 .out_implib = options.out_implib,
1464 .is_test = options.is_test,1468 .is_test = options.is_test,
1465 .wasi_exec_model = wasi_exec_model,1469 .wasi_exec_model = wasi_exec_model,
1466 .use_stage1 = use_stage1,1470 .use_stage1 = use_stage1,
src/link.zig+1
...@@ -127,6 +127,7 @@ pub const Options = struct {...@@ -127,6 +127,7 @@ pub const Options = struct {
127 gc_sections: ?bool = null,127 gc_sections: ?bool = null,
128 allow_shlib_undefined: ?bool,128 allow_shlib_undefined: ?bool,
129 subsystem: ?std.Target.SubSystem,129 subsystem: ?std.Target.SubSystem,
130 out_implib: ?[]const u8,
130 linker_script: ?[]const u8,131 linker_script: ?[]const u8,
131 version_script: ?[]const u8,132 version_script: ?[]const u8,
132 soname: ?[]const u8,133 soname: ?[]const u8,
src/link/Coff.zig+5
...@@ -948,6 +948,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {...@@ -948,6 +948,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
948 man.hash.add(self.base.options.dynamicbase);948 man.hash.add(self.base.options.dynamicbase);
949 man.hash.addOptional(self.base.options.major_subsystem_version);949 man.hash.addOptional(self.base.options.major_subsystem_version);
950 man.hash.addOptional(self.base.options.minor_subsystem_version);950 man.hash.addOptional(self.base.options.minor_subsystem_version);
951 man.hash.addOptionalBytes(self.base.options.out_implib);
951952
952 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.953 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
953 _ = try man.hit();954 _ = try man.hit();
...@@ -1094,6 +1095,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {...@@ -1094,6 +1095,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
1094 try argv.append(p);1095 try argv.append(p);
1095 }1096 }
10961097
1098 if (self.base.options.out_implib != null) {
1099 try argv.append(try allocPrint(arena, "-IMPLIB:{s}.lib", .{full_out_path}));
1100 }
1101
1097 const resolved_subsystem: ?std.Target.SubSystem = blk: {1102 const resolved_subsystem: ?std.Target.SubSystem = blk: {
1098 if (self.base.options.subsystem) |explicit| break :blk explicit;1103 if (self.base.options.subsystem) |explicit| break :blk explicit;
1099 switch (target.os.tag) {1104 switch (target.os.tag) {
src/main.zig+29
...@@ -654,6 +654,7 @@ fn buildOutputType(...@@ -654,6 +654,7 @@ fn buildOutputType(
654 var main_pkg_path: ?[]const u8 = null;654 var main_pkg_path: ?[]const u8 = null;
655 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;655 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
656 var subsystem: ?std.Target.SubSystem = null;656 var subsystem: ?std.Target.SubSystem = null;
657 var out_implib: ?[]const u8 = null;
657 var major_subsystem_version: ?u32 = null;658 var major_subsystem_version: ?u32 = null;
658 var minor_subsystem_version: ?u32 = null;659 var minor_subsystem_version: ?u32 = null;
659 var wasi_exec_model: ?std.builtin.WasiExecModel = null;660 var wasi_exec_model: ?std.builtin.WasiExecModel = null;
...@@ -1637,6 +1638,14 @@ fn buildOutputType(...@@ -1637,6 +1638,14 @@ fn buildOutputType(
1637 fatal("unable to parse -current_version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });1638 fatal("unable to parse -current_version '{s}': {s}", .{ linker_args.items[i], @errorName(err) });
1638 };1639 };
1639 have_version = true;1640 have_version = true;
1641 } else if (mem.eql(u8, arg, "--out-implib") or
1642 mem.eql(u8, arg, "-implib"))
1643 {
1644 i += 1;
1645 if (i >= linker_args.items.len) {
1646 fatal("expected linker arg after '{s}'", .{arg});
1647 }
1648 out_implib = linker_args.items[i];
1640 } else {1649 } else {
1641 warn("unsupported linker arg: {s}", .{arg});1650 warn("unsupported linker arg: {s}", .{arg});
1642 }1651 }
...@@ -2154,6 +2163,16 @@ fn buildOutputType(...@@ -2154,6 +2163,16 @@ fn buildOutputType(
2154 else => false,2163 else => false,
2155 };2164 };
21562165
2166 // Always output import libraries (.lib) when building for msvc to replicate
2167 // `link` behavior. lld does not always output import libraries so on the
2168 // gnu abi users must set out_implib.
2169 if (output_mode == .Lib and emit_bin == .yes and target_info.target.abi == .msvc and out_implib == null) {
2170 const emit_bin_ext = fs.path.extension(emit_bin.yes);
2171 out_implib = try std.fmt.allocPrint(gpa, "{s}.lib", .{
2172 emit_bin.yes[0 .. emit_bin.yes.len - emit_bin_ext.len],
2173 });
2174 }
2175
2157 gimmeMoreOfThoseSweetSweetFileDescriptors();2176 gimmeMoreOfThoseSweetSweetFileDescriptors();
21582177
2159 const comp = Compilation.create(gpa, .{2178 const comp = Compilation.create(gpa, .{
...@@ -2263,6 +2282,7 @@ fn buildOutputType(...@@ -2263,6 +2282,7 @@ fn buildOutputType(
2263 .test_name_prefix = test_name_prefix,2282 .test_name_prefix = test_name_prefix,
2264 .disable_lld_caching = !have_enable_cache,2283 .disable_lld_caching = !have_enable_cache,
2265 .subsystem = subsystem,2284 .subsystem = subsystem,
2285 .out_implib = out_implib,
2266 .wasi_exec_model = wasi_exec_model,2286 .wasi_exec_model = wasi_exec_model,
2267 .debug_compile_errors = debug_compile_errors,2287 .debug_compile_errors = debug_compile_errors,
2268 .enable_link_snapshots = enable_link_snapshots,2288 .enable_link_snapshots = enable_link_snapshots,
...@@ -2661,6 +2681,15 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2661,6 +2681,15 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
26612681
2662 _ = try cache_dir.updateFile(src_pdb_path, cwd, dst_pdb_path, .{});2682 _ = try cache_dir.updateFile(src_pdb_path, cwd, dst_pdb_path, .{});
2663 }2683 }
2684
2685 if (comp.bin_file.options.out_implib) |out_implib| {
2686 const src_implib_path = try std.fmt.allocPrint(gpa, "{s}.lib", .{bin_sub_path});
2687 defer gpa.free(src_implib_path);
2688 if (std.fs.path.dirname(out_implib)) |implib_dir| {
2689 try cwd.makePath(implib_dir);
2690 }
2691 _ = try cache_dir.updateFile(src_implib_path, cwd, out_implib, .{});
2692 }
2664 },2693 },
2665 }2694 }
2666}2695}