diff --git a/.gitignore b/.gitignore index bf6826b824..fb3ac3fec3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ *.exe *.o .*.c + +*.obj + +*.pdb diff --git a/compiler/msvc_win.v b/compiler/msvc_win.v index 715536c9dc..71f11201b9 100644 --- a/compiler/msvc_win.v +++ b/compiler/msvc_win.v @@ -32,25 +32,24 @@ struct MsvcResult { struct FindResult { sdk_ver int - windows_sdk_root byteptr - windows_sdk_um_library_path byteptr - windows_sdk_ucrt_library_path byteptr - vs_exe_path byteptr - vs_library_path byteptr + windows_sdk_root *u16 + windows_sdk_um_library_path *u16 + windows_sdk_ucrt_library_path *u16 + vs_exe_path *u16 + vs_library_path *u16 } fn C.find_visual_studio_and_windows_sdk() *FindResult -fn C.wide_string_to_narrow_temp(byteptr) byteptr fn find_msvc() *MsvcResult { $if windows { r := C.find_visual_studio_and_windows_sdk() - windows_sdk_root := tos_clone(C.wide_string_to_narrow_temp(r.windows_sdk_root)) - ucrt_lib_folder := tos_clone(C.wide_string_to_narrow_temp(r.windows_sdk_ucrt_library_path)) - um_lib_folder := tos_clone(C.wide_string_to_narrow_temp(r.windows_sdk_um_library_path)) - vs_lib_folder := tos_clone(C.wide_string_to_narrow_temp(r.vs_library_path)) - exe_folder := tos_clone(C.wide_string_to_narrow_temp(r.vs_exe_path)) + windows_sdk_root := string_from_wide(r.windows_sdk_root) + ucrt_lib_folder := string_from_wide(r.windows_sdk_ucrt_library_path) + um_lib_folder := string_from_wide(r.windows_sdk_um_library_path) + vs_lib_folder := string_from_wide(r.vs_library_path) + exe_folder := string_from_wide(r.vs_exe_path) mut ucrt_include_folder := ucrt_lib_folder.replace('Lib', 'Include') mut vs_include_folder := vs_lib_folder.replace('lib', 'include') @@ -88,7 +87,7 @@ fn find_msvc() *MsvcResult { pub fn cc_msvc(v *V) { r := find_msvc() - mut a := ['-w', '/volatile:ms'] // arguments for the C compiler + mut a := ['-w', '/volatile:ms', '/D_UNICODE', '/DUNICODE'] // arguments for the C compiler // cl.exe is stupid so these are in a different order to the ones below! @@ -274,6 +273,6 @@ fn build_thirdparty_obj_file_with_msvc(flag string) { println('$cfiles') - res := os.exec('""$msvc.exe_path\\cl.exe" /volatile:ms /Z7 $include_string /c $cfiles /Fo"$obj_path""') + res := os.exec('""$msvc.exe_path\\cl.exe" /volatile:ms /Z7 $include_string /c $cfiles /Fo"$obj_path" /D_UNICODE /DUNICODE"') println(res) } \ No newline at end of file diff --git a/thirdparty/microsoft_craziness/microsoft_craziness.c b/thirdparty/microsoft_craziness/microsoft_craziness.c index 68d41288fb..22e83bea81 100644 --- a/thirdparty/microsoft_craziness/microsoft_craziness.c +++ b/thirdparty/microsoft_craziness/microsoft_craziness.c @@ -1,24 +1,3 @@ #define MICROSOFT_CRAZINESS_IMPLEMENTATION -#include "microsoft_craziness.h" - -#ifdef _WIN32 - -// Never hang around to a pointer from this function -// This is not thread safe -char *wide_string_to_narrow_temp(wchar_t *wc) { - static char buffer[10000][10]; - static int counter = 0; - - char *cur_buffer = buffer[counter++]; - - int len = wcslen(wc); - int c = wcstombs(cur_buffer, wc, len); - cur_buffer[c] = 0; - - // something assert len == c - - return cur_buffer; -} - -#endif \ No newline at end of file +#include "microsoft_craziness.h" \ No newline at end of file diff --git a/thirdparty/microsoft_craziness/microsoft_craziness.h b/thirdparty/microsoft_craziness/microsoft_craziness.h index 02f1d6673f..cbb1933394 100644 --- a/thirdparty/microsoft_craziness/microsoft_craziness.h +++ b/thirdparty/microsoft_craziness/microsoft_craziness.h @@ -338,6 +338,7 @@ wchar_t *find_windows_kit_root_with_key(HKEY key, wchar_t *version) { DWORD length = required_length + 2; // The +2 is for the maybe optional zero later on. // Probably we are over-allocating. + wchar_t *value = (wchar_t *)malloc(length); if (!value) return NULL; @@ -350,8 +351,8 @@ wchar_t *find_windows_kit_root_with_key(HKEY key, wchar_t *version) { // The documentation says that if the string for some reason was not stored // with zero-termination, we need to manually terminate it. Sigh!! - if (value[length]) { - value[length + 1] = 0; + if (value[required_length / 2 - 1]) { + value[required_length / 2] = 0; } return value; @@ -521,6 +522,13 @@ bool find_visual_studio_2017_by_fighting_through_microsoft_craziness( if (!instances) return false; + // SetupInstance will return the installations in the order they were made + // - this results in 2017 being got before 2019 and we dont want this + // so get all the installations first, parse the versions and pick the best + BSTR best_path = NULL; + Version_Data best_version; + best_version.best_name = NULL; + bool found_visual_studio_2017 = false; while (1) { ULONG found = 0; @@ -529,81 +537,95 @@ bool find_visual_studio_2017_by_fighting_through_microsoft_craziness( if (hr != S_OK) break; + BSTR vs_version; + hr = CALL_STDMETHOD(instance, GetInstallationVersion, &vs_version); + + win10_best(vs_version, vs_version, &best_version); + BSTR bstr_inst_path; hr = CALL_STDMETHOD(instance, GetInstallationPath, &bstr_inst_path); CALL_STDMETHOD_(instance, Release); if (hr != S_OK) continue; - wchar_t *tools_filename = concat2( - bstr_inst_path, - L"\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); - SysFreeString(bstr_inst_path); - - FILE *f; - errno_t open_result = _wfopen_s(&f, tools_filename, L"rt"); - free(tools_filename); - if (open_result != 0) - continue; - if (!f) + // Do this here to get instance->Release() called + if (lstrcmpW(best_version.best_name, vs_version)) continue; - LARGE_INTEGER tools_file_size; - HANDLE file_handle = (HANDLE)_get_osfhandle(_fileno(f)); - BOOL success = GetFileSizeEx(file_handle, &tools_file_size); - if (!success) { - fclose(f); - continue; - } - - uint64_t version_bytes = - (tools_file_size.QuadPart + 1) * - 2; // Warning: This multiplication by 2 presumes there is no - // variable-length encoding in the wchars (wacky characters in the - // file could betray this expectation). - wchar_t *version = (wchar_t *)malloc(version_bytes); - - wchar_t *read_result = fgetws(version, version_bytes, f); - fclose(f); - if (!read_result) - continue; - - wchar_t *version_tail = wcschr(version, '\n'); - if (version_tail) - *version_tail = 0; // Stomp the data, because nobody cares about it. - - wchar_t *library_path = - concat4(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x64"); - wchar_t *library_file = - concat2(library_path, - L"\\vcruntime.lib"); // @Speed: Could have library_path point to - // this string, with a smaller count, to - // save on memory flailing! - - if (os_file_exists(library_file)) { - wchar_t *link_exe_path = concat4(bstr_inst_path, L"\\VC\\Tools\\MSVC\\", - version, L"\\bin\\Hostx64\\x64"); - free(version); - - result->vs_exe_path = link_exe_path; - result->vs_library_path = library_path; - found_visual_studio_2017 = true; - break; - } - - free(version); - - /* - Ryan Saunderson said: - "Clang uses the 'SetupInstance->GetInstallationVersion' / - ISetupHelper->ParseVersion to find the newest version and then reads the - tools file to define the tools path - which is definitely better than - what i did." - - So... @Incomplete: Should probably pick the newest version... - */ + best_path = bstr_inst_path; } + if (best_path == NULL) + goto failed; + + // result->vs_root_path = _wcsdup(best_path); + + wchar_t *tools_filename = + concat2(best_path, + L"\\VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt"); + + FILE *f; + errno_t open_result = _wfopen_s(&f, tools_filename, L"rt"); + free(tools_filename); + if (open_result != 0) + return false; + if (!f) + return false; + + LARGE_INTEGER tools_file_size; + HANDLE file_handle = (HANDLE)_get_osfhandle(_fileno(f)); + BOOL success = GetFileSizeEx(file_handle, &tools_file_size); + if (!success) { + fclose(f); + return false; + } + + uint64_t version_bytes = + (tools_file_size.QuadPart + 1) * + 2; // Warning: This multiplication by 2 presumes there is no + // variable-length encoding in the wchars (wacky characters in the file + // could betray this expectation). + wchar_t *version = (wchar_t *)malloc(version_bytes); + + wchar_t *read_result = fgetws(version, version_bytes, f); + fclose(f); + if (!read_result) + return false; + + wchar_t *version_tail = wcschr(version, '\n'); + if (version_tail) + *version_tail = 0; // Stomp the data, because nobody cares about it. + + wchar_t *library_path = + concat4(best_path, L"\\VC\\Tools\\MSVC\\", version, L"\\lib\\x64"); + wchar_t *library_file = concat2( + library_path, L"\\vcruntime.lib"); // @Speed: Could have library_path + // point to this string, with a smaller + // count, to save on memory flailing! + + if (os_file_exists(library_file)) { + wchar_t *link_exe_path = concat4(best_path, L"\\VC\\Tools\\MSVC\\", version, + L"\\bin\\Hostx64\\x64"); + + result->vs_exe_path = link_exe_path; + result->vs_library_path = library_path; + + found_visual_studio_2017 = true; + } + + free(version); + SysFreeString(best_path); + + /* + Ryan Saunderson said: + "Clang uses the 'SetupInstance->GetInstallationVersion' / + ISetupHelper->ParseVersion to find the newest version and then reads the + tools file to define the tools path - which is definitely better than what + i did." So... @Incomplete: Should probably pick the newest version... + */ + +failed: + CALL_STDMETHOD_(instances, Release); return found_visual_studio_2017; } diff --git a/vlib/os/os.v b/vlib/os/os.v index b2c97d5684..f51bbbf10f 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -703,9 +703,9 @@ pub fn chdir(path string) { pub fn getwd() string { $if windows { - max := 512 // MAX_PATH * sizeof(wchar_t) + max := 1024 // MAX_PATH * sizeof(wchar_t) buf := &u16(malloc(max)) - if C._wgetcwd(buf, max) == 0 { + if C._wgetcwd(buf, max/2) == 0 { return '' } return string_from_wide(buf)