diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 6abb650a6..093aab21d 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -276,6 +276,7 @@ pub const Compilation = struct { LibCRequiredButNotProvidedOrFound, LibCMissingDynamicLinker, InvalidDarwinVersionString, + UnsupportedLinkArchitecture, }; pub const Event = union(enum) { diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index c9c631a7f..3938c0d90 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -20,8 +20,10 @@ pub const LibCInstallation = struct { CCompilerExitCode, CCompilerCrashed, CCompilerCannotFindHeaders, - CCompilerCannotFindCRuntime, + LibCRuntimeNotFound, LibCStdLibHeaderNotFound, + LibCKernel32LibNotFound, + UnsupportedArchitecture, }; pub fn parse( @@ -111,7 +113,7 @@ pub const LibCInstallation = struct { \\lib_dir={} \\ \\# The directory that contains `crtbegin.o`. - \\# On Linux, can be found with `cc -print-file-name=crt1.o`. + \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`. \\# Not needed when targeting MacOS or Windows. \\static_lib_dir={} \\ @@ -142,21 +144,22 @@ pub const LibCInstallation = struct { self.initEmpty(); var group = event.Group(FindError!void).init(loop); errdefer group.cancelAll(); + var windows_sdk: ?*c.ZigWindowsSDK = null; + errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk)); + switch (builtin.os) { builtin.Os.windows => { var sdk: *c.ZigWindowsSDK = undefined; switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) { c.ZigFindWindowsSdkError.None => { - defer c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk)); + windows_sdk = sdk; - errdefer if (self.msvc_lib_dir) |s| loop.allocator.free(s); if (sdk.msvc_lib_dir_ptr) |ptr| { self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]); } - //try group.call(findNativeIncludeDirWindows, self, loop); - //try group.call(findNativeLibDirWindows, self, loop); - //try group.call(findNativeMsvcLibDir, self, loop); - //try group.call(findNativeKernel32LibDir, self, loop); + try group.call(findNativeKernel32LibDir, self, loop, sdk); + try group.call(findNativeIncludeDirWindows, self, loop, sdk); + try group.call(findNativeLibDirWindows, self, loop, sdk); }, c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory, c.ZigFindWindowsSdkError.NotFound => return error.NotFound, @@ -230,61 +233,64 @@ pub const LibCInstallation = struct { const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h"); defer loop.allocator.free(stdlib_path); - if (std.os.File.access(loop.allocator, stdlib_path)) |_| { + if (try fileExists(loop.allocator, stdlib_path)) { self.include_dir = try std.mem.dupe(loop.allocator, u8, search_path); return; - } else |err| switch (err) { - error.NotFound, error.PermissionDenied => continue, - error.OutOfMemory => return error.OutOfMemory, - else => return error.FileSystem, } } return error.LibCStdLibHeaderNotFound; } - async fn findNativeIncludeDirWindows(self: *LibCInstallation, loop: *event.Loop) !void { - // TODO - //ZigWindowsSDK *sdk = get_windows_sdk(g); - //g->libc_include_dir = buf_alloc(); - //if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) { - // fprintf(stderr, "Unable to determine libc include path. --libc-include-dir"); - // exit(1); - //} - @panic("TODO"); + async fn findNativeIncludeDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) !void { + var search_buf: [2]Search = undefined; + const searches = fillSearch(&search_buf, sdk); + + var result_buf = try std.Buffer.initSize(loop.allocator, 0); + defer result_buf.deinit(); + + for (searches) |search| { + result_buf.shrink(0); + const stream = &std.io.BufferOutStream.init(&result_buf).stream; + try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version); + + const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h"); + defer loop.allocator.free(stdlib_path); + + if (try fileExists(loop.allocator, stdlib_path)) { + self.include_dir = result_buf.toOwnedSlice(); + return; + } + } + + return error.LibCStdLibHeaderNotFound; } - async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop) FindError!void { - // TODO - //ZigWindowsSDK *sdk = get_windows_sdk(g); + async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void { + var search_buf: [2]Search = undefined; + const searches = fillSearch(&search_buf, sdk); - //if (g->msvc_lib_dir == nullptr) { - // Buf* vc_lib_dir = buf_alloc(); - // if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) { - // fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir"); - // exit(1); - // } - // g->msvc_lib_dir = vc_lib_dir; - //} + var result_buf = try std.Buffer.initSize(loop.allocator, 0); + defer result_buf.deinit(); - //if (g->libc_lib_dir == nullptr) { - // Buf* ucrt_lib_path = buf_alloc(); - // if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) { - // fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir"); - // exit(1); - // } - // g->libc_lib_dir = ucrt_lib_path; - //} - - //if (g->kernel32_lib_dir == nullptr) { - // Buf* kern_lib_path = buf_alloc(); - // if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) { - // fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir"); - // exit(1); - // } - // g->kernel32_lib_dir = kern_lib_path; - //} - @panic("TODO"); + for (searches) |search| { + result_buf.shrink(0); + const stream = &std.io.BufferOutStream.init(&result_buf).stream; + try stream.print("{}\\Lib\\{}\\ucrt\\", search.path, search.version); + switch (builtin.arch) { + builtin.Arch.i386 => try stream.write("x86"), + builtin.Arch.x86_64 => try stream.write("x64"), + builtin.Arch.aarch64 => try stream.write("arm"), + else => return error.UnsupportedArchitecture, + } + const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib"); + defer loop.allocator.free(ucrt_lib_path); + if (try fileExists(loop.allocator, ucrt_lib_path)) { + self.lib_dir = result_buf.toOwnedSlice(); + return; + } + } + return error.LibCRuntimeNotFound; } async fn findNativeLibDirLinux(self: *LibCInstallation, loop: *event.Loop) FindError!void { @@ -330,17 +336,37 @@ pub const LibCInstallation = struct { dyn_test.result = result; return; } else |err| switch (err) { - error.CCompilerCannotFindCRuntime => return, + error.LibCRuntimeNotFound => return, else => return err, } } - async fn findNativeMsvcLibDir(self: *LibCInstallation, loop: *event.Loop) FindError!void { - @panic("TODO"); - } - async fn findNativeKernel32LibDir(self: *LibCInstallation, loop: *event.Loop) FindError!void { - @panic("TODO"); + async fn findNativeKernel32LibDir(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void { + var search_buf: [2]Search = undefined; + const searches = fillSearch(&search_buf, sdk); + + var result_buf = try std.Buffer.initSize(loop.allocator, 0); + defer result_buf.deinit(); + + for (searches) |search| { + result_buf.shrink(0); + const stream = &std.io.BufferOutStream.init(&result_buf).stream; + try stream.print("{}\\Lib\\{}\\um\\", search.path, search.version); + switch (builtin.arch) { + builtin.Arch.i386 => try stream.write("x86\\"), + builtin.Arch.x86_64 => try stream.write("x64\\"), + builtin.Arch.aarch64 => try stream.write("arm\\"), + else => return error.UnsupportedArchitecture, + } + const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib"); + defer loop.allocator.free(kernel32_path); + if (try fileExists(loop.allocator, kernel32_path)) { + self.kernel32_lib_dir = result_buf.toOwnedSlice(); + return; + } + } + return error.LibCKernel32LibNotFound; } fn initEmpty(self: *LibCInstallation) void { @@ -386,8 +412,8 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo }, } var it = std.mem.split(exec_result.stdout, "\n\r"); - const line = it.next() orelse return error.CCompilerCannotFindCRuntime; - const dirname = std.os.path.dirname(line) orelse return error.CCompilerCannotFindCRuntime; + const line = it.next() orelse return error.LibCRuntimeNotFound; + const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound; if (want_dirname) { return std.mem.dupe(loop.allocator, u8, dirname); @@ -395,3 +421,42 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo return std.mem.dupe(loop.allocator, u8, line); } } + +const Search = struct { + path: []const u8, + version: []const u8, +}; + +fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { + var search_end: usize = 0; + if (sdk.path10_ptr) |path10_ptr| { + if (sdk.version10_ptr) |ver10_ptr| { + search_buf[search_end] = Search{ + .path = path10_ptr[0..sdk.path10_len], + .version = ver10_ptr[0..sdk.version10_len], + }; + search_end += 1; + } + } + if (sdk.path81_ptr) |path81_ptr| { + if (sdk.version81_ptr) |ver81_ptr| { + search_buf[search_end] = Search{ + .path = path81_ptr[0..sdk.path81_len], + .version = ver81_ptr[0..sdk.version81_len], + }; + search_end += 1; + } + } + return search_buf[0..search_end]; +} + + +fn fileExists(allocator: *std.mem.Allocator, path: []const u8) !bool { + if (std.os.File.access(allocator, path)) |_| { + return true; + } else |err| switch (err) { + error.NotFound, error.PermissionDenied => return false, + error.OutOfMemory => return error.OutOfMemory, + else => return error.FileSystem, + } +} diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 0a83743ef..b9eefa9d4 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -313,8 +313,150 @@ fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { try ctx.args.append(full_path_with_null.ptr); } -fn constructLinkerArgsCoff(ctx: *Context) void { - @panic("TODO"); +fn constructLinkerArgsCoff(ctx: *Context) !void { + try ctx.args.append(c"-NOLOGO"); + + if (!ctx.comp.strip) { + try ctx.args.append(c"-DEBUG"); + } + + switch (ctx.comp.target.getArch()) { + builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"), + builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"), + builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"), + else => return error.UnsupportedLinkArchitecture, + } + + if (ctx.comp.windows_subsystem_windows) { + try ctx.args.append(c"/SUBSYSTEM:windows"); + } else if (ctx.comp.windows_subsystem_console) { + try ctx.args.append(c"/SUBSYSTEM:console"); + } + + const is_library = ctx.comp.kind == Compilation.Kind.Lib; + + const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst()); + try ctx.args.append(out_arg.ptr); + + if (ctx.comp.haveLibC()) { + try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr); + try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr); + try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr); + } + + if (ctx.link_in_crt) { + const lib_str = if (ctx.comp.is_static) "lib" else ""; + const d_str = if (ctx.comp.build_mode == builtin.Mode.Debug) "d" else ""; + + if (ctx.comp.is_static) { + const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str); + try ctx.args.append(cmt_lib_name.ptr); + } else { + const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str); + try ctx.args.append(msvcrt_lib_name.ptr); + } + + const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str); + try ctx.args.append(vcruntime_lib_name.ptr); + + const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str); + try ctx.args.append(crt_lib_name.ptr); + + // Visual C++ 2015 Conformance Changes + // https://msdn.microsoft.com/en-us/library/bb531344.aspx + try ctx.args.append(c"legacy_stdio_definitions.lib"); + + // msvcrt depends on kernel32 + try ctx.args.append(c"kernel32.lib"); + } else { + try ctx.args.append(c"-NODEFAULTLIB"); + if (!is_library) { + try ctx.args.append(c"-ENTRY:WinMainCRTStartup"); + // TODO + //if (g->have_winmain) { + // lj->args.append("-ENTRY:WinMain"); + //} else { + // lj->args.append("-ENTRY:WinMainCRTStartup"); + //} + } + } + + if (is_library and !ctx.comp.is_static) { + try ctx.args.append(c"-DLL"); + } + + //for (size_t i = 0; i < g->lib_dirs.length; i += 1) { + // const char *lib_dir = g->lib_dirs.at(i); + // lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir))); + //} + + for (ctx.comp.link_objects) |link_object| { + const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object); + try ctx.args.append(link_obj_with_null.ptr); + } + try addFnObjects(ctx); + + switch (ctx.comp.kind) { + Compilation.Kind.Exe, Compilation.Kind.Lib => { + if (!ctx.comp.haveLibC()) { + @panic("TODO"); + //Buf *builtin_o_path = build_o(g, "builtin"); + //lj->args.append(buf_ptr(builtin_o_path)); + } + + // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage + // TODO + //Buf *compiler_rt_o_path = build_compiler_rt(g); + //lj->args.append(buf_ptr(compiler_rt_o_path)); + }, + Compilation.Kind.Obj => {}, + } + + //Buf *def_contents = buf_alloc(); + //ZigList gen_lib_args = {0}; + //for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) { + // LinkLib *link_lib = g->link_libs_list.at(lib_i); + // if (buf_eql_str(link_lib->name, "c")) { + // continue; + // } + // if (link_lib->provided_explicitly) { + // if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) { + // Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name)); + // lj->args.append(buf_ptr(arg)); + // } + // else { + // lj->args.append(buf_ptr(link_lib->name)); + // } + // } else { + // buf_resize(def_contents, 0); + // buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name)); + // for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) { + // Buf *symbol_name = link_lib->symbols.at(exp_i); + // buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name)); + // } + // buf_appendf(def_contents, "\n"); + + // Buf *def_path = buf_alloc(); + // os_path_join(g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); + // os_write_file(def_path, def_contents); + + // Buf *generated_lib_path = buf_alloc(); + // os_path_join(g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); + + // gen_lib_args.resize(0); + // gen_lib_args.append("link"); + + // coff_append_machine_arg(g, &gen_lib_args); + // gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); + // gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); + // Buf diag = BUF_INIT; + // if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) { + // fprintf(stderr, "%s\n", buf_ptr(&diag)); + // exit(1); + // } + // lj->args.append(buf_ptr(generated_lib_path)); + // } + //} } fn constructLinkerArgsMachO(ctx: *Context) !void { diff --git a/src/windows_sdk.cpp b/src/windows_sdk.cpp index 059bdee4e..0f9d0fc30 100644 --- a/src/windows_sdk.cpp +++ b/src/windows_sdk.cpp @@ -287,7 +287,10 @@ ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) { } rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)priv->base.path10_ptr, &tmp_buf_len); if (rc == ERROR_SUCCESS) { - priv->base.path10_len = tmp_buf_len; + priv->base.path10_len = tmp_buf_len - 1; + if (priv->base.path10_ptr[priv->base.path10_len - 1] == '\\') { + priv->base.path10_len -= 1; + } } else { free((void*)priv->base.path10_ptr); priv->base.path10_ptr = nullptr; @@ -302,7 +305,10 @@ ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) { } rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)priv->base.path81_ptr, &tmp_buf_len); if (rc == ERROR_SUCCESS) { - priv->base.path81_len = tmp_buf_len; + priv->base.path81_len = tmp_buf_len - 1; + if (priv->base.path81_ptr[priv->base.path81_len - 1] == '\\') { + priv->base.path81_len -= 1; + } } else { free((void*)priv->base.path81_ptr); priv->base.path81_ptr = nullptr; diff --git a/std/os/file.zig b/std/os/file.zig index 52bc590f7..6998ba00d 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -139,7 +139,9 @@ pub const File = struct { const err = windows.GetLastError(); switch (err) { - windows.ERROR.FILE_NOT_FOUND => return error.NotFound, + windows.ERROR.FILE_NOT_FOUND, + windows.ERROR.PATH_NOT_FOUND, + => return error.NotFound, windows.ERROR.ACCESS_DENIED => return error.PermissionDenied, else => return os.unexpectedErrorWindows(err), }