From c0bd14cee73bd41c35f9ea12f450881c0976f9dd Mon Sep 17 00:00:00 2001 From: Jonathan Nilsson Date: Tue, 9 Sep 2025 22:38:40 +0200 Subject: [PATCH] Find cl and set INCLUDE env var outside of a visual studio command promt (#2467) * Added search for cl --------- Co-authored-by: Christoffer Lerno --- src/compiler/compiler.c | 6 +++ src/compiler/linker.c | 15 +++++++- src/compiler/windows_support.c | 4 +- src/utils/find_msvc.c | 68 +++++++++++++++++++++++++++------- src/utils/lib.h | 3 ++ src/utils/stringutils.c | 8 ++++ 6 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 2cc24e6d4..3d0dd7c70 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -1754,6 +1754,12 @@ const char *default_c_compiler(void) return cc; } #if PLATFORM_WINDOWS + WindowsSDK *sdk = windows_get_sdk(); + + if (sdk && sdk->cl_path) + { + return cc = sdk->cl_path; + } return cc = "cl.exe"; #else return cc = "cc"; diff --git a/src/compiler/linker.c b/src/compiler/linker.c index 5750edd95..b861b5930 100644 --- a/src/compiler/linker.c +++ b/src/compiler/linker.c @@ -1008,7 +1008,7 @@ const char *cc_compiler(const char *cc, const char *file, const char *flags, con if (!dir) dir = compiler.build.build_dir; if (output_subdir) dir = dir ? file_append_path(dir, output_subdir) : output_subdir; if (dir) dir_make(dir); - bool is_cl_exe = str_eq(cc, "cl.exe"); + bool is_cl_exe = str_ends_with(cc, "cl.exe"); char *filename = NULL; bool split_worked = file_namesplit(file, &filename, NULL); if (!split_worked) error_exit("Cannot compile '%s'", file); @@ -1031,6 +1031,8 @@ const char *cc_compiler(const char *cc, const char *file, const char *flags, con const char ***args_ref = &parts; add_quote_arg(cc); + if (is_cl_exe) add_plain_arg("/nologo"); + FOREACH(const char *, include_dir, include_dirs) { add_concat_quote_arg(is_cl_exe ? "/I" : "-I ", include_dir); @@ -1060,6 +1062,17 @@ const char *cc_compiler(const char *cc, const char *file, const char *flags, con add_quote_arg(out_name); } +#if PLATFORM_WINDOWS + if (is_cl_exe) + { + WindowsSDK *sdk = windows_get_sdk(); + if (sdk && sdk->cl_include_env) + { + _putenv_s("INCLUDE", sdk->cl_include_env); + } + } +#endif + const char *output = assemble_linker_command(parts, PLATFORM_WINDOWS); DEBUG_LOG("Compiling c sources using '%s'", output); if (system(output) != 0) diff --git a/src/compiler/windows_support.c b/src/compiler/windows_support.c index aee9435fc..5e6a0c8d9 100644 --- a/src/compiler/windows_support.c +++ b/src/compiler/windows_support.c @@ -16,14 +16,14 @@ static WindowsSDK *sdk = NULL; #if PLATFORM_WINDOWS -WindowsSDK get_windows_link_paths(void); +WindowsSDK get_windows_paths(void); static WindowsSDK loaded; WindowsSDK *windows_get_sdk(void) { if (!sdk) { - loaded = get_windows_link_paths(); + loaded = get_windows_paths(); sdk = &loaded; } return sdk; diff --git a/src/utils/find_msvc.c b/src/utils/find_msvc.c index 95803b4f6..64541b55f 100644 --- a/src/utils/find_msvc.c +++ b/src/utils/find_msvc.c @@ -10,25 +10,63 @@ static char *find_visual_studio(void); static char *find_windows_kit_root(void); +static char *find_best_version(const char *root, const char *subdir); -WindowsSDK get_windows_link_paths() +WindowsSDK get_windows_paths() { WindowsSDK out = {0}; - char *path = find_windows_kit_root(); + char *root = find_windows_kit_root(); - if (!path) + if (!root) { error_exit("Failed to find windows kit root."); } - out.windows_sdk_path = path; - out.vs_library_path = find_visual_studio(); + out.windows_sdk_path = find_best_version(root, "Lib"); + if (!out.windows_sdk_path) + { + free(root); + error_exit("Failed to find Lib dir in windows kit root."); + } + + char *windows_sdk_include_root = find_best_version(root, "Include"); + + if (!windows_sdk_include_root) + { + free(root); + error_exit("Failed to find Include dir in windows kit root."); + } + + char *vs_path = find_visual_studio(); + + scratch_buffer_clear(); + scratch_buffer_printf("%s\\lib\\x64", vs_path); + out.vs_library_path = scratch_buffer_copy(); + + if (!getenv("INCLUDE")) + { + scratch_buffer_clear(); + scratch_buffer_printf("%s\\bin\\Hostx64\\x64\\cl.exe", vs_path); + out.cl_path = scratch_buffer_copy(); + + scratch_buffer_clear(); + scratch_buffer_printf("%s\\include;", vs_path); + scratch_buffer_printf("%s\\cppwinrt;", windows_sdk_include_root); + scratch_buffer_printf("%s\\cppwinrt;", windows_sdk_include_root); + scratch_buffer_printf("%s\\shared;", windows_sdk_include_root); + scratch_buffer_printf("%s\\ucrt;", windows_sdk_include_root); + scratch_buffer_printf("%s\\um;", windows_sdk_include_root); + scratch_buffer_printf("%s\\winrt;", windows_sdk_include_root); + + out.cl_include_env = scratch_buffer_copy(); + } + + free(root); return out; } - static char *find_visual_studio(void) { // Let's locate vswhere.exe @@ -58,11 +96,10 @@ static char *find_visual_studio(void) // We have the version, so we're done with the path: scratch_buffer_clear(); - scratch_buffer_printf("%s\\VC\\Tools\\MSVC\\%s\\lib\\x64", install_path, version); + scratch_buffer_printf("%s\\VC\\Tools\\MSVC\\%s", install_path, version); return scratch_buffer_copy(); } - static char *find_windows_kit_root(void) { HKEY main_key; @@ -91,9 +128,15 @@ static char *find_windows_kit_root(void) char *root = win_utf16to8(value); free(value); + return root; +} + +static char *find_best_version(const char *root, const char *subdir) +{ scratch_buffer_clear(); scratch_buffer_append(root); - scratch_buffer_append("Lib\\*"); + scratch_buffer_append(subdir); + scratch_buffer_append("\\*"); WIN32_FIND_DATAW find_data; uint16_t *wildcard_name = win_utf8to16(scratch_buffer_to_string()); @@ -126,19 +169,18 @@ static char *find_windows_kit_root(void) while (FindNextFileW(handle, &find_data)); FindClose(handle); - if (!best_file) goto SEARCH_FAILED;; + if (!best_file) goto SEARCH_FAILED; scratch_buffer_clear(); scratch_buffer_append(root); - scratch_buffer_append("Lib\\"); + scratch_buffer_append(subdir); + scratch_buffer_append("\\"); scratch_buffer_append(best_file); - free(root); free(best_file); return scratch_buffer_copy(); SEARCH_FAILED: - free(root); return NULL; } diff --git a/src/utils/lib.h b/src/utils/lib.h index 42eab7569..bd526a3a2 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -40,6 +40,8 @@ typedef struct typedef struct { char* windows_sdk_path; char* vs_library_path; + char* cl_path; + char* cl_include_env; } WindowsSDK; #define MAX_STRING_BUFFER 0x10000 @@ -153,6 +155,7 @@ bool str_is_valid_constant(const char *string); const char *str_unescape(char *string); bool str_is_identifier(const char *string); bool str_eq(const char *str1, const char *str2); +bool str_ends_with(const char *str, const char *end); bool str_is_type(const char *string); bool slice_is_type(const char *string, size_t); bool str_is_integer(const char *string); diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 1a6d65e47..11eaf8894 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -143,6 +143,14 @@ bool str_eq(const char *str1, const char *str2) return str1 == str2 || (str1 && str2 && strcmp(str1, str2) == 0); } +bool str_ends_with(const char *str, const char *end) +{ + size_t str_len = strlen(str); + size_t end_len = strlen(end); + if (end_len > str_len) return false; + return memcmp(str + str_len - end_len, end, end_len) == 0; +} + bool str_is_integer(const char *string) { if (string[0] == '-') string++;