| 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,6 +92,7 @@ set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries |
| 92 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") | 92 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") |
| 93 | set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib") | 93 | set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib") |
| 94 | set(ZIG_ENABLE_ZSTD on CACHE BOOL "Enable linking zstd") | 94 | set(ZIG_ENABLE_ZSTD on CACHE BOOL "Enable linking zstd") |
| 95 | set(ZIG_ENABLE_LIBCPP on CACHE BOOL "Enable linking libcpp") | ||
| 95 | set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd") | 96 | set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd") |
| 96 | set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache") | 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,7 +99,7 @@ pub fn build(b: *Builder) !void { |
| 99 | const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse false; | 99 | const enable_macos_sdk = b.option(bool, "enable-macos-sdk", "Run tests requiring presence of macOS SDK and frameworks") orelse false; |
| 100 | const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false; | 100 | const enable_symlinks_windows = b.option(bool, "enable-symlinks-windows", "Run tests requiring presence of symlinks on Windows") orelse false; |
| 101 | const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h"); | 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 | if (!skip_install_lib_files) { | 104 | if (!skip_install_lib_files) { |
| 105 | b.installDirectory(InstallDirectoryOptions{ | 105 | b.installDirectory(InstallDirectoryOptions{ |
| ... | @@ -278,8 +278,8 @@ pub fn build(b: *Builder) !void { | ... | @@ -278,8 +278,8 @@ pub fn build(b: *Builder) !void { |
| 278 | try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx); | 278 | try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx); |
| 279 | } else { | 279 | } else { |
| 280 | // Here we are -Denable-llvm but no cmake integration. | 280 | // Here we are -Denable-llvm but no cmake integration. |
| 281 | try addStaticLlvmOptionsToExe(exe, !disable_zstd); | 281 | try addStaticLlvmOptionsToExe(exe); |
| 282 | try addStaticLlvmOptionsToExe(test_cases, !disable_zstd); | 282 | try addStaticLlvmOptionsToExe(test_cases); |
| 283 | } | 283 | } |
| 284 | if (target.isWindows()) { | 284 | if (target.isWindows()) { |
| 285 | inline for (.{ exe, test_cases }) |artifact| { | 285 | inline for (.{ exe, test_cases }) |artifact| { |
| ... | @@ -607,7 +607,7 @@ fn addCmakeCfgOptionsToExe( | ... | @@ -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 | // Adds the Zig C++ sources which both stage1 and stage2 need. | 611 | // Adds the Zig C++ sources which both stage1 and stage2 need. |
| 612 | // | 612 | // |
| 613 | // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling | 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,10 +629,7 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep, link_zstd: bool) !vo |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | exe.linkSystemLibrary("z"); | 631 | exe.linkSystemLibrary("z"); |
| 632 | 632 | exe.linkSystemLibrary("zstd"); | |
| 633 | if (link_zstd) { | ||
| 634 | exe.linkSystemLibrary("zstd"); | ||
| 635 | } | ||
| 636 | 633 | ||
| 637 | if (exe.target.getOs().tag != .windows or exe.target.getAbi() != .msvc) { | 634 | if (exe.target.getOs().tag != .windows or exe.target.getAbi() != .msvc) { |
| 638 | // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries. | 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,6 +1042,11 @@ pub const InitOptions = struct { |
| 1042 | /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols | 1042 | /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols |
| 1043 | dead_strip_dylibs: bool = false, | 1043 | dead_strip_dylibs: bool = false, |
| 1044 | libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, | 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 | fn addPackageTableToCacheHash( | 1052 | fn addPackageTableToCacheHash( |
| ... | @@ -1892,6 +1897,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1892,6 +1897,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1892 | .headerpad_max_install_names = options.headerpad_max_install_names, | 1897 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 1893 | .dead_strip_dylibs = options.dead_strip_dylibs, | 1898 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 1894 | .force_undefined_symbols = .{}, | 1899 | .force_undefined_symbols = .{}, |
| 1900 | .pdb_source_path = pdb_source_path, | ||
| 1901 | .pdb_out_path = options.pdb_out_path, | ||
| 1895 | }); | 1902 | }); |
| 1896 | errdefer bin_file.destroy(); | 1903 | errdefer bin_file.destroy(); |
| 1897 | comp.* = .{ | 1904 | comp.* = .{ |
src/link.zig+3| ... | @@ -223,6 +223,9 @@ pub const Options = struct { | ... | @@ -223,6 +223,9 @@ pub const Options = struct { |
| 223 | /// paths when consolidating CodeView streams into a single PDB file. | 223 | /// paths when consolidating CodeView streams into a single PDB file. |
| 224 | pdb_source_path: ?[]const u8 = null, | 224 | pdb_source_path: ?[]const u8 = null, |
| 225 | 225 | ||
| 226 | /// (Windows) PDB output path | ||
| 227 | pdb_out_path: ?[]const u8 = null, | ||
| 228 | |||
| 226 | /// (Windows) .def file to specify when linking | 229 | /// (Windows) .def file to specify when linking |
| 227 | module_definition_file: ?[]const u8 = null, | 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,12 +166,16 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 166 | try argv.append("-DEBUG"); | 166 | try argv.append("-DEBUG"); |
| 167 | 167 | ||
| 168 | const out_ext = std.fs.path.extension(full_out_path); | 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 | full_out_path[0 .. full_out_path.len - out_ext.len], | 170 | full_out_path[0 .. full_out_path.len - out_ext.len], |
| 171 | }); | 171 | }); |
| 172 | |||
| 172 | try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); | 173 | try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); |
| 173 | try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb})); | 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 | if (self.base.options.lto) { | 179 | if (self.base.options.lto) { |
| 176 | switch (self.base.options.optimize_mode) { | 180 | switch (self.base.options.optimize_mode) { |
| 177 | .Debug => {}, | 181 | .Debug => {}, |
| ... | @@ -427,7 +431,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -427,7 +431,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 427 | } | 431 | } |
| 428 | } else { | 432 | } else { |
| 429 | try argv.append("-NODEFAULTLIB"); | 433 | try argv.append("-NODEFAULTLIB"); |
| 430 | if (!is_lib) { | 434 | if (!is_lib and self.base.options.entry == null) { |
| 431 | if (self.base.options.module) |module| { | 435 | if (self.base.options.module) |module| { |
| 432 | if (module.stage1_flags.have_winmain_crt_startup) { | 436 | if (module.stage1_flags.have_winmain_crt_startup) { |
| 433 | try argv.append("-ENTRY:WinMainCRTStartup"); | 437 | try argv.append("-ENTRY:WinMainCRTStartup"); |
| ... | @@ -435,7 +439,32 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -435,7 +439,32 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 435 | try argv.append("-ENTRY:wWinMainCRTStartup"); | 439 | try argv.append("-ENTRY:wWinMainCRTStartup"); |
| 436 | } | 440 | } |
| 437 | } else { | 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,6 +782,7 @@ fn buildOutputType( |
| 782 | var headerpad_max_install_names: bool = false; | 782 | var headerpad_max_install_names: bool = false; |
| 783 | var dead_strip_dylibs: bool = false; | 783 | var dead_strip_dylibs: bool = false; |
| 784 | var reference_trace: ?u32 = null; | 784 | var reference_trace: ?u32 = null; |
| 785 | var pdb_out_path: ?[]const u8 = null; | ||
| 785 | 786 | ||
| 786 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. | 787 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 787 | // This array is populated by zig cc frontend and then has to be converted to zig-style | 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,7 +1542,10 @@ fn buildOutputType( |
| 1541 | .no_stack_protector => want_stack_protector = 0, | 1542 | .no_stack_protector => want_stack_protector = 0, |
| 1542 | .unwind_tables => want_unwind_tables = true, | 1543 | .unwind_tables => want_unwind_tables = true, |
| 1543 | .no_unwind_tables => want_unwind_tables = false, | 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 | .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, | 1549 | .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, |
| 1546 | .shared => { | 1550 | .shared => { |
| 1547 | link_mode = .Dynamic; | 1551 | link_mode = .Dynamic; |
| ... | @@ -2120,6 +2124,24 @@ fn buildOutputType( | ... | @@ -2120,6 +2124,24 @@ fn buildOutputType( |
| 2120 | next_arg, | 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 | } else { | 2145 | } else { |
| 2124 | warn("unsupported linker arg: {s}", .{arg}); | 2146 | warn("unsupported linker arg: {s}", .{arg}); |
| 2125 | } | 2147 | } |
| ... | @@ -3069,6 +3091,7 @@ fn buildOutputType( | ... | @@ -3069,6 +3091,7 @@ fn buildOutputType( |
| 3069 | .headerpad_max_install_names = headerpad_max_install_names, | 3091 | .headerpad_max_install_names = headerpad_max_install_names, |
| 3070 | .dead_strip_dylibs = dead_strip_dylibs, | 3092 | .dead_strip_dylibs = dead_strip_dylibs, |
| 3071 | .reference_trace = reference_trace, | 3093 | .reference_trace = reference_trace, |
| 3094 | .pdb_out_path = pdb_out_path, | ||
| 3072 | }) catch |err| switch (err) { | 3095 | }) catch |err| switch (err) { |
| 3073 | error.LibCUnavailable => { | 3096 | error.LibCUnavailable => { |
| 3074 | const target = target_info.target; | 3097 | const target = target_info.target; |