aboutsummaryrefslogtreecommitdiff
path: root/src/windows_sdk.cpp
diff options
context:
space:
mode:
authorAndrea Orru <andrea@orru.io>2018-08-06 01:43:19 -0400
committerAndrea Orru <andrea@orru.io>2018-08-06 01:43:19 -0400
commitd2f5e57b68da0b16e5789ca19045ccbcb4ecfa8d (patch)
treee9fa3caec533a0d1e2b434868b2fde1f9240e5c8 /src/windows_sdk.cpp
parent06614b3fa09954464c2e2f32756cacedc178a282 (diff)
parent63a23e848a62d5f167f8d5478de9766cb24aa6eb (diff)
downloadzig-d2f5e57b68da0b16e5789ca19045ccbcb4ecfa8d.tar.gz
zig-d2f5e57b68da0b16e5789ca19045ccbcb4ecfa8d.zip
Merge branch 'master' into zen_stdlib
Diffstat (limited to 'src/windows_sdk.cpp')
-rw-r--r--src/windows_sdk.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/src/windows_sdk.cpp b/src/windows_sdk.cpp
new file mode 100644
index 0000000000..0f9d0fc301
--- /dev/null
+++ b/src/windows_sdk.cpp
@@ -0,0 +1,352 @@
+/*
+ * 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 - 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;
+ }
+ }
+ {
+ 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 - 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;
+ }
+ }
+
+ {
+ 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