authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-05 17:26:32-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-05 17:26:32-07:00
logc28c38d1e5648a45e8b3b2edbd1c732edb8d2642
tree9e151a988b4196a57fe51cd34515cbe1090cc6a2
parent301a89849b1f80afb01bebf1288afd767aea7122
parent25e6187d28813c0f5227095b927374d901c6004b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13514 from kcbanner/windows_build_fixes

Windows: Support building stage3, and bootstrapping via MSVC

7 files changed, 109 insertions(+), 24 deletions(-)

CMakeLists.txt+20-15
......@@ -89,9 +89,9 @@ endif()
8989
9090set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
9191set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")
92set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
93set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib")
94set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd")
92set(ZIG_STATIC_LLVM ${ZIG_STATIC} CACHE BOOL "Prefer linking against static LLVM libraries")
93set(ZIG_STATIC_ZLIB ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zlib")
94set(ZIG_STATIC_ZSTD ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zstd")
9595set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache")
9696
9797if(ZIG_USE_CCACHE)
......@@ -103,12 +103,6 @@ if(ZIG_USE_CCACHE)
103103 endif()
104104endif()
105105
106if(ZIG_STATIC)
107 set(ZIG_STATIC_LLVM ON)
108 set(ZIG_STATIC_ZLIB ON)
109 set(ZIG_STATIC_ZSTD ON)
110endif()
111
112106if (ZIG_SHARED_LLVM AND ZIG_STATIC_LLVM)
113107 message(SEND_ERROR "-DZIG_SHARED_LLVM and -DZIG_STATIC_LLVM cannot both be enabled simultaneously")
114108endif()
......@@ -138,13 +132,23 @@ find_package(clang 15)
138132find_package(lld 15)
139133
140134if(ZIG_STATIC_ZLIB)
141 list(REMOVE_ITEM LLVM_LIBRARIES "-lz")
135 if (MSVC)
136 list(REMOVE_ITEM LLVM_LIBRARIES "z.lib")
137 else()
138 list(REMOVE_ITEM LLVM_LIBRARIES "-lz")
139 endif()
140
142141 find_library(ZLIB NAMES libz.a libzlibstatic.a z zlib libz NAMES_PER_DIR)
143142 list(APPEND LLVM_LIBRARIES "${ZLIB}")
144143endif()
145144
146145if(ZIG_STATIC_ZSTD)
147 list(REMOVE_ITEM LLVM_LIBRARIES "-lzstd")
146 if (MSVC)
147 list(REMOVE_ITEM LLVM_LIBRARIES "zstd.lib")
148 else()
149 list(REMOVE_ITEM LLVM_LIBRARIES "-lzstd")
150 endif()
151
148152 find_library(ZSTD NAMES libzstd.a libzstdstatic.a zstd NAMES_PER_DIR)
149153 list(APPEND LLVM_LIBRARIES "${ZSTD}")
150154endif()
......@@ -168,6 +172,7 @@ foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
168172 string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE)
169173 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR})
170174 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR})
175 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${CMAKE_BINARY_DIR})
171176endforeach(CONFIG_TYPE CMAKE_CONFIGURATION_TYPES)
172177
173178include_directories(${LLVM_INCLUDE_DIRS})
......@@ -722,9 +727,9 @@ set(HOST_TARGET_TRIPLE "${HOST_TARGET_ARCH}-${HOST_TARGET_OS}")
722727
723728if(MSVC)
724729 set(ZIG_WASM2C_COMPILE_FLAGS "")
725 set(ZIG1_COMPILE_FLAGS "/std:c99 /Os")
726 set(ZIG2_COMPILE_FLAGS "/std:c99 /O0")
727 set(ZIG2_LINK_FLAGS "/STACK:16777216")
730 set(ZIG1_COMPILE_FLAGS "/Os")
731 set(ZIG2_COMPILE_FLAGS "/Od")
732 set(ZIG2_LINK_FLAGS "/STACK:16777216 /FORCE:MULTIPLE")
728733else()
729734 set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
730735 set(ZIG1_COMPILE_FLAGS "-std=c99 -Os")
......@@ -838,7 +843,7 @@ if(ZIG_SINGLE_THREADED)
838843else()
839844 set(ZIG_SINGLE_THREADED_ARG "")
840845endif()
841if(ZIG_STATIC)
846if(ZIG_STATIC AND NOT MSVC)
842847 set(ZIG_STATIC_ARG "-Duse-zig-libcxx")
843848else()
844849 set(ZIG_STATIC_ARG "")
build.zig+12-2
......@@ -628,8 +628,16 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
628628 exe.linkSystemLibrary("z");
629629 exe.linkSystemLibrary("zstd");
630630
631 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
632 exe.linkSystemLibrary("c++");
631 if (exe.target.getOs().tag != .windows or exe.target.getAbi() != .msvc) {
632 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
633 exe.linkSystemLibrary("c++");
634 }
635
636 if (exe.target.getOs().tag == .windows) {
637 exe.linkSystemLibrary("version");
638 exe.linkSystemLibrary("uuid");
639 exe.linkSystemLibrary("ole32");
640 }
633641}
634642
635643fn addCxxKnownPath(
......@@ -673,6 +681,8 @@ fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
673681 while (it.next()) |lib| {
674682 if (mem.startsWith(u8, lib, "-l")) {
675683 exe.linkSystemLibrary(lib["-l".len..]);
684 } else if (exe.target.isWindows() and mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) {
685 exe.linkSystemLibrary(lib[0 .. lib.len - ".lib".len]);
676686 } else {
677687 exe.addObjectFile(lib);
678688 }
cmake/Findclang.cmake+4
......@@ -68,6 +68,10 @@ else()
6868 FIND_AND_ADD_CLANG_LIB(clangSupport)
6969endif()
7070
71if (MSVC)
72 set(CLANG_LIBRARIES ${CLANG_LIBRARIES} "version.lib")
73endif()
74
7175include(FindPackageHandleStandardArgs)
7276find_package_handle_standard_args(clang DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)
7377
src/Compilation.zig+16-3
......@@ -984,6 +984,7 @@ pub const InitOptions = struct {
984984 linker_dynamicbase: bool = false,
985985 linker_optimization: ?u8 = null,
986986 linker_compress_debug_sections: ?link.CompressDebugSections = null,
987 linker_module_definition_file: ?[]const u8 = null,
987988 major_subsystem_version: ?u32 = null,
988989 minor_subsystem_version: ?u32 = null,
989990 clang_passthrough_mode: bool = false,
......@@ -1041,6 +1042,11 @@ pub const InitOptions = struct {
10411042 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
10421043 dead_strip_dylibs: bool = false,
10431044 libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
1045 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
1046 /// paths when consolidating CodeView streams into a single PDB file.
1047 pdb_source_path: ?[]const u8 = null,
1048 /// (Windows) PDB output path
1049 pdb_out_path: ?[]const u8 = null,
10441050};
10451051
10461052fn addPackageTableToCacheHash(
......@@ -1815,6 +1821,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18151821 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
18161822 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
18171823 .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
1824 .module_definition_file = options.linker_module_definition_file,
18181825 .import_memory = options.linker_import_memory orelse false,
18191826 .import_symbols = options.linker_import_symbols,
18201827 .import_table = options.linker_import_table,
......@@ -1890,6 +1897,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18901897 .headerpad_max_install_names = options.headerpad_max_install_names,
18911898 .dead_strip_dylibs = options.dead_strip_dylibs,
18921899 .force_undefined_symbols = .{},
1900 .pdb_source_path = options.pdb_source_path,
1901 .pdb_out_path = options.pdb_out_path,
18931902 });
18941903 errdefer bin_file.destroy();
18951904 comp.* = .{
......@@ -3297,8 +3306,8 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
32973306 // TODO Surface more error details.
32983307 comp.lockAndSetMiscFailure(
32993308 .windows_import_lib,
3300 "unable to generate DLL import .lib file: {s}",
3301 .{@errorName(err)},
3309 "unable to generate DLL import .lib file for {s}: {s}",
3310 .{ link_lib, @errorName(err) },
33023311 );
33033312 };
33043313 },
......@@ -4379,7 +4388,7 @@ pub fn addCCArgs(
43794388 try argv.append("-fno-unwind-tables");
43804389 }
43814390 },
4382 .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {},
4391 .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig => {},
43834392 .assembly => {
43844393 // The Clang assembler does not accept the list of CPU features like the
43854394 // compiler frontend does. Therefore we must hard-code the -m flags for
......@@ -4524,6 +4533,7 @@ pub const FileExt = enum {
45244533 object,
45254534 static_library,
45264535 zig,
4536 def,
45274537 unknown,
45284538
45294539 pub fn clangSupportsDepFile(ext: FileExt) bool {
......@@ -4537,6 +4547,7 @@ pub const FileExt = enum {
45374547 .object,
45384548 .static_library,
45394549 .zig,
4550 .def,
45404551 .unknown,
45414552 => false,
45424553 };
......@@ -4629,6 +4640,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
46294640 return .object;
46304641 } else if (mem.endsWith(u8, filename, ".cu")) {
46314642 return .cu;
4643 } else if (mem.endsWith(u8, filename, ".def")) {
4644 return .def;
46324645 } else {
46334646 return .unknown;
46344647 }
src/link.zig+10
......@@ -219,6 +219,16 @@ pub const Options = struct {
219219 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
220220 dead_strip_dylibs: bool = false,
221221
222 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
223 /// paths when consolidating CodeView streams into a single PDB file.
224 pdb_source_path: ?[]const u8 = null,
225
226 /// (Windows) PDB output path
227 pdb_out_path: ?[]const u8 = null,
228
229 /// (Windows) .def file to specify when linking
230 module_definition_file: ?[]const u8 = null,
231
222232 pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
223233 return if (options.use_lld) .Obj else options.output_mode;
224234 }
src/link/Coff/lld.zig+17-2
......@@ -98,6 +98,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
9898 // strip does not need to go into the linker hash because it is part of the hash namespace
9999 man.hash.addOptional(self.base.options.major_subsystem_version);
100100 man.hash.addOptional(self.base.options.minor_subsystem_version);
101 man.hash.addOptional(self.base.options.version);
102 try man.addOptionalFile(self.base.options.module_definition_file);
101103
102104 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
103105 _ = try man.hit();
......@@ -166,12 +168,16 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
166168 try argv.append("-DEBUG");
167169
168170 const out_ext = std.fs.path.extension(full_out_path);
169 const out_pdb = try allocPrint(arena, "{s}.pdb", .{
171 const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
170172 full_out_path[0 .. full_out_path.len - out_ext.len],
171173 });
174
172175 try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb}));
173176 try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb}));
174177 }
178 if (self.base.options.version) |version| {
179 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
180 }
175181 if (self.base.options.lto) {
176182 switch (self.base.options.optimize_mode) {
177183 .Debug => {},
......@@ -260,6 +266,10 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
260266 try argv.append(p);
261267 }
262268
269 if (self.base.options.module_definition_file) |def| {
270 try argv.append(try allocPrint(arena, "-DEF:{s}", .{def}));
271 }
272
263273 const resolved_subsystem: ?std.Target.SubSystem = blk: {
264274 if (self.base.options.subsystem) |explicit| break :blk explicit;
265275 switch (target.os.tag) {
......@@ -423,7 +433,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
423433 }
424434 } else {
425435 try argv.append("-NODEFAULTLIB");
426 if (!is_lib) {
436 if (!is_lib and self.base.options.entry == null) {
427437 if (self.base.options.module) |module| {
428438 if (module.stage1_flags.have_winmain_crt_startup) {
429439 try argv.append("-ENTRY:WinMainCRTStartup");
......@@ -486,6 +496,11 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
486496 continue;
487497 }
488498 }
499 if (target.abi == .msvc) {
500 argv.appendAssumeCapacity(lib_basename);
501 continue;
502 }
503
489504 log.err("DLL import library for -l{s} not found", .{key});
490505 return error.DllImportLibraryNotFound;
491506 }
src/main.zig+30-2
......@@ -748,6 +748,7 @@ fn buildOutputType(
748748 var linker_nxcompat = false;
749749 var linker_dynamicbase = false;
750750 var linker_optimization: ?u8 = null;
751 var linker_module_definition_file: ?[]const u8 = null;
751752 var test_evented_io = false;
752753 var test_no_exec = false;
753754 var entry: ?[]const u8 = null;
......@@ -787,6 +788,7 @@ fn buildOutputType(
787788 var headerpad_max_install_names: bool = false;
788789 var dead_strip_dylibs: bool = false;
789790 var reference_trace: ?u32 = null;
791 var pdb_out_path: ?[]const u8 = null;
790792
791793 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
792794 // This array is populated by zig cc frontend and then has to be converted to zig-style
......@@ -1410,7 +1412,7 @@ fn buildOutputType(
14101412 root_src_file = arg;
14111413 }
14121414 },
1413 .unknown => {
1415 .def, .unknown => {
14141416 fatal("unrecognized file extension of parameter '{s}'", .{arg});
14151417 },
14161418 }
......@@ -1484,6 +1486,9 @@ fn buildOutputType(
14841486 .must_link = must_link,
14851487 });
14861488 },
1489 .def => {
1490 linker_module_definition_file = it.only_arg;
1491 },
14871492 .zig => {
14881493 if (root_src_file) |other| {
14891494 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
......@@ -1543,7 +1548,10 @@ fn buildOutputType(
15431548 .no_stack_protector => want_stack_protector = 0,
15441549 .unwind_tables => want_unwind_tables = true,
15451550 .no_unwind_tables => want_unwind_tables = false,
1546 .nostdlib => ensure_libc_on_non_freestanding = false,
1551 .nostdlib => {
1552 ensure_libc_on_non_freestanding = false;
1553 ensure_libcpp_on_non_freestanding = false;
1554 },
15471555 .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
15481556 .shared => {
15491557 link_mode = .Dynamic;
......@@ -2122,6 +2130,24 @@ fn buildOutputType(
21222130 next_arg,
21232131 });
21242132 };
2133 } else if (mem.startsWith(u8, arg, "/subsystem:")) {
2134 var split_it = mem.splitBackwards(u8, arg, ":");
2135 subsystem = try parseSubSystem(split_it.first());
2136 } else if (mem.startsWith(u8, arg, "/implib:")) {
2137 var split_it = mem.splitBackwards(u8, arg, ":");
2138 emit_implib = .{ .yes = split_it.first() };
2139 emit_implib_arg_provided = true;
2140 } else if (mem.startsWith(u8, arg, "/pdb:")) {
2141 var split_it = mem.splitBackwards(u8, arg, ":");
2142 pdb_out_path = split_it.first();
2143 } else if (mem.startsWith(u8, arg, "/version:")) {
2144 var split_it = mem.splitBackwards(u8, arg, ":");
2145 const version_arg = split_it.first();
2146 version = std.builtin.Version.parse(version_arg) catch |err| {
2147 fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) });
2148 };
2149
2150 have_version = true;
21252151 } else {
21262152 warn("unsupported linker arg: {s}", .{arg});
21272153 }
......@@ -3021,6 +3047,7 @@ fn buildOutputType(
30213047 .linker_dynamicbase = linker_dynamicbase,
30223048 .linker_optimization = linker_optimization,
30233049 .linker_compress_debug_sections = linker_compress_debug_sections,
3050 .linker_module_definition_file = linker_module_definition_file,
30243051 .major_subsystem_version = major_subsystem_version,
30253052 .minor_subsystem_version = minor_subsystem_version,
30263053 .link_eh_frame_hdr = link_eh_frame_hdr,
......@@ -3070,6 +3097,7 @@ fn buildOutputType(
30703097 .headerpad_max_install_names = headerpad_max_install_names,
30713098 .dead_strip_dylibs = dead_strip_dylibs,
30723099 .reference_trace = reference_trace,
3100 .pdb_out_path = pdb_out_path,
30733101 }) catch |err| switch (err) {
30743102 error.LibCUnavailable => {
30753103 const target = target_info.target;