mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #13514 from kcbanner/windows_build_fixes
Windows: Support building stage3, and bootstrapping via MSVC
This commit is contained in:
commit
c28c38d1e5
@ -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)
|
||||
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)
|
||||
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 "")
|
||||
|
||||
10
build.zig
10
build.zig
@ -628,8 +628,16 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
|
||||
exe.linkSystemLibrary("z");
|
||||
exe.linkSystemLibrary("zstd");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
10
src/link.zig
10
src/link.zig
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
32
src/main.zig
32
src/main.zig
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user