authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 14:46:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-29 14:48:12-07:00
log0da7c4b0c8a2a2fe0862f7757bc5976342d51dc8
treea009c84f49be7b52e13964014222cb960915d136
parent7c0ee423859739b5484de8de867006ead787fb66

improve stage2 COFF LLD linking

* change some {} to be {s} to gain type safety * fix libraries being libfoo.lib instead of foo.lib for COFF * when linking mingw-w64, add the "always link" libs so that we generate DLL import .lib files for them as the linker code relies on. * COFF LLD linker does not support -r so we do a file copy as an alternative to the -r thing that ELF linking does. I will file an issue for the corresponding TODO upon merging this branch, to look into an optimization that possibly elides this copy when the source and destination are both cache directories. * add a CLI error message when trying to link multiple objects into one and using COFF object format.

5 files changed, 282 insertions(+), 253 deletions(-)

lib/std/zig.zig+13-13
......@@ -84,36 +84,36 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
8484 .uefi => ".efi",
8585 else => ".exe",
8686 };
87 return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, suffix });
87 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });
8888 },
8989 .Lib => {
9090 const suffix = switch (options.link_mode orelse .Static) {
9191 .Static => ".lib",
9292 .Dynamic => ".dll",
9393 };
94 return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
94 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });
9595 },
96 .Obj => return std.fmt.allocPrint(allocator, "{}{}", .{ root_name, target.abi.oFileExt() }),
96 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.abi.oFileExt() }),
9797 },
9898 .elf => switch (options.output_mode) {
9999 .Exe => return allocator.dupe(u8, root_name),
100100 .Lib => {
101101 switch (options.link_mode orelse .Static) {
102 .Static => return std.fmt.allocPrint(allocator, "{}{}.a", .{
102 .Static => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
103103 target.libPrefix(), root_name,
104104 }),
105105 .Dynamic => {
106106 if (options.version) |ver| {
107 return std.fmt.allocPrint(allocator, "{}{}.so.{}.{}.{}", .{
107 return std.fmt.allocPrint(allocator, "{s}{s}.so.{d}.{d}.{d}", .{
108108 target.libPrefix(), root_name, ver.major, ver.minor, ver.patch,
109109 });
110110 } else {
111 return std.fmt.allocPrint(allocator, "{}{}.so", .{ target.libPrefix(), root_name });
111 return std.fmt.allocPrint(allocator, "{s}{s}.so", .{ target.libPrefix(), root_name });
112112 }
113113 },
114114 }
115115 },
116 .Obj => return std.fmt.allocPrint(allocator, "{}.o", .{root_name}),
116 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
117117 },
118118 .macho => switch (options.output_mode) {
119119 .Exe => return allocator.dupe(u8, root_name),
......@@ -122,14 +122,14 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
122122 .Static => ".a",
123123 .Dynamic => ".dylib",
124124 };
125 return std.fmt.allocPrint(allocator, "{}{}{}", .{ target.libPrefix(), root_name, suffix });
125 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });
126126 },
127 .Obj => return std.fmt.allocPrint(allocator, "{}.o", .{root_name}),
127 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
128128 },
129 .wasm => return std.fmt.allocPrint(allocator, "{}.wasm", .{root_name}),
130 .c => return std.fmt.allocPrint(allocator, "{}.c", .{root_name}),
131 .hex => return std.fmt.allocPrint(allocator, "{}.ihex", .{root_name}),
132 .raw => return std.fmt.allocPrint(allocator, "{}.bin", .{root_name}),
129 .wasm => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),
130 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),
131 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
132 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
133133 }
134134}
135135
src/Compilation.zig+5
......@@ -879,6 +879,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
879879 try comp.work_queue.ensureUnusedCapacity(static_lib_jobs.len + 1);
880880 comp.work_queue.writeAssumeCapacity(&static_lib_jobs);
881881 comp.work_queue.writeItemAssumeCapacity(crt_job);
882
883 // When linking mingw-w64 there are some import libs we always need.
884 for (mingw.always_link_libs) |name| {
885 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});
886 }
882887 }
883888 // Generate Windows import libs.
884889 if (comp.getTarget().os.tag == .windows) {
src/link.zig+1-1
......@@ -321,7 +321,7 @@ pub const File = struct {
321321 // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
322322 // Until then, we do `lld -r -o output.o input.o` even though the output is the same
323323 // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file
324 // to the final location.
324 // to the final location. See also the corresponding TODO in Coff linking.
325325 const full_out_path = try emit.directory.join(comp.gpa, &[_][]const u8{emit.sub_path});
326326 defer comp.gpa.free(full_out_path);
327327 assert(comp.c_object_table.count() == 1);
src/link/Coff.zig+252-237
......@@ -873,287 +873,302 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
873873 };
874874 }
875875
876 const is_obj = self.base.options.output_mode == .Obj;
877
878 // Create an LLD command line and invoke it.
879 var argv = std.ArrayList([]const u8).init(self.base.allocator);
880 defer argv.deinit();
881 // Even though we're calling LLD as a library it thinks the first argument is its own exe name.
882 try argv.append("lld");
883 if (is_obj) {
884 try argv.append("-r");
885 }
876 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
886877
887 try argv.append("-ERRORLIMIT:0");
888 try argv.append("-NOLOGO");
889 if (!self.base.options.strip) {
890 try argv.append("-DEBUG");
891 }
892 if (self.base.options.output_mode == .Exe) {
893 const stack_size = self.base.options.stack_size_override orelse 16777216;
894 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
895 }
878 if (self.base.options.output_mode == .Obj) {
879 // LLD's COFF driver does not support the equvialent of `-r` so we do a simple file copy
880 // here. TODO: think carefully about how we can avoid this redundant operation when doing
881 // build-obj. See also the corresponding TODO in linkAsArchive.
882 const the_object_path = blk: {
883 if (self.base.options.objects.len != 0)
884 break :blk self.base.options.objects[0];
896885
897 if (target.cpu.arch == .i386) {
898 try argv.append("-MACHINE:X86");
899 } else if (target.cpu.arch == .x86_64) {
900 try argv.append("-MACHINE:X64");
901 } else if (target.cpu.arch.isARM()) {
902 if (target.cpu.arch.ptrBitWidth() == 32) {
903 try argv.append("-MACHINE:ARM");
904 } else {
905 try argv.append("-MACHINE:ARM64");
886 if (comp.c_object_table.count() != 0)
887 break :blk comp.c_object_table.items()[0].key.status.success.object_path;
888
889 if (module_obj_path) |p|
890 break :blk p;
891
892 // TODO I think this is unreachable. Audit this situation when solving the above TODO
893 // regarding eliding redundant object -> object transformations.
894 return error.NoObjectsToLink;
895 };
896 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
897 } else {
898 // Create an LLD command line and invoke it.
899 var argv = std.ArrayList([]const u8).init(self.base.allocator);
900 defer argv.deinit();
901 // Even though we're calling LLD as a library it thinks the first argument is its own exe name.
902 try argv.append("lld");
903
904 try argv.append("-ERRORLIMIT:0");
905 try argv.append("-NOLOGO");
906 if (!self.base.options.strip) {
907 try argv.append("-DEBUG");
908 }
909 if (self.base.options.output_mode == .Exe) {
910 const stack_size = self.base.options.stack_size_override orelse 16777216;
911 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
906912 }
907 }
908913
909 if (is_dyn_lib) {
910 try argv.append("-DLL");
911 }
914 if (target.cpu.arch == .i386) {
915 try argv.append("-MACHINE:X86");
916 } else if (target.cpu.arch == .x86_64) {
917 try argv.append("-MACHINE:X64");
918 } else if (target.cpu.arch.isARM()) {
919 if (target.cpu.arch.ptrBitWidth() == 32) {
920 try argv.append("-MACHINE:ARM");
921 } else {
922 try argv.append("-MACHINE:ARM64");
923 }
924 }
912925
913 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
914 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
926 if (is_dyn_lib) {
927 try argv.append("-DLL");
928 }
915929
916 if (self.base.options.link_libc) {
917 if (self.base.options.libc_installation) |libc_installation| {
918 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
930 try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
919931
920 if (target.abi == .msvc) {
921 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?}));
922 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?}));
932 if (self.base.options.link_libc) {
933 if (self.base.options.libc_installation) |libc_installation| {
934 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
935
936 if (target.abi == .msvc) {
937 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?}));
938 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?}));
939 }
923940 }
924941 }
925 }
926942
927 for (self.base.options.lib_dirs) |lib_dir| {
928 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir}));
929 }
943 for (self.base.options.lib_dirs) |lib_dir| {
944 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir}));
945 }
930946
931 try argv.appendSlice(self.base.options.objects);
947 try argv.appendSlice(self.base.options.objects);
932948
933 for (comp.c_object_table.items()) |entry| {
934 try argv.append(entry.key.status.success.object_path);
935 }
949 for (comp.c_object_table.items()) |entry| {
950 try argv.append(entry.key.status.success.object_path);
951 }
936952
937 if (module_obj_path) |p| {
938 try argv.append(p);
939 }
953 if (module_obj_path) |p| {
954 try argv.append(p);
955 }
940956
941 const resolved_subsystem: ?std.Target.SubSystem = blk: {
942 if (self.base.options.subsystem) |explicit| break :blk explicit;
943 switch (target.os.tag) {
944 .windows => {
945 if (self.base.options.module) |module| {
946 if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
947 break :blk null;
948 if (module.stage1_flags.have_c_main or self.base.options.is_test or
949 module.stage1_flags.have_winmain_crt_startup or
950 module.stage1_flags.have_wwinmain_crt_startup)
951 {
952 break :blk .Console;
957 const resolved_subsystem: ?std.Target.SubSystem = blk: {
958 if (self.base.options.subsystem) |explicit| break :blk explicit;
959 switch (target.os.tag) {
960 .windows => {
961 if (self.base.options.module) |module| {
962 if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
963 break :blk null;
964 if (module.stage1_flags.have_c_main or self.base.options.is_test or
965 module.stage1_flags.have_winmain_crt_startup or
966 module.stage1_flags.have_wwinmain_crt_startup)
967 {
968 break :blk .Console;
969 }
970 if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
971 break :blk .Windows;
953972 }
954 if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
955 break :blk .Windows;
956 }
957 },
958 .uefi => break :blk .EfiApplication,
959 else => {},
960 }
961 break :blk null;
962 };
963 const Mode = enum { uefi, win32 };
964 const mode: Mode = mode: {
965 if (resolved_subsystem) |subsystem| switch (subsystem) {
966 .Console => {
967 try argv.append("-SUBSYSTEM:console");
968 break :mode .win32;
969 },
970 .EfiApplication => {
971 try argv.append("-SUBSYSTEM:efi_application");
972 break :mode .uefi;
973 },
974 .EfiBootServiceDriver => {
975 try argv.append("-SUBSYSTEM:efi_boot_service_driver");
976 break :mode .uefi;
977 },
978 .EfiRom => {
979 try argv.append("-SUBSYSTEM:efi_rom");
980 break :mode .uefi;
981 },
982 .EfiRuntimeDriver => {
983 try argv.append("-SUBSYSTEM:efi_runtime_driver");
973 },
974 .uefi => break :blk .EfiApplication,
975 else => {},
976 }
977 break :blk null;
978 };
979 const Mode = enum { uefi, win32 };
980 const mode: Mode = mode: {
981 if (resolved_subsystem) |subsystem| switch (subsystem) {
982 .Console => {
983 try argv.append("-SUBSYSTEM:console");
984 break :mode .win32;
985 },
986 .EfiApplication => {
987 try argv.append("-SUBSYSTEM:efi_application");
988 break :mode .uefi;
989 },
990 .EfiBootServiceDriver => {
991 try argv.append("-SUBSYSTEM:efi_boot_service_driver");
992 break :mode .uefi;
993 },
994 .EfiRom => {
995 try argv.append("-SUBSYSTEM:efi_rom");
996 break :mode .uefi;
997 },
998 .EfiRuntimeDriver => {
999 try argv.append("-SUBSYSTEM:efi_runtime_driver");
1000 break :mode .uefi;
1001 },
1002 .Native => {
1003 try argv.append("-SUBSYSTEM:native");
1004 break :mode .win32;
1005 },
1006 .Posix => {
1007 try argv.append("-SUBSYSTEM:posix");
1008 break :mode .win32;
1009 },
1010 .Windows => {
1011 try argv.append("-SUBSYSTEM:windows");
1012 break :mode .win32;
1013 },
1014 } else if (target.os.tag == .uefi) {
9841015 break :mode .uefi;
985 },
986 .Native => {
987 try argv.append("-SUBSYSTEM:native");
988 break :mode .win32;
989 },
990 .Posix => {
991 try argv.append("-SUBSYSTEM:posix");
992 break :mode .win32;
993 },
994 .Windows => {
995 try argv.append("-SUBSYSTEM:windows");
1016 } else {
9961017 break :mode .win32;
997 },
998 } else if (target.os.tag == .uefi) {
999 break :mode .uefi;
1000 } else {
1001 break :mode .win32;
1002 }
1003 };
1018 }
1019 };
10041020
1005 switch (mode) {
1006 .uefi => try argv.appendSlice(&[_][]const u8{
1007 "-BASE:0",
1008 "-ENTRY:EfiMain",
1009 "-OPT:REF",
1010 "-SAFESEH:NO",
1011 "-MERGE:.rdata=.data",
1012 "-ALIGN:32",
1013 "-NODEFAULTLIB",
1014 "-SECTION:.xdata,D",
1015 }),
1016 .win32 => {
1017 if (link_in_crt) {
1018 if (target.abi.isGnu()) {
1019 try argv.append("-lldmingw");
1020
1021 if (target.cpu.arch == .i386) {
1022 try argv.append("-ALTERNATENAME:__image_base__=___ImageBase");
1023 } else {
1024 try argv.append("-ALTERNATENAME:__image_base__=__ImageBase");
1025 }
1021 switch (mode) {
1022 .uefi => try argv.appendSlice(&[_][]const u8{
1023 "-BASE:0",
1024 "-ENTRY:EfiMain",
1025 "-OPT:REF",
1026 "-SAFESEH:NO",
1027 "-MERGE:.rdata=.data",
1028 "-ALIGN:32",
1029 "-NODEFAULTLIB",
1030 "-SECTION:.xdata,D",
1031 }),
1032 .win32 => {
1033 if (link_in_crt) {
1034 if (target.abi.isGnu()) {
1035 try argv.append("-lldmingw");
1036
1037 if (target.cpu.arch == .i386) {
1038 try argv.append("-ALTERNATENAME:__image_base__=___ImageBase");
1039 } else {
1040 try argv.append("-ALTERNATENAME:__image_base__=__ImageBase");
1041 }
10261042
1027 if (is_dyn_lib) {
1028 try argv.append(try comp.get_libc_crt_file(arena, "dllcrt2.o"));
1029 } else {
1030 try argv.append(try comp.get_libc_crt_file(arena, "crt2.o"));
1031 }
1043 if (is_dyn_lib) {
1044 try argv.append(try comp.get_libc_crt_file(arena, "dllcrt2.o"));
1045 } else {
1046 try argv.append(try comp.get_libc_crt_file(arena, "crt2.o"));
1047 }
10321048
1033 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));
1034 try argv.append(try comp.get_libc_crt_file(arena, "mingwex.lib"));
1035 try argv.append(try comp.get_libc_crt_file(arena, "msvcrt-os.lib"));
1049 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));
1050 try argv.append(try comp.get_libc_crt_file(arena, "mingwex.lib"));
1051 try argv.append(try comp.get_libc_crt_file(arena, "msvcrt-os.lib"));
10361052
1037 for (mingw.always_link_libs) |name| {
1038 if (!self.base.options.system_libs.contains(name)) {
1039 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});
1040 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));
1053 for (mingw.always_link_libs) |name| {
1054 if (!self.base.options.system_libs.contains(name)) {
1055 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});
1056 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));
1057 }
1058 }
1059 } else {
1060 const lib_str = switch (self.base.options.link_mode) {
1061 .Dynamic => "",
1062 .Static => "lib",
1063 };
1064 const d_str = switch (self.base.options.optimize_mode) {
1065 .Debug => "d",
1066 else => "",
1067 };
1068 switch (self.base.options.link_mode) {
1069 .Static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})),
1070 .Dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})),
10411071 }
1042 }
1043 } else {
1044 const lib_str = switch (self.base.options.link_mode) {
1045 .Dynamic => "",
1046 .Static => "lib",
1047 };
1048 const d_str = switch (self.base.options.optimize_mode) {
1049 .Debug => "d",
1050 else => "",
1051 };
1052 switch (self.base.options.link_mode) {
1053 .Static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})),
1054 .Dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})),
1055 }
10561072
1057 try argv.append(try allocPrint(arena, "{s}vcruntime{s}.lib", .{ lib_str, d_str }));
1058 try argv.append(try allocPrint(arena, "{s}ucrt{s}.lib", .{ lib_str, d_str }));
1073 try argv.append(try allocPrint(arena, "{s}vcruntime{s}.lib", .{ lib_str, d_str }));
1074 try argv.append(try allocPrint(arena, "{s}ucrt{s}.lib", .{ lib_str, d_str }));
10591075
1060 //Visual C++ 2015 Conformance Changes
1061 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
1062 try argv.append("legacy_stdio_definitions.lib");
1076 //Visual C++ 2015 Conformance Changes
1077 //https://msdn.microsoft.com/en-us/library/bb531344.aspx
1078 try argv.append("legacy_stdio_definitions.lib");
10631079
1064 // msvcrt depends on kernel32 and ntdll
1065 try argv.append("kernel32.lib");
1066 try argv.append("ntdll.lib");
1067 }
1068 } else {
1069 try argv.append("-NODEFAULTLIB");
1070 if (!is_lib) {
1071 if (self.base.options.module) |module| {
1072 if (module.stage1_flags.have_winmain) {
1073 try argv.append("-ENTRY:WinMain");
1074 } else if (module.stage1_flags.have_wwinmain) {
1075 try argv.append("-ENTRY:wWinMain");
1076 } else if (module.stage1_flags.have_wwinmain_crt_startup) {
1077 try argv.append("-ENTRY:wWinMainCRTStartup");
1080 // msvcrt depends on kernel32 and ntdll
1081 try argv.append("kernel32.lib");
1082 try argv.append("ntdll.lib");
1083 }
1084 } else {
1085 try argv.append("-NODEFAULTLIB");
1086 if (!is_lib) {
1087 if (self.base.options.module) |module| {
1088 if (module.stage1_flags.have_winmain) {
1089 try argv.append("-ENTRY:WinMain");
1090 } else if (module.stage1_flags.have_wwinmain) {
1091 try argv.append("-ENTRY:wWinMain");
1092 } else if (module.stage1_flags.have_wwinmain_crt_startup) {
1093 try argv.append("-ENTRY:wWinMainCRTStartup");
1094 } else {
1095 try argv.append("-ENTRY:WinMainCRTStartup");
1096 }
10781097 } else {
10791098 try argv.append("-ENTRY:WinMainCRTStartup");
10801099 }
1081 } else {
1082 try argv.append("-ENTRY:WinMainCRTStartup");
10831100 }
10841101 }
1085 }
1086 },
1087 }
1102 },
1103 }
10881104
1089 if (!is_obj) {
10901105 // libc++ dep
10911106 if (self.base.options.link_libcpp) {
10921107 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
10931108 try argv.append(comp.libcxx_static_lib.?.full_object_path);
10941109 try argv.append(comp.libunwind_static_lib.?.full_object_path);
10951110 }
1096 }
10971111
1098 // compiler-rt and libc
1099 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
1100 if (!self.base.options.link_libc) {
1101 try argv.append(comp.libc_static_lib.?.full_object_path);
1112 // compiler-rt and libc
1113 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
1114 if (!self.base.options.link_libc) {
1115 try argv.append(comp.libc_static_lib.?.full_object_path);
1116 }
1117 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
1118 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
1119 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
11021120 }
1103 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
1104 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
1105 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
1106 }
11071121
1108 for (self.base.options.system_libs.items()) |entry| {
1109 const lib_basename = try allocPrint(arena, "{s}.lib", .{entry.key});
1110 if (comp.crt_files.get(lib_basename)) |crt_file| {
1111 try argv.append(crt_file.full_object_path);
1112 } else {
1113 try argv.append(lib_basename);
1122 for (self.base.options.system_libs.items()) |entry| {
1123 const lib_basename = try allocPrint(arena, "{s}.lib", .{entry.key});
1124 if (comp.crt_files.get(lib_basename)) |crt_file| {
1125 try argv.append(crt_file.full_object_path);
1126 } else {
1127 try argv.append(lib_basename);
1128 }
11141129 }
1115 }
11161130
1117 if (self.base.options.verbose_link) {
1118 Compilation.dump_argv(argv.items);
1119 }
1131 if (self.base.options.verbose_link) {
1132 Compilation.dump_argv(argv.items);
1133 }
11201134
1121 const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
1122 for (argv.items) |arg, i| {
1123 new_argv[i] = try arena.dupeZ(u8, arg);
1124 }
1135 const new_argv = try arena.allocSentinel(?[*:0]const u8, argv.items.len, null);
1136 for (argv.items) |arg, i| {
1137 new_argv[i] = try arena.dupeZ(u8, arg);
1138 }
11251139
1126 var stderr_context: LLDContext = .{
1127 .coff = self,
1128 .data = std.ArrayList(u8).init(self.base.allocator),
1129 };
1130 defer stderr_context.data.deinit();
1131 var stdout_context: LLDContext = .{
1132 .coff = self,
1133 .data = std.ArrayList(u8).init(self.base.allocator),
1134 };
1135 defer stdout_context.data.deinit();
1136 const llvm = @import("../llvm.zig");
1137 const ok = llvm.Link(
1138 .COFF,
1139 new_argv.ptr,
1140 new_argv.len,
1141 append_diagnostic,
1142 @ptrToInt(&stdout_context),
1143 @ptrToInt(&stderr_context),
1144 );
1145 if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
1146 if (stdout_context.data.items.len != 0) {
1147 std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
1148 }
1149 if (!ok) {
1150 // TODO parse this output and surface with the Compilation API rather than
1151 // directly outputting to stderr here.
1152 std.debug.print("{}", .{stderr_context.data.items});
1153 return error.LLDReportedFailure;
1154 }
1155 if (stderr_context.data.items.len != 0) {
1156 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
1140 var stderr_context: LLDContext = .{
1141 .coff = self,
1142 .data = std.ArrayList(u8).init(self.base.allocator),
1143 };
1144 defer stderr_context.data.deinit();
1145 var stdout_context: LLDContext = .{
1146 .coff = self,
1147 .data = std.ArrayList(u8).init(self.base.allocator),
1148 };
1149 defer stdout_context.data.deinit();
1150 const llvm = @import("../llvm.zig");
1151 const ok = llvm.Link(
1152 .COFF,
1153 new_argv.ptr,
1154 new_argv.len,
1155 append_diagnostic,
1156 @ptrToInt(&stdout_context),
1157 @ptrToInt(&stderr_context),
1158 );
1159 if (stderr_context.oom or stdout_context.oom) return error.OutOfMemory;
1160 if (stdout_context.data.items.len != 0) {
1161 std.log.warn("unexpected LLD stdout: {}", .{stdout_context.data.items});
1162 }
1163 if (!ok) {
1164 // TODO parse this output and surface with the Compilation API rather than
1165 // directly outputting to stderr here.
1166 std.debug.print("{}", .{stderr_context.data.items});
1167 return error.LLDReportedFailure;
1168 }
1169 if (stderr_context.data.items.len != 0) {
1170 std.log.warn("unexpected LLD stderr: {}", .{stderr_context.data.items});
1171 }
11571172 }
11581173
11591174 if (!self.base.options.disable_lld_caching) {
src/main.zig+11-2
......@@ -1314,8 +1314,8 @@ fn buildOutputType(
13141314 }
13151315 }
13161316
1317 const object_format: ?std.Target.ObjectFormat = blk: {
1318 const ofmt = target_ofmt orelse break :blk null;
1317 const object_format: std.Target.ObjectFormat = blk: {
1318 const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
13191319 if (mem.eql(u8, ofmt, "elf")) {
13201320 break :blk .elf;
13211321 } else if (mem.eql(u8, ofmt, "c")) {
......@@ -1337,6 +1337,15 @@ fn buildOutputType(
13371337 }
13381338 };
13391339
1340 if (output_mode == .Obj and object_format == .coff) {
1341 const total_obj_count = c_source_files.items.len +
1342 @boolToInt(root_src_file != null) +
1343 link_objects.items.len;
1344 if (total_obj_count > 1) {
1345 fatal("COFF does not support linking multiple objects into one", .{});
1346 }
1347 }
1348
13401349 var cleanup_emit_bin_dir: ?fs.Dir = null;
13411350 defer if (cleanup_emit_bin_dir) |*dir| dir.close();
13421351