| author | |
| committer | |
| log | b42442f5b4913938b04f580b1d13a1fd7318514d |
| tree | db86066c6ea6dc6f34904c162a49bf450c6419bb |
| parent | a03c8ef4bf526888518d13de1794c28375900cc2 |
Using zig cc with CMake on Windows was failing during compiler
detection. -nostdinc was causing the crt not to be linked, and Coff/lld.zig
assumed that wWinMainCRTStartup would be present in this case.
-nostdlib did not prevent the default behaviour of linking libc++ when
zig c++ was used. This caused libc++ to be built when CMake ran
ABI detection using zig c++, which fails as libcxxabi cannot compile
under MSVC.
- Change the behaviour of COFF -nostdinc to set /entry to the function that the
default CRT method for the specified subsystem would have called.
- Fix -ENTRY being passed twice if it was specified explicitly and -nostdlib was present.
- Add support for /pdb, /version, /implib, and /subsystem as linker args (passed by CMake)
- Remove -Ddisable-zstd, no longer needed
- Add -Ddisable-libcpp for use when bootstrapping on msvc6 files changed, 72 insertions(+), 12 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -92,6 +92,7 @@ set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries |
| 92 | 92 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") |
| 93 | 93 | set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib") |
| 94 | 94 | set(ZIG_ENABLE_ZSTD on CACHE BOOL "Enable linking zstd") |
| 95 | set(ZIG_ENABLE_LIBCPP on CACHE BOOL "Enable linking libcpp") | |
| 95 | 96 | set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd") |
| 96 | 97 | set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache") |
| 97 | 98 |
build.zig+5-8| ... | ... | @@ -99,7 +99,7 @@ pub fn build(b: *Builder) !void { |
| 99 | 99 | const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse false; |
| 100 | 100 | const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false; |
| 101 | 101 | const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); |
| 102 | const disable_zstd = b.option(bool, "disable-zstd", "Skip linking zstd") orelse false; | |
| 102 | const disable_libcpp = b.option(bool, "disable-libcpp", "Skip building/linking libcpp") orelse false; | |
| 103 | 103 | |
| 104 | 104 | if (!skip_install_lib_files) { |
| 105 | 105 | b.installDirectory(InstallDirectoryOptions{ |
| ... | ... | @@ -278,8 +278,8 @@ pub fn build(b: *Builder) !void { |
| 278 | 278 | try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx); |
| 279 | 279 | } else { |
| 280 | 280 | // Here we are -Denable-llvm but no cmake integration. |
| 281 | try addStaticLlvmOptionsToExe(exe, !disable_zstd); | |
| 282 | try addStaticLlvmOptionsToExe(test_cases, !disable_zstd); | |
| 281 | try addStaticLlvmOptionsToExe(exe); | |
| 282 | try addStaticLlvmOptionsToExe(test_cases); | |
| 283 | 283 | } |
| 284 | 284 | if (target.isWindows()) { |
| 285 | 285 | inline for (.{ exe, test_cases }) |artifact| { |
| ... | ... | @@ -607,7 +607,7 @@ fn addCmakeCfgOptionsToExe( |
| 607 | 607 | } |
| 608 | 608 | } |
| 609 | 609 | |
| 610 | fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep, link_zstd: bool) !void { | |
| 610 | fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void { | |
| 611 | 611 | // Adds the Zig C++ sources which both stage1 and stage2 need. |
| 612 | 612 | // |
| 613 | 613 | // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling |
| ... | ... | @@ -629,10 +629,7 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep, link_zstd: bool) !vo |
| 629 | 629 | } |
| 630 | 630 | |
| 631 | 631 | exe.linkSystemLibrary("z"); |
| 632 | ||
| 633 | if (link_zstd) { | |
| 634 | exe.linkSystemLibrary("zstd"); | |
| 635 | } | |
| 632 | exe.linkSystemLibrary("zstd"); | |
| 636 | 633 | |
| 637 | 634 | if (exe.target.getOs().tag != .windows or exe.target.getAbi() != .msvc) { |
| 638 | 635 | // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries. |
src/Compilation.zig+7| ... | ... | @@ -1042,6 +1042,11 @@ pub const InitOptions = struct { |
| 1042 | 1042 | /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols |
| 1043 | 1043 | dead_strip_dylibs: bool = false, |
| 1044 | 1044 | 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, | |
| 1045 | 1050 | }; |
| 1046 | 1051 | |
| 1047 | 1052 | fn addPackageTableToCacheHash( |
| ... | ... | @@ -1892,6 +1897,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1892 | 1897 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 1893 | 1898 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 1894 | 1899 | .force_undefined_symbols = .{}, |
| 1900 | .pdb_source_path = pdb_source_path, | |
| 1901 | .pdb_out_path = options.pdb_out_path, | |
| 1895 | 1902 | }); |
| 1896 | 1903 | errdefer bin_file.destroy(); |
| 1897 | 1904 | comp.* = .{ |
src/link.zig+3| ... | ... | @@ -223,6 +223,9 @@ pub const Options = struct { |
| 223 | 223 | /// paths when consolidating CodeView streams into a single PDB file. |
| 224 | 224 | pdb_source_path: ?[]const u8 = null, |
| 225 | 225 | |
| 226 | /// (Windows) PDB output path | |
| 227 | pdb_out_path: ?[]const u8 = null, | |
| 228 | ||
| 226 | 229 | /// (Windows) .def file to specify when linking |
| 227 | 230 | module_definition_file: ?[]const u8 = null, |
| 228 | 231 |
src/link/Coff/lld.zig+32-3| ... | ... | @@ -166,12 +166,16 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 166 | 166 | try argv.append("-DEBUG"); |
| 167 | 167 | |
| 168 | 168 | const out_ext = std.fs.path.extension(full_out_path); |
| 169 | const out_pdb = try allocPrint(arena, "{s}.pdb", .{ | |
| 169 | const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ | |
| 170 | 170 | full_out_path[0 .. full_out_path.len - out_ext.len], |
| 171 | 171 | }); |
| 172 | ||
| 172 | 173 | try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); |
| 173 | 174 | try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb})); |
| 174 | 175 | } |
| 176 | if (self.base.options.version) |version| { | |
| 177 | try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); | |
| 178 | } | |
| 175 | 179 | if (self.base.options.lto) { |
| 176 | 180 | switch (self.base.options.optimize_mode) { |
| 177 | 181 | .Debug => {}, |
| ... | ... | @@ -427,7 +431,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 427 | 431 | } |
| 428 | 432 | } else { |
| 429 | 433 | try argv.append("-NODEFAULTLIB"); |
| 430 | if (!is_lib) { | |
| 434 | if (!is_lib and self.base.options.entry == null) { | |
| 431 | 435 | if (self.base.options.module) |module| { |
| 432 | 436 | if (module.stage1_flags.have_winmain_crt_startup) { |
| 433 | 437 | try argv.append("-ENTRY:WinMainCRTStartup"); |
| ... | ... | @@ -435,7 +439,32 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 435 | 439 | try argv.append("-ENTRY:wWinMainCRTStartup"); |
| 436 | 440 | } |
| 437 | 441 | } else { |
| 438 | try argv.append("-ENTRY:wWinMainCRTStartup"); | |
| 442 | // If the crt isn't being linked, it won't provide the CRT startup methods that | |
| 443 | // call through to the user-provided entrypoint. Instead, choose the entry point | |
| 444 | // that the CRT methods would have called. Note that this differs from the behaviour | |
| 445 | // of link.exe (which still tries to use the CRT methods in this case), but this | |
| 446 | // fixes CMake compiler checks when using zig cc on Windows, as Windows-Clang.cmake | |
| 447 | // does not specify /entry:main | |
| 448 | ||
| 449 | // TODO: I think the correct thing to do in this case would be to inspect the object | |
| 450 | // being linked (like link.exe / lld-link does) and detect which symbols are available. | |
| 451 | // This would allow detection of the w variants, as well as the crt methods. | |
| 452 | if (resolved_subsystem) |subsystem| { | |
| 453 | switch (subsystem) { | |
| 454 | .Console => { | |
| 455 | // The default is to call mainCRTStartup/wmainCRTStartup, which calls main/wmain | |
| 456 | try argv.append("-ENTRY:main"); | |
| 457 | }, | |
| 458 | .Windows => { | |
| 459 | // The default is to call WinMainCRTStartup/wWinMainCRTStartup, which calls WinMain/wWinMain | |
| 460 | try argv.append("-ENTRY:WinMain"); | |
| 461 | }, | |
| 462 | else => {} | |
| 463 | } | |
| 464 | } | |
| 465 | ||
| 466 | // when no /entry is specified, lld-link will infer it based on which functions | |
| 467 | // are present in the object being linked - see lld/COFF/Driver.cpp#LinkerDriver::findDefaultEntry | |
| 439 | 468 | } |
| 440 | 469 | } |
| 441 | 470 | } |
src/main.zig+24-1| ... | ... | @@ -782,6 +782,7 @@ fn buildOutputType( |
| 782 | 782 | var headerpad_max_install_names: bool = false; |
| 783 | 783 | var dead_strip_dylibs: bool = false; |
| 784 | 784 | var reference_trace: ?u32 = null; |
| 785 | var pdb_out_path: ?[]const u8 = null; | |
| 785 | 786 | |
| 786 | 787 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 787 | 788 | // This array is populated by zig cc frontend and then has to be converted to zig-style |
| ... | ... | @@ -1541,7 +1542,10 @@ fn buildOutputType( |
| 1541 | 1542 | .no_stack_protector => want_stack_protector = 0, |
| 1542 | 1543 | .unwind_tables => want_unwind_tables = true, |
| 1543 | 1544 | .no_unwind_tables => want_unwind_tables = false, |
| 1544 | .nostdlib => ensure_libc_on_non_freestanding = false, | |
| 1545 | .nostdlib => { | |
| 1546 | ensure_libc_on_non_freestanding = false; | |
| 1547 | ensure_libcpp_on_non_freestanding = false; | |
| 1548 | }, | |
| 1545 | 1549 | .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, |
| 1546 | 1550 | .shared => { |
| 1547 | 1551 | link_mode = .Dynamic; |
| ... | ... | @@ -2120,6 +2124,24 @@ fn buildOutputType( |
| 2120 | 2124 | next_arg, |
| 2121 | 2125 | }); |
| 2122 | 2126 | }; |
| 2127 | } else if (mem.startsWith(u8, arg, "/subsystem:")) { | |
| 2128 | var split_it = mem.splitBackwards(u8, arg, ":"); | |
| 2129 | subsystem = try parseSubSystem(split_it.first()); | |
| 2130 | } else if (mem.startsWith(u8, arg, "/implib:")) { | |
| 2131 | var split_it = mem.splitBackwards(u8, arg, ":"); | |
| 2132 | emit_implib = .{ .yes = split_it.first() }; | |
| 2133 | emit_implib_arg_provided = true; | |
| 2134 | } else if (mem.startsWith(u8, arg, "/pdb:")) { | |
| 2135 | var split_it = mem.splitBackwards(u8, arg, ":"); | |
| 2136 | pdb_out_path = split_it.first(); | |
| 2137 | } else if (mem.startsWith(u8, arg, "/version:")) { | |
| 2138 | var split_it = mem.splitBackwards(u8, arg, ":"); | |
| 2139 | const version_arg = split_it.first(); | |
| 2140 | version = std.builtin.Version.parse(version_arg) catch |err| { | |
| 2141 | fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) }); | |
| 2142 | }; | |
| 2143 | ||
| 2144 | have_version = true; | |
| 2123 | 2145 | } else { |
| 2124 | 2146 | warn("unsupported linker arg: {s}", .{arg}); |
| 2125 | 2147 | } |
| ... | ... | @@ -3069,6 +3091,7 @@ fn buildOutputType( |
| 3069 | 3091 | .headerpad_max_install_names = headerpad_max_install_names, |
| 3070 | 3092 | .dead_strip_dylibs = dead_strip_dylibs, |
| 3071 | 3093 | .reference_trace = reference_trace, |
| 3094 | .pdb_out_path = pdb_out_path, | |
| 3072 | 3095 | }) catch |err| switch (err) { |
| 3073 | 3096 | error.LibCUnavailable => { |
| 3074 | 3097 | const target = target_info.target; |