Commit 58c5f94a99

Andrew Kelley <superjoe30@gmail.com>
2018-07-21 05:37:37
self-hosted: share C++ code for finding libc on windows
1 parent f5a67db
src/analyze.cpp
@@ -4379,7 +4379,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
 
 static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
     if (g->win_sdk == nullptr) {
-        if (os_find_windows_sdk(&g->win_sdk)) {
+        if (zig_find_windows_sdk(&g->win_sdk)) {
             fprintf(stderr, "unable to determine windows sdk path\n");
             exit(1);
         }
@@ -4499,12 +4499,11 @@ void find_libc_lib_path(CodeGen *g) {
             ZigWindowsSDK *sdk = get_windows_sdk(g);
 
             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)) {
+                if (sdk->msvc_lib_dir_ptr == nullptr) {
                     fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
                     exit(1);
                 }
-                g->msvc_lib_dir = vc_lib_dir;
+                g->msvc_lib_dir = buf_create_from_mem(sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
             }
 
             if (g->libc_lib_dir == nullptr) {
src/os.cpp
@@ -26,7 +26,6 @@
 #include <windows.h>
 #include <io.h>
 #include <fcntl.h>
-#include "windows_com.hpp"
 
 typedef SSIZE_T ssize_t;
 #else
@@ -1115,249 +1114,10 @@ void os_stderr_set_color(TermColor color) {
 #endif
 }
 
-int os_find_windows_sdk(ZigWindowsSDK **out_sdk) {
-#if defined(ZIG_OS_WINDOWS)
-    ZigWindowsSDK *result_sdk = allocate<ZigWindowsSDK>(1);
-    buf_resize(&result_sdk->path10, 0);
-    buf_resize(&result_sdk->path81, 0);
-
-    HKEY key;
-    HRESULT rc;
-    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
-    if (rc != ERROR_SUCCESS) {
-        return ErrorFileNotFound;
-    }
-
-    {
-        DWORD tmp_buf_len = MAX_PATH;
-        buf_resize(&result_sdk->path10, tmp_buf_len);
-        rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path10), &tmp_buf_len);
-        if (rc == ERROR_FILE_NOT_FOUND) {
-            buf_resize(&result_sdk->path10, 0);
-        } else {
-            buf_resize(&result_sdk->path10, tmp_buf_len);
-        }
-    }
-    {
-        DWORD tmp_buf_len = MAX_PATH;
-        buf_resize(&result_sdk->path81, tmp_buf_len);
-        rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path81), &tmp_buf_len);
-        if (rc == ERROR_FILE_NOT_FOUND) {
-            buf_resize(&result_sdk->path81, 0);
-        } else {
-            buf_resize(&result_sdk->path81, tmp_buf_len);
-        }
-    }
-
-    if (buf_len(&result_sdk->path10) != 0) {
-        Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\*", buf_ptr(&result_sdk->path10));
-
-        // enumerate files in sdk path looking for latest version
-        WIN32_FIND_DATA ffd;
-        HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
-        if (hFind == INVALID_HANDLE_VALUE) {
-            return ErrorFileNotFound;
-        }
-        int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
-        bool found_version_dir = false;
-        for (;;) {
-            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-                int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
-                sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
-                if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
-                    // Microsoft released 26624 as 10240 accidentally.
-                    // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
-                    c2 = 26624;
-                }
-                if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
-                    v0 = c0, v1 = c1, v2 = c2, v3 = c3;
-                    buf_init_from_str(&result_sdk->version10, ffd.cFileName);
-                    found_version_dir = true;
-                }
-            }
-            if (FindNextFile(hFind, &ffd) == 0) {
-                FindClose(hFind);
-                break;
-            }
-        }
-        if (!found_version_dir) {
-            buf_resize(&result_sdk->path10, 0);
-        }
-    }
-
-    if (buf_len(&result_sdk->path81) != 0) {
-        Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\winv*", buf_ptr(&result_sdk->path81));
-
-        // enumerate files in sdk path looking for latest version
-        WIN32_FIND_DATA ffd;
-        HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
-        if (hFind == INVALID_HANDLE_VALUE) {
-            return ErrorFileNotFound;
-        }
-        int v0 = 0, v1 = 0;
-        bool found_version_dir = false;
-        for (;;) {
-            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-                int c0 = 0, c1 = 0;
-                sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
-                if ((c0 > v0) || (c1 > v1)) {
-                    v0 = c0, v1 = c1;
-                    buf_init_from_str(&result_sdk->version81, ffd.cFileName);
-                    found_version_dir = true;
-                }
-            }
-            if (FindNextFile(hFind, &ffd) == 0) {
-                FindClose(hFind);
-                break;
-            }
-        }
-        if (!found_version_dir) {
-            buf_resize(&result_sdk->path81, 0);
-        }
-    }
-
-    *out_sdk = result_sdk;
-    return 0;
-#else
-    return ErrorFileNotFound;
-#endif
-}
-
-int os_get_win32_vcruntime_path(Buf* output_buf, ZigLLVM_ArchType platform_type) {
-#if defined(ZIG_OS_WINDOWS)
-    buf_resize(output_buf, 0);
-    //COM Smart Pointerse requires explicit scope
-    {
-        HRESULT rc;
-        rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
-        if (rc != S_OK) {
-            goto com_done;
-        }
-
-        //This COM class is installed when a VS2017
-        ISetupConfigurationPtr setup_config;
-        rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
-        if (rc != S_OK) {
-            goto com_done;
-        }
-
-        IEnumSetupInstancesPtr all_instances;
-        rc = setup_config->EnumInstances(&all_instances);
-        if (rc != S_OK) {
-            goto com_done;
-        }
-
-        ISetupInstance* curr_instance;
-        ULONG found_inst;
-        while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
-            BSTR bstr_inst_path;
-            rc = curr_instance->GetInstallationPath(&bstr_inst_path);
-            if (rc != S_OK) {
-                goto com_done;
-            }
-            //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
-            UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
-            ULONG tmp_path_len = bstr_path_len / 2 + 1;
-            char* conv_path = (char*)bstr_inst_path;
-            char *tmp_path = (char*)alloca(tmp_path_len);
-            memset(tmp_path, 0, tmp_path_len);
-            uint32_t c = 0;
-            for (uint32_t i = 0; i < bstr_path_len; i += 2) {
-                tmp_path[c] = conv_path[i];
-                ++c;
-                assert(c != tmp_path_len);
-            }
-
-            buf_append_str(output_buf, tmp_path);
-            buf_append_char(output_buf, '\\');
-
-            Buf* tmp_buf = buf_alloc();
-            buf_append_buf(tmp_buf, output_buf);
-            buf_append_str(tmp_buf, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
-            FILE* tools_file = fopen(buf_ptr(tmp_buf), "r");
-            if (!tools_file) {
-                goto com_done;
-            }
-            memset(tmp_path, 0, tmp_path_len);
-            fgets(tmp_path, tmp_path_len, tools_file);
-            strtok(tmp_path, " \r\n");
-            fclose(tools_file);
-            buf_appendf(output_buf, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
-            switch (platform_type) {
-            case ZigLLVM_x86:
-                buf_append_str(output_buf, "x86\\");
-                break;
-            case ZigLLVM_x86_64:
-                buf_append_str(output_buf, "x64\\");
-                break;
-            case ZigLLVM_arm:
-                buf_append_str(output_buf, "arm\\");
-                break;
-            default:
-                zig_panic("Attemped to use vcruntime for non-supported platform.");
-            }
-            buf_resize(tmp_buf, 0);
-            buf_append_buf(tmp_buf, output_buf);
-            buf_append_str(tmp_buf, "vcruntime.lib");
-
-            if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
-                return 0;
-            }
-        }
-    }
-
-com_done:;
-    HKEY key;
-    HRESULT rc;
-    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
-    if (rc != ERROR_SUCCESS) {
-        return ErrorFileNotFound;
-    }
-
-    DWORD dw_type = 0;
-    DWORD cb_data = 0;
-    rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
-    if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
-        return ErrorFileNotFound;
-    }
-
-    Buf* tmp_buf = buf_alloc_fixed(cb_data);
-    RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)buf_ptr(tmp_buf), &cb_data);
-    //RegQueryValueExA returns the length of the string INCLUDING the null terminator
-    buf_resize(tmp_buf, cb_data-1);
-    buf_append_str(tmp_buf, "VC\\Lib\\");
-    switch (platform_type) {
-    case ZigLLVM_x86:
-        //x86 is in the root of the Lib folder
-        break;
-    case ZigLLVM_x86_64:
-        buf_append_str(tmp_buf, "amd64\\");
-        break;
-    case ZigLLVM_arm:
-        buf_append_str(tmp_buf, "arm\\");
-        break;
-    default:
-        zig_panic("Attemped to use vcruntime for non-supported platform.");
-    }
-
-    buf_append_buf(output_buf, tmp_buf);
-    buf_append_str(tmp_buf, "vcruntime.lib");
-
-    if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
-        return 0;
-    } else {
-        buf_resize(output_buf, 0);
-        return ErrorFileNotFound;
-    }
-#else
-    return ErrorFileNotFound;
-#endif
-}
-
 int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
 #if defined(ZIG_OS_WINDOWS)
     buf_resize(output_buf, 0);
-    buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
+    buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
     switch (platform_type) {
     case ZigLLVM_x86:
         buf_append_str(output_buf, "x86\\");
@@ -1389,7 +1149,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
 int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
 #if defined(ZIG_OS_WINDOWS)
     buf_resize(output_buf, 0);
-    buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
+    buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
     if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
         return 0;
     }
@@ -1406,7 +1166,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
 #if defined(ZIG_OS_WINDOWS)
     {
         buf_resize(output_buf, 0);
-        buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));
+        buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
         switch (platform_type) {
         case ZigLLVM_x86:
             buf_append_str(output_buf, "x86\\");
@@ -1429,7 +1189,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
     }
     {
         buf_resize(output_buf, 0);
-        buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path81), buf_ptr(&sdk->version81));
+        buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
         switch (platform_type) {
         case ZigLLVM_x86:
             buf_append_str(output_buf, "x86\\");
src/os.hpp
@@ -12,6 +12,7 @@
 #include "buffer.hpp"
 #include "error.hpp"
 #include "zig_llvm.h"
+#include "windows_sdk.h"
 
 #include <stdio.h>
 #include <inttypes.h>
@@ -79,15 +80,6 @@ bool os_is_sep(uint8_t c);
 
 int os_self_exe_path(Buf *out_path);
 
-struct ZigWindowsSDK {
-    Buf path10;
-    Buf version10;
-    Buf path81;
-    Buf version81;
-};
-
-int os_find_windows_sdk(ZigWindowsSDK **out_sdk);
-int os_get_win32_vcruntime_path(Buf *output_buf, ZigLLVM_ArchType platform_type);
 int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
 int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
 int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
src/windows_sdk.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2018 Andrew Kelley
+ *
+ * This file is part of zig, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#include "windows_sdk.h"
+
+#if defined(_WIN32)
+
+#include "windows_com.hpp"
+#include <inttypes.h>
+#include <assert.h>
+
+struct ZigWindowsSDKPrivate {
+    ZigWindowsSDK base;
+};
+
+enum NativeArch {
+    NativeArchArm,
+    NativeArchi386,
+    NativeArchx86_64,
+};
+
+#if defined(_M_ARM) || defined(__arm_)
+static const NativeArch native_arch = NativeArchArm;
+#endif
+#if defined(_M_IX86) || defined(__i386__)
+static const NativeArch native_arch = NativeArchi386;
+#endif
+#if defined(_M_X64) || defined(__x86_64__)
+static const NativeArch native_arch = NativeArchx86_64;
+#endif
+
+void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {
+    if (sdk == nullptr) {
+        return;
+    }
+    free((void*)sdk->path10_ptr);
+    free((void*)sdk->version10_ptr);
+    free((void*)sdk->path81_ptr);
+    free((void*)sdk->version81_ptr);
+    free((void*)sdk->msvc_lib_dir_ptr);
+}
+
+static ZigFindWindowsSdkError find_msvc_lib_dir(ZigWindowsSDKPrivate *priv) {
+    //COM Smart Pointers requires explicit scope
+    {
+        HRESULT rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+        if (rc != S_OK && rc != S_FALSE) {
+            goto com_done;
+        }
+
+        //This COM class is installed when a VS2017
+        ISetupConfigurationPtr setup_config;
+        rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
+        if (rc != S_OK) {
+            goto com_done;
+        }
+
+        IEnumSetupInstancesPtr all_instances;
+        rc = setup_config->EnumInstances(&all_instances);
+        if (rc != S_OK) {
+            goto com_done;
+        }
+
+        ISetupInstance* curr_instance;
+        ULONG found_inst;
+        while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
+            BSTR bstr_inst_path;
+            rc = curr_instance->GetInstallationPath(&bstr_inst_path);
+            if (rc != S_OK) {
+                goto com_done;
+            }
+            //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
+            //TODO call an actual function to do this
+            UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
+            ULONG tmp_path_len = bstr_path_len / 2 + 1;
+            char* conv_path = (char*)bstr_inst_path;
+            // TODO don't use alloca
+            char *tmp_path = (char*)alloca(tmp_path_len);
+            memset(tmp_path, 0, tmp_path_len);
+            uint32_t c = 0;
+            for (uint32_t i = 0; i < bstr_path_len; i += 2) {
+                tmp_path[c] = conv_path[i];
+                ++c;
+                assert(c != tmp_path_len);
+            }
+            char output_path[4096];
+            output_path[0] = 0;
+            char *out_append_ptr = output_path;
+
+            out_append_ptr += sprintf(out_append_ptr, "%s\\", tmp_path);
+
+            char tmp_buf[4096];
+            sprintf(tmp_buf, "%s%s", output_path, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
+            FILE* tools_file = fopen(tmp_buf, "rb");
+            if (!tools_file) {
+                goto com_done;
+            }
+            memset(tmp_path, 0, tmp_path_len);
+            fgets(tmp_path, tmp_path_len, tools_file);
+            strtok(tmp_path, " \r\n");
+            fclose(tools_file);
+            out_append_ptr += sprintf(out_append_ptr, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
+            switch (native_arch) {
+            case NativeArchi386:
+                out_append_ptr += sprintf(out_append_ptr, "x86\\");
+                break;
+            case NativeArchx86_64:
+                out_append_ptr += sprintf(out_append_ptr, "x64\\");
+                break;
+            case NativeArchArm:
+                out_append_ptr += sprintf(out_append_ptr, "arm\\");
+                break;
+            }
+            sprintf(tmp_buf, "%s%s", output_path, "vcruntime.lib");
+
+            if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
+                priv->base.msvc_lib_dir_ptr = strdup(output_path);
+                if (priv->base.msvc_lib_dir_ptr == nullptr) {
+                    return ZigFindWindowsSdkErrorOutOfMemory;
+                }
+                priv->base.msvc_lib_dir_len = strlen(priv->base.msvc_lib_dir_ptr);
+                return ZigFindWindowsSdkErrorNone;
+            }
+        }
+    }
+
+com_done:;
+    HKEY key;
+    HRESULT rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0,
+        KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
+    if (rc != ERROR_SUCCESS) {
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+
+    DWORD dw_type = 0;
+    DWORD cb_data = 0;
+    rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
+    if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+
+    char tmp_buf[4096];
+
+    RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)tmp_buf, &cb_data);
+    // RegQueryValueExA returns the length of the string INCLUDING the null terminator
+    char *tmp_buf_append_ptr = tmp_buf + (cb_data - 1);
+    tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "VC\\Lib\\");
+    switch (native_arch) {
+    case NativeArchi386:
+        //x86 is in the root of the Lib folder
+        break;
+    case NativeArchx86_64:
+        tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "amd64\\");
+        break;
+    case NativeArchArm:
+        tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "arm\\");
+        break;
+    }
+
+    char *output_path = strdup(tmp_buf);
+    if (output_path == nullptr) {
+        return ZigFindWindowsSdkErrorOutOfMemory;
+    }
+
+    tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "vcruntime.lib");
+
+    if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
+        priv->base.msvc_lib_dir_ptr = output_path;
+        priv->base.msvc_lib_dir_len = strlen(output_path);
+        return ZigFindWindowsSdkErrorNone;
+    } else {
+        free(output_path);
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+}
+
+static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) {
+    if (priv->base.path10_ptr == nullptr)
+        return ZigFindWindowsSdkErrorNone;
+
+    char sdk_lib_dir[4096];
+    int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\*", priv->base.path10_ptr);
+    if (n < 0 || n >= 4096) {
+        return ZigFindWindowsSdkErrorPathTooLong;
+    }
+
+    // enumerate files in sdk path looking for latest version
+    WIN32_FIND_DATA ffd;
+    HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+    int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
+    for (;;) {
+        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
+            sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
+            if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
+                // Microsoft released 26624 as 10240 accidentally.
+                // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
+                c2 = 26624;
+            }
+            if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
+                v0 = c0, v1 = c1, v2 = c2, v3 = c3;
+                free((void*)priv->base.version10_ptr);
+                priv->base.version10_ptr = strdup(ffd.cFileName);
+                if (priv->base.version10_ptr == nullptr) {
+                    FindClose(hFind);
+                    return ZigFindWindowsSdkErrorOutOfMemory;
+                }
+            }
+        }
+        if (FindNextFile(hFind, &ffd) == 0) {
+            FindClose(hFind);
+            break;
+        }
+    }
+    priv->base.version10_len = strlen(priv->base.version10_ptr);
+    return ZigFindWindowsSdkErrorNone;
+}
+
+static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) {
+    if (priv->base.path81_ptr == nullptr)
+        return ZigFindWindowsSdkErrorNone;
+
+    char sdk_lib_dir[4096];
+    int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\winv*", priv->base.path81_ptr);
+    if (n < 0 || n >= 4096) {
+        return ZigFindWindowsSdkErrorPathTooLong;
+    }
+
+    // enumerate files in sdk path looking for latest version
+    WIN32_FIND_DATA ffd;
+    HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+    int v0 = 0, v1 = 0;
+    for (;;) {
+        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            int c0 = 0, c1 = 0;
+            sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
+            if ((c0 > v0) || (c1 > v1)) {
+                v0 = c0, v1 = c1;
+                free((void*)priv->base.version81_ptr);
+                priv->base.version81_ptr = strdup(ffd.cFileName);
+                if (priv->base.version81_ptr == nullptr) {
+                    FindClose(hFind);
+                    return ZigFindWindowsSdkErrorOutOfMemory;
+                }
+            }
+        }
+        if (FindNextFile(hFind, &ffd) == 0) {
+            FindClose(hFind);
+            break;
+        }
+    }
+    priv->base.version81_len = strlen(priv->base.version81_ptr);
+    return ZigFindWindowsSdkErrorNone;
+}
+
+ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
+    ZigWindowsSDKPrivate *priv = (ZigWindowsSDKPrivate*)calloc(1, sizeof(ZigWindowsSDKPrivate));
+    if (priv == nullptr) {
+        return ZigFindWindowsSdkErrorOutOfMemory;
+    }
+
+    HKEY key;
+    HRESULT rc;
+    rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0,
+        KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
+    if (rc != ERROR_SUCCESS) {
+        zig_free_windows_sdk(&priv->base);
+        return ZigFindWindowsSdkErrorNotFound;
+    }
+
+    {
+        DWORD tmp_buf_len = MAX_PATH;
+        priv->base.path10_ptr = (const char *)calloc(tmp_buf_len, 1);
+        if (priv->base.path10_ptr == nullptr) {
+            zig_free_windows_sdk(&priv->base);
+            return ZigFindWindowsSdkErrorOutOfMemory;
+        }
+        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;
+        } else {
+            free((void*)priv->base.path10_ptr);
+            priv->base.path10_ptr = nullptr;
+        }
+    }
+    {
+        DWORD tmp_buf_len = MAX_PATH;
+        priv->base.path81_ptr = (const char *)calloc(tmp_buf_len, 1);
+        if (priv->base.path81_ptr == nullptr) {
+            zig_free_windows_sdk(&priv->base);
+            return ZigFindWindowsSdkErrorOutOfMemory;
+        }
+        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;
+        } else {
+            free((void*)priv->base.path81_ptr);
+            priv->base.path81_ptr = nullptr;
+        }
+    }
+
+    {
+        ZigFindWindowsSdkError err = find_10_version(priv);
+        if (err == ZigFindWindowsSdkErrorOutOfMemory) {
+            zig_free_windows_sdk(&priv->base);
+            return err;
+        }
+    }
+    {
+        ZigFindWindowsSdkError err = find_81_version(priv);
+        if (err == ZigFindWindowsSdkErrorOutOfMemory) {
+            zig_free_windows_sdk(&priv->base);
+            return err;
+        }
+    }
+
+    {
+        ZigFindWindowsSdkError err = find_msvc_lib_dir(priv);
+        if (err == ZigFindWindowsSdkErrorOutOfMemory) {
+            zig_free_windows_sdk(&priv->base);
+            return err;
+        }
+    }
+
+    *out_sdk = &priv->base;
+    return ZigFindWindowsSdkErrorNone;
+}
+
+#else
+
+void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {}
+ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
+    return ZigFindWindowsSdkErrorNotFound;
+}
+
+#endif
src/windows_sdk.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Andrew Kelley
+ *
+ * This file is part of zig, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#ifndef ZIG_WINDOWS_SDK_H
+#define ZIG_WINDOWS_SDK_H
+
+#ifdef __cplusplus
+#define ZIG_EXTERN_C extern "C"
+#else
+#define ZIG_EXTERN_C
+#endif
+
+struct ZigWindowsSDK {
+    const char *path10_ptr;
+    size_t path10_len;
+
+    const char *version10_ptr;
+    size_t version10_len;
+
+    const char *path81_ptr;
+    size_t path81_len;
+
+    const char *version81_ptr;
+    size_t version81_len;
+
+    const char *msvc_lib_dir_ptr;
+    size_t msvc_lib_dir_len;
+};
+
+enum ZigFindWindowsSdkError {
+    ZigFindWindowsSdkErrorNone,
+    ZigFindWindowsSdkErrorOutOfMemory,
+    ZigFindWindowsSdkErrorNotFound,
+    ZigFindWindowsSdkErrorPathTooLong,
+};
+
+ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);
+
+ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);
+
+#endif
src-self-hosted/c.zig
@@ -4,4 +4,5 @@ pub use @cImport({
     @cInclude("inttypes.h");
     @cInclude("config.h");
     @cInclude("zig_llvm.h");
+    @cInclude("windows_sdk.h");
 });
src-self-hosted/libc_installation.zig
@@ -2,6 +2,7 @@ const std = @import("std");
 const builtin = @import("builtin");
 const event = std.event;
 const Target = @import("target.zig").Target;
+const c = @import("c.zig");
 
 /// See the render function implementation for documentation of the fields.
 pub const LibCInstallation = struct {
@@ -122,7 +123,7 @@ pub const LibCInstallation = struct {
             \\# Only needed when targeting Windows.
             \\kernel32_lib_dir={}
             \\
-            \\# The full path to the dynamic linker.
+            \\# The full path to the dynamic linker, on the target system.
             \\# Only needed when targeting Linux.
             \\dynamic_linker_path={}
             \\
@@ -143,10 +144,24 @@ pub const LibCInstallation = struct {
         errdefer group.cancelAll();
         switch (builtin.os) {
             builtin.Os.windows => {
-                try group.call(findNativeIncludeDirWindows, self, loop);
-                try group.call(findNativeLibDirWindows, self, loop);
-                try group.call(findNativeMsvcLibDir, self, loop);
-                try group.call(findNativeKernel32LibDir, self, loop);
+                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));
+
+                        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);
+                    },
+                    c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory,
+                    c.ZigFindWindowsSdkError.NotFound => return error.NotFound,
+                    c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,
+                }
             },
             builtin.Os.linux => {
                 try group.call(findNativeIncludeDirLinux, self, loop);
std/os/windows/advapi32.zig
@@ -0,0 +1,30 @@
+use @import("index.zig");
+
+pub const PROV_RSA_FULL = 1;
+
+pub const REGSAM = ACCESS_MASK;
+pub const ACCESS_MASK = DWORD;
+pub const PHKEY = &HKEY;
+pub const HKEY = &HKEY__;
+pub const HKEY__ = extern struct {
+    unused: c_int,
+};
+pub const LSTATUS = LONG;
+
+pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
+    phProv: *HCRYPTPROV,
+    pszContainer: ?LPCSTR,
+    pszProvider: ?LPCSTR,
+    dwProvType: DWORD,
+    dwFlags: DWORD,
+) BOOL;
+
+pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
+
+pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
+
+pub extern "advapi32" stdcallcc fn RegOpenKeyExW(hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM,
+    phkResult: &HKEY,) LSTATUS;
+
+pub extern "advapi32" stdcallcc fn RegQueryValueExW(hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,
+    lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,) LSTATUS;
std/os/windows/index.zig
@@ -1,190 +1,19 @@
 const std = @import("../../index.zig");
 const assert = std.debug.assert;
+
+pub use @import("advapi32.zig");
+pub use @import("kernel32.zig");
+pub use @import("ole32.zig");
+pub use @import("shell32.zig");
+pub use @import("shlwapi.zig");
+pub use @import("user32.zig");
+
 test "import" {
     _ = @import("util.zig");
 }
 
 pub const ERROR = @import("error.zig");
 
-pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
-    phProv: *HCRYPTPROV,
-    pszContainer: ?LPCSTR,
-    pszProvider: ?LPCSTR,
-    dwProvType: DWORD,
-    dwFlags: DWORD,
-) BOOL;
-
-pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
-
-pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
-
-pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
-
-pub extern "kernel32" stdcallcc fn CreateDirectoryA(
-    lpPathName: LPCSTR,
-    lpSecurityAttributes: ?*SECURITY_ATTRIBUTES,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn CreateFileA(
-    lpFileName: LPCSTR,
-    dwDesiredAccess: DWORD,
-    dwShareMode: DWORD,
-    lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
-    dwCreationDisposition: DWORD,
-    dwFlagsAndAttributes: DWORD,
-    hTemplateFile: ?HANDLE,
-) HANDLE;
-
-pub extern "kernel32" stdcallcc fn CreatePipe(
-    hReadPipe: *HANDLE,
-    hWritePipe: *HANDLE,
-    lpPipeAttributes: *const SECURITY_ATTRIBUTES,
-    nSize: DWORD,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn CreateProcessA(
-    lpApplicationName: ?LPCSTR,
-    lpCommandLine: LPSTR,
-    lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
-    lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
-    bInheritHandles: BOOL,
-    dwCreationFlags: DWORD,
-    lpEnvironment: ?*c_void,
-    lpCurrentDirectory: ?LPCSTR,
-    lpStartupInfo: *STARTUPINFOA,
-    lpProcessInformation: *PROCESS_INFORMATION,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(
-    lpSymlinkFileName: LPCSTR,
-    lpTargetFileName: LPCSTR,
-    dwFlags: DWORD,
-) BOOLEAN;
-
-pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
-
-pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
-
-pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
-
-pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
-
-pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
-pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
-pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
-
-pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
-
-pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
-
-pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
-
-pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
-
-pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
-
-pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
-
-pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
-
-pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
-    in_hFile: HANDLE,
-    in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
-    out_lpFileInformation: *c_void,
-    in_dwBufferSize: DWORD,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
-    hFile: HANDLE,
-    lpszFilePath: LPSTR,
-    cchFilePath: DWORD,
-    dwFlags: DWORD,
-) DWORD;
-
-pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
-pub extern "kernel32" stdcallcc fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) void;
-pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
-
-pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
-pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
-pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
-pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
-pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
-pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
-pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
-
-pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
-
-pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
-
-pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
-
-pub extern "kernel32" stdcallcc fn MoveFileExA(
-    lpExistingFileName: LPCSTR,
-    lpNewFileName: LPCSTR,
-    dwFlags: DWORD,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn PostQueuedCompletionStatus(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ?*OVERLAPPED) BOOL;
-
-pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *LARGE_INTEGER) BOOL;
-
-pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
-
-pub extern "kernel32" stdcallcc fn ReadFile(
-    in_hFile: HANDLE,
-    out_lpBuffer: *c_void,
-    in_nNumberOfBytesToRead: DWORD,
-    out_lpNumberOfBytesRead: *DWORD,
-    in_out_lpOverlapped: ?*OVERLAPPED,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
-
-pub extern "kernel32" stdcallcc fn SetFilePointerEx(
-    in_fFile: HANDLE,
-    in_liDistanceToMove: LARGE_INTEGER,
-    out_opt_ldNewFilePointer: ?*LARGE_INTEGER,
-    in_dwMoveMethod: DWORD,
-) BOOL;
-
-pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
-
-pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
-
-pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
-
-pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
-
-pub extern "kernel32" stdcallcc fn WriteFile(
-    in_hFile: HANDLE,
-    in_lpBuffer: *const c_void,
-    in_nNumberOfBytesToWrite: DWORD,
-    out_lpNumberOfBytesWritten: ?*DWORD,
-    in_out_lpOverlapped: ?*OVERLAPPED,
-) BOOL;
-
-//TODO: call unicode versions instead of relying on ANSI code page
-pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
-
-pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
-
-pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
-
-pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
-
-pub const PROV_RSA_FULL = 1;
-
 pub const BOOL = c_int;
 pub const BOOLEAN = BYTE;
 pub const BYTE = u8;
@@ -206,6 +35,7 @@ pub const LPSTR = [*]CHAR;
 pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
 pub const LPVOID = *c_void;
 pub const LPWSTR = [*]WCHAR;
+pub const LPCWSTR = [*]const WCHAR;
 pub const PVOID = *c_void;
 pub const PWSTR = [*]WCHAR;
 pub const SIZE_T = usize;
@@ -442,10 +272,6 @@ pub const SYSTEM_INFO = extern struct {
     wProcessorRevision: WORD,
 };
 
-pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
-
-pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
-
 pub const HRESULT = c_long;
 
 pub const KNOWNFOLDERID = GUID;
std/os/windows/kernel32.zig
@@ -0,0 +1,162 @@
+use @import("index.zig");
+
+pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
+
+pub extern "kernel32" stdcallcc fn CreateDirectoryA(
+    lpPathName: LPCSTR,
+    lpSecurityAttributes: ?*SECURITY_ATTRIBUTES,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn CreateFileA(
+    lpFileName: LPCSTR,
+    dwDesiredAccess: DWORD,
+    dwShareMode: DWORD,
+    lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
+    dwCreationDisposition: DWORD,
+    dwFlagsAndAttributes: DWORD,
+    hTemplateFile: ?HANDLE,
+) HANDLE;
+
+pub extern "kernel32" stdcallcc fn CreatePipe(
+    hReadPipe: *HANDLE,
+    hWritePipe: *HANDLE,
+    lpPipeAttributes: *const SECURITY_ATTRIBUTES,
+    nSize: DWORD,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn CreateProcessA(
+    lpApplicationName: ?LPCSTR,
+    lpCommandLine: LPSTR,
+    lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
+    lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
+    bInheritHandles: BOOL,
+    dwCreationFlags: DWORD,
+    lpEnvironment: ?*c_void,
+    lpCurrentDirectory: ?LPCSTR,
+    lpStartupInfo: *STARTUPINFOA,
+    lpProcessInformation: *PROCESS_INFORMATION,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(
+    lpSymlinkFileName: LPCSTR,
+    lpTargetFileName: LPCSTR,
+    dwFlags: DWORD,
+) BOOLEAN;
+
+pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
+
+pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
+
+pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
+
+pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
+
+pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
+pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
+pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
+
+pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
+
+pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
+
+pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
+
+pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
+
+pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
+
+pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
+
+pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
+
+pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
+    in_hFile: HANDLE,
+    in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
+    out_lpFileInformation: *c_void,
+    in_dwBufferSize: DWORD,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
+    hFile: HANDLE,
+    lpszFilePath: LPSTR,
+    cchFilePath: DWORD,
+    dwFlags: DWORD,
+) DWORD;
+
+pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
+pub extern "kernel32" stdcallcc fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) void;
+pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
+
+pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
+pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
+pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
+pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
+pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
+pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
+pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
+
+pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
+
+pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
+
+pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
+
+pub extern "kernel32" stdcallcc fn MoveFileExA(
+    lpExistingFileName: LPCSTR,
+    lpNewFileName: LPCSTR,
+    dwFlags: DWORD,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn PostQueuedCompletionStatus(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ?*OVERLAPPED) BOOL;
+
+pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *LARGE_INTEGER) BOOL;
+
+pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
+
+pub extern "kernel32" stdcallcc fn ReadFile(
+    in_hFile: HANDLE,
+    out_lpBuffer: *c_void,
+    in_nNumberOfBytesToRead: DWORD,
+    out_lpNumberOfBytesRead: *DWORD,
+    in_out_lpOverlapped: ?*OVERLAPPED,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
+
+pub extern "kernel32" stdcallcc fn SetFilePointerEx(
+    in_fFile: HANDLE,
+    in_liDistanceToMove: LARGE_INTEGER,
+    out_opt_ldNewFilePointer: ?*LARGE_INTEGER,
+    in_dwMoveMethod: DWORD,
+) BOOL;
+
+pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
+
+pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
+
+pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
+
+pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
+
+pub extern "kernel32" stdcallcc fn WriteFile(
+    in_hFile: HANDLE,
+    in_lpBuffer: *const c_void,
+    in_nNumberOfBytesToWrite: DWORD,
+    out_lpNumberOfBytesWritten: ?*DWORD,
+    in_out_lpOverlapped: ?*OVERLAPPED,
+) BOOL;
+
+//TODO: call unicode versions instead of relying on ANSI code page
+pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
+
+pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
std/os/windows/ole32.zig
@@ -0,0 +1,18 @@
+use @import("index.zig");
+
+pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
+pub extern "ole32.dll" stdcallcc fn CoUninitialize() void;
+pub extern "ole32.dll" stdcallcc fn CoGetCurrentProcess() DWORD;
+pub extern "ole32.dll" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
+
+
+pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
+pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
+pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
+pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
+pub const COINIT = extern enum {
+    COINIT_APARTMENTTHREADED = 2,
+    COINIT_MULTITHREADED = 0,
+    COINIT_DISABLE_OLE1DDE = 4,
+    COINIT_SPEED_OVER_MEMORY = 8,
+};
std/os/windows/shell32.zig
@@ -0,0 +1,4 @@
+use @import("index.zig");
+
+pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
+
std/os/windows/shlwapi.zig
@@ -0,0 +1,4 @@
+use @import("index.zig");
+
+pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
+
std/os/windows/user32.zig
@@ -0,0 +1,4 @@
+use @import("index.zig");
+
+pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
+
CMakeLists.txt
@@ -426,6 +426,7 @@ set(ZIG_SOURCES
 )
 set(ZIG_CPP_SOURCES
     "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
+    "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
 )
 
 set(ZIG_STD_FILES
@@ -567,8 +568,14 @@ set(ZIG_STD_FILES
     "os/linux/x86_64.zig"
     "os/path.zig"
     "os/time.zig"
+    "os/windows/advapi32.zig"
     "os/windows/error.zig"
     "os/windows/index.zig"
+    "os/windows/kernel32.zig"
+    "os/windows/ole32.zig"
+    "os/windows/shell32.zig"
+    "os/windows/shlwapi.zig"
+    "os/windows/user32.zig"
     "os/windows/util.zig"
     "os/zen.zig"
     "rand/index.zig"