diff options
| author | WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> | 2022-05-25 02:00:13 +0100 |
|---|---|---|
| committer | WalterPlinge <22519813+WalterPlinge@users.noreply.github.com> | 2022-05-25 02:00:13 +0100 |
| commit | 831a86599ecd6d5ddf3f691fc94cf9c0effda50b (patch) | |
| tree | 804dd033e8b9b383e0fb0a9870c120bede038ba7 /src | |
| parent | 3c5124ce68110b780f9cd5aaa3801f1f200b98fe (diff) | |
Add fallback build paths search using environment variables
Diffstat (limited to 'src')
| -rw-r--r-- | src/build_settings.cpp | 221 |
1 files changed, 216 insertions, 5 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b458d8308..4d560bc00 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1186,7 +1186,201 @@ void init_build_context(TargetMetrics *cross_target) { // NOTE(IC): In order to find Visual C++ paths without relying on environment variables. // NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`. #include "microsoft_craziness.h" -#endif + +// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both +// official and portable installations (like mmozeiko's portable msvc script). This will only use +// the first paths it finds, and won't overwrite any values that `result` already has. +bool find_portable_msvc_installation(gbAllocator allocator, Find_Result_Utf8 *result) { + if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) { + return false; + } + + bool sdk_found = false; + if(result->windows_sdk_root.len > 0 + && result->windows_sdk_um_library_path.len > 0 + && result->windows_sdk_ucrt_library_path.len > 0) { + sdk_found = true; + } + + // We can find windows sdk using the following combination of env vars: + // (UniversalCRTSdkDir or WindowsSdkDir) and (WindowsSDKLibVersion or WindowsSDKVersion) + if (!sdk_found) { + // These appear to be suitable env vars used by Visual Studio + char const *win_sdk_ver_env = gb_get_env("WindowsSDKVersion", allocator); + char const *win_sdk_lib_env = gb_get_env("WindowsSDKLibVersion", allocator); + char const *win_sdk_dir_env = gb_get_env("WindowsSdkDir", allocator); + char const *crt_sdk_dir_env = gb_get_env("UniversalCRTSdkDir", allocator); + defer (gb_free(allocator, (void*)win_sdk_ver_env)); + defer (gb_free(allocator, (void*)win_sdk_lib_env)); + defer (gb_free(allocator, (void*)win_sdk_dir_env)); + defer (gb_free(allocator, (void*)crt_sdk_dir_env)); + + // NOTE(WalterPlinge): If any combination is found, let's just assume they are correct + if ((win_sdk_ver_env || win_sdk_lib_env) && (win_sdk_dir_env || crt_sdk_dir_env)) { + //? Maybe we need to handle missing '\' at end of strings, so far it doesn't seem an issue + String dir = win_sdk_dir_env + ? make_string_c(win_sdk_dir_env) + : make_string_c(crt_sdk_dir_env); + String ver = win_sdk_ver_env + ? make_string_c(win_sdk_ver_env) + : make_string_c(win_sdk_lib_env); + + // These have trailing '\' as we are just composing the path + String um_dir = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("um\\x64\\") + : make_string_c("um\\x86\\"); + String ucrt_dir = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("ucrt\\x64\\") + : make_string_c("ucrt\\x86\\"); + + result->windows_sdk_root = concatenate3_strings(allocator, dir, make_string_c("Lib\\"), ver); + result->windows_sdk_um_library_path = concatenate_strings(allocator, result->windows_sdk_root, um_dir); + result->windows_sdk_ucrt_library_path = concatenate_strings(allocator, result->windows_sdk_root, ucrt_dir); + + sdk_found = true; + } + } + + // If we haven't found it yet, we can loop through LIB for specific folders + //? This may not be robust enough using `um\x64` and `ucrt\x64` + if (!sdk_found) { + char const *lib_env = gb_get_env("LIB", allocator); + defer (gb_free(allocator, (void*)lib_env)); + if (lib_env) { + String lib = make_string_c(lib_env); + + // NOTE(WalterPlinge): I don't know if there's a chance for the LIB variable + // to be set without a trailing '\' (apart from manually), so we can just + // check paths without it (see use of `String end` in the loop below) + String um_dir = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("um\\x64") + : make_string_c("um\\x86"); + String ucrt_dir = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("ucrt\\x64") + : make_string_c("ucrt\\x86"); + + isize lo = {0}; + isize hi = {0}; + for (isize c = 0; c <= lib.len; c += 1) { + if (c != lib.len && lib[c] != ';') { + continue; + } + hi = c; + String dir = substring(lib, lo, hi); + defer (lo = hi + 1); + + // Remove the last slash so we can match with the strings above + String end = dir[dir.len - 1] == '\\' + ? substring(dir, 0, dir.len - 1) + : substring(dir, 0, dir.len); + + // Find one and we can make the other + if (string_ends_with(end, um_dir)) { + result->windows_sdk_um_library_path = concatenate_strings(allocator, end, make_string_c("\\")); + break; + } else if (string_ends_with(end, ucrt_dir)) { + result->windows_sdk_ucrt_library_path = concatenate_strings(allocator, end, make_string_c("\\")); + break; + } + } + + // Get the root from the one we found, and make the other + if (result->windows_sdk_um_library_path.len > 0) { + result->windows_sdk_root = substring(result->windows_sdk_um_library_path, 0, result->windows_sdk_um_library_path.len - 1 - um_dir.len); + result->windows_sdk_ucrt_library_path = concatenate3_strings(allocator, result->windows_sdk_root, ucrt_dir, make_string_c("\\")); + } else if (result->windows_sdk_ucrt_library_path.len > 0) { + result->windows_sdk_root = substring(result->windows_sdk_ucrt_library_path, 0, result->windows_sdk_ucrt_library_path.len - 1 - ucrt_dir.len); + result->windows_sdk_um_library_path = concatenate3_strings(allocator, result->windows_sdk_root, um_dir, make_string_c("\\")); + } + + if (result->windows_sdk_root.len > 0) { + sdk_found = true; + } + } + } + + // NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was + // installed using mmozeiko's portable msvc script, which uses the windows 10 sdk. + // This may need to be changed later if it ends up causing problems. + if (sdk_found && result->windows_sdk_version == 0) { + result->windows_sdk_version = 10; + } + + bool vs_found = false; + if (result->vs_exe_path.len > 0 && result->vs_library_path.len > 0) { + vs_found = true; + } + + // We can find visual studio using VCToolsInstallDir + if (!vs_found) { + char const *vctid_env = gb_get_env("VCToolsInstallDir", allocator); + defer (gb_free(allocator, (void*)vctid_env)); + if (vctid_env) { + String vctid = make_string_c(vctid_env); + String exe = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("bin\\Hostx64\\x64\\") + : make_string_c("bin\\Hostx86\\x86\\"); + String lib = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("lib\\x64\\") + : make_string_c("lib\\x86\\"); + result->vs_exe_path = concatenate_strings(allocator, vctid, exe); + result->vs_library_path = concatenate_strings(allocator, vctid, lib); + vs_found = true; + } + } + + // If we haven't found it yet, we can loop through Path for specific folders + if (!vs_found) { + char const *path_env = gb_get_env("Path", allocator); + defer (gb_free(allocator, (void*)path_env)); + if (path_env) { + String path = make_string_c(path_env); + + String exe = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("bin\\Hostx64\\x64") + : make_string_c("bin\\Hostx86\\x86"); + String lib = build_context.metrics.arch == TargetArch_amd64 + ? make_string_c("lib\\x64") + : make_string_c("lib\\x86"); + + isize lo = {0}; + isize hi = {0}; + for (isize c = 0; c <= path.len; c += 1) { + if (c != path.len && path[c] != ';') { + continue; + } + + hi = c; + String dir = substring(path, lo, hi); + defer (lo = hi + 1); + + String end = dir[dir.len - 1] == '\\' + ? substring(dir, 0, dir.len - 1) + : substring(dir, 0, dir.len); + + // check if cl.exe and link.exe exist in this folder + String cl = concatenate_strings(allocator, end, make_string_c("\\cl.exe")); + String link = concatenate_strings(allocator, end, make_string_c("\\link.exe")); + defer (gb_free(allocator, cl.text)); + defer (gb_free(allocator, link.text)); + + if (!string_ends_with(end, exe) || !gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) { + continue; + } + + String root = substring(end, 0, end.len - exe.len); + + result->vs_exe_path = concatenate_strings(allocator, end, make_string_c("\\")); + result->vs_library_path = concatenate3_strings(allocator, root, lib, make_string_c("\\")); + + vs_found = true; + } + } + } + + return sdk_found && vs_found; +} +#endif defined(GB_SYSTEM_WINDOWS) // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. // We've previously called `parse_build_flags`, so `out_filepath` should be set. @@ -1227,11 +1421,28 @@ bool init_build_paths(String init_filename) { if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - return false; + bool all_found = + find_result.windows_sdk_root.len > 0 && + find_result.windows_sdk_um_library_path.len > 0 && + find_result.windows_sdk_ucrt_library_path.len > 0 && + find_result.vs_exe_path.len > 0 && + find_result.vs_library_path.len > 0; + + if (find_result.windows_sdk_version == 0 || !all_found) { + if (!find_portable_msvc_installation(ha, &find_result)) { + gb_printf_err("Windows SDK not found.\n"); + return false; + } } +#if 0 + printf("windows_sdk_root: %.*s\n", LIT(find_result.windows_sdk_root)); + printf("windows_sdk_um_library_path: %.*s\n", LIT(find_result.windows_sdk_um_library_path)); + printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(find_result.windows_sdk_ucrt_library_path)); + printf("vs_exe_path: %.*s\n", LIT(find_result.vs_exe_path)); + printf("vs_library_path: %.*s\n", LIT(find_result.vs_library_path)); + + gb_exit(1); +#endif if (find_result.windows_sdk_um_library_path.len > 0) { GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); |