Merge pull request #13514 from kcbanner/windows_build_fixes

Windows: Support building stage3, and bootstrapping via MSVC
This commit is contained in:
Andrew Kelley 2023-01-05 17:26:32 -07:00 committed by GitHub
commit c28c38d1e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 109 additions and 24 deletions

View File

@ -89,9 +89,9 @@ endif()
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
set(ZIG_STATIC_ZLIB off CACHE BOOL "Prefer linking against static zlib")
set(ZIG_STATIC_ZSTD off CACHE BOOL "Prefer linking against static zstd")
set(ZIG_STATIC_LLVM ${ZIG_STATIC} CACHE BOOL "Prefer linking against static LLVM libraries")
set(ZIG_STATIC_ZLIB ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zlib")
set(ZIG_STATIC_ZSTD ${ZIG_STATIC} CACHE BOOL "Prefer linking against static zstd")
set(ZIG_USE_CCACHE off CACHE BOOL "Use ccache")
if(ZIG_USE_CCACHE)
@ -103,12 +103,6 @@ if(ZIG_USE_CCACHE)
endif()
endif()
if(ZIG_STATIC)
set(ZIG_STATIC_LLVM ON)
set(ZIG_STATIC_ZLIB ON)
set(ZIG_STATIC_ZSTD ON)
endif()
if (ZIG_SHARED_LLVM AND ZIG_STATIC_LLVM)
message(SEND_ERROR "-DZIG_SHARED_LLVM and -DZIG_STATIC_LLVM cannot both be enabled simultaneously")
endif()
@ -138,13 +132,23 @@ find_package(clang 15)
find_package(lld 15)
if(ZIG_STATIC_ZLIB)
list(REMOVE_ITEM LLVM_LIBRARIES "-lz")
if (MSVC)
list(REMOVE_ITEM LLVM_LIBRARIES "z.lib")
else()
list(REMOVE_ITEM LLVM_LIBRARIES "-lz")
endif()
find_library(ZLIB NAMES libz.a libzlibstatic.a z zlib libz NAMES_PER_DIR)
list(APPEND LLVM_LIBRARIES "${ZLIB}")
endif()
if(ZIG_STATIC_ZSTD)
list(REMOVE_ITEM LLVM_LIBRARIES "-lzstd")
if (MSVC)
list(REMOVE_ITEM LLVM_LIBRARIES "zstd.lib")
else()
list(REMOVE_ITEM LLVM_LIBRARIES "-lzstd")
endif()
find_library(ZSTD NAMES libzstd.a libzstdstatic.a zstd NAMES_PER_DIR)
list(APPEND LLVM_LIBRARIES "${ZSTD}")
endif()
@ -168,6 +172,7 @@ foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${CONFIG_TYPE} CONFIG_TYPE)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${ZIG_CPP_LIB_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONFIG_TYPE} ${CMAKE_BINARY_DIR})
endforeach(CONFIG_TYPE CMAKE_CONFIGURATION_TYPES)
include_directories(${LLVM_INCLUDE_DIRS})
@ -722,9 +727,9 @@ set(HOST_TARGET_TRIPLE "${HOST_TARGET_ARCH}-${HOST_TARGET_OS}")
if(MSVC)
set(ZIG_WASM2C_COMPILE_FLAGS "")
set(ZIG1_COMPILE_FLAGS "/std:c99 /Os")
set(ZIG2_COMPILE_FLAGS "/std:c99 /O0")
set(ZIG2_LINK_FLAGS "/STACK:16777216")
set(ZIG1_COMPILE_FLAGS "/Os")
set(ZIG2_COMPILE_FLAGS "/Od")
set(ZIG2_LINK_FLAGS "/STACK:16777216 /FORCE:MULTIPLE")
else()
set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
set(ZIG1_COMPILE_FLAGS "-std=c99 -Os")
@ -838,7 +843,7 @@ if(ZIG_SINGLE_THREADED)
else()
set(ZIG_SINGLE_THREADED_ARG "")
endif()
if(ZIG_STATIC)
if(ZIG_STATIC AND NOT MSVC)
set(ZIG_STATIC_ARG "-Duse-zig-libcxx")
else()
set(ZIG_STATIC_ARG "")

View File

@ -628,8 +628,16 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
exe.linkSystemLibrary("z");
exe.linkSystemLibrary("zstd");
// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");
if (exe.target.getOs().tag != .windows or exe.target.getAbi() != .msvc) {
// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");
}
if (exe.target.getOs().tag == .windows) {
exe.linkSystemLibrary("version");
exe.linkSystemLibrary("uuid");
exe.linkSystemLibrary("ole32");
}
}
fn addCxxKnownPath(
@ -673,6 +681,8 @@ fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
while (it.next()) |lib| {
if (mem.startsWith(u8, lib, "-l")) {
exe.linkSystemLibrary(lib["-l".len..]);
} else if (exe.target.isWindows() and mem.endsWith(u8, lib, ".lib") and !fs.path.isAbsolute(lib)) {
exe.linkSystemLibrary(lib[0 .. lib.len - ".lib".len]);
} else {
exe.addObjectFile(lib);
}

View File

@ -68,6 +68,10 @@ else()
FIND_AND_ADD_CLANG_LIB(clangSupport)
endif()
if (MSVC)
set(CLANG_LIBRARIES ${CLANG_LIBRARIES} "version.lib")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(clang DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)

View File

@ -984,6 +984,7 @@ pub const InitOptions = struct {
linker_dynamicbase: bool = false,
linker_optimization: ?u8 = null,
linker_compress_debug_sections: ?link.CompressDebugSections = null,
linker_module_definition_file: ?[]const u8 = null,
major_subsystem_version: ?u32 = null,
minor_subsystem_version: ?u32 = null,
clang_passthrough_mode: bool = false,
@ -1041,6 +1042,11 @@ pub const InitOptions = struct {
/// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
dead_strip_dylibs: bool = false,
libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
/// (Windows) PDB source path prefix to instruct the linker how to resolve relative
/// paths when consolidating CodeView streams into a single PDB file.
pdb_source_path: ?[]const u8 = null,
/// (Windows) PDB output path
pdb_out_path: ?[]const u8 = null,
};
fn addPackageTableToCacheHash(
@ -1815,6 +1821,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.allow_shlib_undefined = options.linker_allow_shlib_undefined,
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
.compress_debug_sections = options.linker_compress_debug_sections orelse .none,
.module_definition_file = options.linker_module_definition_file,
.import_memory = options.linker_import_memory orelse false,
.import_symbols = options.linker_import_symbols,
.import_table = options.linker_import_table,
@ -1890,6 +1897,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.headerpad_max_install_names = options.headerpad_max_install_names,
.dead_strip_dylibs = options.dead_strip_dylibs,
.force_undefined_symbols = .{},
.pdb_source_path = options.pdb_source_path,
.pdb_out_path = options.pdb_out_path,
});
errdefer bin_file.destroy();
comp.* = .{
@ -3297,8 +3306,8 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
// TODO Surface more error details.
comp.lockAndSetMiscFailure(
.windows_import_lib,
"unable to generate DLL import .lib file: {s}",
.{@errorName(err)},
"unable to generate DLL import .lib file for {s}: {s}",
.{ link_lib, @errorName(err) },
);
};
},
@ -4379,7 +4388,7 @@ pub fn addCCArgs(
try argv.append("-fno-unwind-tables");
}
},
.shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {},
.shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig => {},
.assembly => {
// The Clang assembler does not accept the list of CPU features like the
// compiler frontend does. Therefore we must hard-code the -m flags for
@ -4524,6 +4533,7 @@ pub const FileExt = enum {
object,
static_library,
zig,
def,
unknown,
pub fn clangSupportsDepFile(ext: FileExt) bool {
@ -4537,6 +4547,7 @@ pub const FileExt = enum {
.object,
.static_library,
.zig,
.def,
.unknown,
=> false,
};
@ -4629,6 +4640,8 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
return .object;
} else if (mem.endsWith(u8, filename, ".cu")) {
return .cu;
} else if (mem.endsWith(u8, filename, ".def")) {
return .def;
} else {
return .unknown;
}

View File

@ -219,6 +219,16 @@ pub const Options = struct {
/// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
dead_strip_dylibs: bool = false,
/// (Windows) PDB source path prefix to instruct the linker how to resolve relative
/// paths when consolidating CodeView streams into a single PDB file.
pdb_source_path: ?[]const u8 = null,
/// (Windows) PDB output path
pdb_out_path: ?[]const u8 = null,
/// (Windows) .def file to specify when linking
module_definition_file: ?[]const u8 = null,
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
return if (options.use_lld) .Obj else options.output_mode;
}

View File

@ -98,6 +98,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
// strip does not need to go into the linker hash because it is part of the hash namespace
man.hash.addOptional(self.base.options.major_subsystem_version);
man.hash.addOptional(self.base.options.minor_subsystem_version);
man.hash.addOptional(self.base.options.version);
try man.addOptionalFile(self.base.options.module_definition_file);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@ -166,12 +168,16 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append("-DEBUG");
const out_ext = std.fs.path.extension(full_out_path);
const out_pdb = try allocPrint(arena, "{s}.pdb", .{
const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{
full_out_path[0 .. full_out_path.len - out_ext.len],
});
try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb}));
try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb}));
}
if (self.base.options.version) |version| {
try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
}
if (self.base.options.lto) {
switch (self.base.options.optimize_mode) {
.Debug => {},
@ -260,6 +266,10 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try argv.append(p);
}
if (self.base.options.module_definition_file) |def| {
try argv.append(try allocPrint(arena, "-DEF:{s}", .{def}));
}
const resolved_subsystem: ?std.Target.SubSystem = blk: {
if (self.base.options.subsystem) |explicit| break :blk explicit;
switch (target.os.tag) {
@ -423,7 +433,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
}
} else {
try argv.append("-NODEFAULTLIB");
if (!is_lib) {
if (!is_lib and self.base.options.entry == null) {
if (self.base.options.module) |module| {
if (module.stage1_flags.have_winmain_crt_startup) {
try argv.append("-ENTRY:WinMainCRTStartup");
@ -486,6 +496,11 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
continue;
}
}
if (target.abi == .msvc) {
argv.appendAssumeCapacity(lib_basename);
continue;
}
log.err("DLL import library for -l{s} not found", .{key});
return error.DllImportLibraryNotFound;
}

View File

@ -748,6 +748,7 @@ fn buildOutputType(
var linker_nxcompat = false;
var linker_dynamicbase = false;
var linker_optimization: ?u8 = null;
var linker_module_definition_file: ?[]const u8 = null;
var test_evented_io = false;
var test_no_exec = false;
var entry: ?[]const u8 = null;
@ -787,6 +788,7 @@ fn buildOutputType(
var headerpad_max_install_names: bool = false;
var dead_strip_dylibs: bool = false;
var reference_trace: ?u32 = null;
var pdb_out_path: ?[]const u8 = null;
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
// This array is populated by zig cc frontend and then has to be converted to zig-style
@ -1410,7 +1412,7 @@ fn buildOutputType(
root_src_file = arg;
}
},
.unknown => {
.def, .unknown => {
fatal("unrecognized file extension of parameter '{s}'", .{arg});
},
}
@ -1484,6 +1486,9 @@ fn buildOutputType(
.must_link = must_link,
});
},
.def => {
linker_module_definition_file = it.only_arg;
},
.zig => {
if (root_src_file) |other| {
fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
@ -1543,7 +1548,10 @@ fn buildOutputType(
.no_stack_protector => want_stack_protector = 0,
.unwind_tables => want_unwind_tables = true,
.no_unwind_tables => want_unwind_tables = false,
.nostdlib => ensure_libc_on_non_freestanding = false,
.nostdlib => {
ensure_libc_on_non_freestanding = false;
ensure_libcpp_on_non_freestanding = false;
},
.nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
.shared => {
link_mode = .Dynamic;
@ -2122,6 +2130,24 @@ fn buildOutputType(
next_arg,
});
};
} else if (mem.startsWith(u8, arg, "/subsystem:")) {
var split_it = mem.splitBackwards(u8, arg, ":");
subsystem = try parseSubSystem(split_it.first());
} else if (mem.startsWith(u8, arg, "/implib:")) {
var split_it = mem.splitBackwards(u8, arg, ":");
emit_implib = .{ .yes = split_it.first() };
emit_implib_arg_provided = true;
} else if (mem.startsWith(u8, arg, "/pdb:")) {
var split_it = mem.splitBackwards(u8, arg, ":");
pdb_out_path = split_it.first();
} else if (mem.startsWith(u8, arg, "/version:")) {
var split_it = mem.splitBackwards(u8, arg, ":");
const version_arg = split_it.first();
version = std.builtin.Version.parse(version_arg) catch |err| {
fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) });
};
have_version = true;
} else {
warn("unsupported linker arg: {s}", .{arg});
}
@ -3021,6 +3047,7 @@ fn buildOutputType(
.linker_dynamicbase = linker_dynamicbase,
.linker_optimization = linker_optimization,
.linker_compress_debug_sections = linker_compress_debug_sections,
.linker_module_definition_file = linker_module_definition_file,
.major_subsystem_version = major_subsystem_version,
.minor_subsystem_version = minor_subsystem_version,
.link_eh_frame_hdr = link_eh_frame_hdr,
@ -3070,6 +3097,7 @@ fn buildOutputType(
.headerpad_max_install_names = headerpad_max_install_names,
.dead_strip_dylibs = dead_strip_dylibs,
.reference_trace = reference_trace,
.pdb_out_path = pdb_out_path,
}) catch |err| switch (err) {
error.LibCUnavailable => {
const target = target_info.target;