From dcb4e6fed7e90a3fa0a9df986de2a4dadba82118 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Wed, 19 Aug 2026 20:31:12 +0800 Subject: [PATCH] Fix Windows build for cl.exe and clang targeting MSVC Make the build and tests work on Windows with both MSVC cl.exe and clang targeting x86_64-pc-windows-msvc, in both C and C++ modes. - shared.h: for cl.exe add /utf-8 to the C (/TC) and C++ (/std:c++20 /TP) flag sets so UTF-8 sources compile correctly on Windows. For clang targeting MSVC use clang-style flags (-std=c99 / -x c++, -Wall, -Wswitch-enum, ...) instead of the MSVC-only flags that its driver rejects. - nob.h: make nob_cc_output append ".exe" when building with clang targeting MSVC (-o.exe) so the produced binary matches the "../.exe" run command. cl.exe already emits ".exe" through /Fe, and non-Windows builds are unchanged. - nob.h: include and undef the private SDK guards (_WINUSER_, _WINGDI_, _IMM_, _WINCON_) and WIN32_LEAN_AND_MEAN after the system includes so SetConsoleOutputCP() is declared even when compiling with cl.exe /TP. Also undef UNICODE so the generic WinAPI names keep resolving to the ANSI variants the rest of the code uses. - nob.c: remove the extern "C" workaround for SetConsoleOutputCP(), no longer needed with the header fix above. --- nob.c | 10 ---------- nob.h | 24 ++++++++++++++++++++++-- shared.h | 15 +++++++++++++-- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/nob.c b/nob.c index acc56b7..9484abc 100644 --- a/nob.c +++ b/nob.c @@ -165,16 +165,6 @@ void print_available_commands(Commands commands) } } -#if defined(_WIN32) && defined(_MSC_VER) && defined(__cplusplus) -// TODO: I don't know why, but when you compile nob.c with -// cl.exe /std:c++20 /TP nob.c -// It just can't find the declaration of SetConsoleOutputCP(). -// This is probably something about how we include windows.h in nob.h -extern "C" { - WINBASEAPI BOOL WINAPI SetConsoleOutputCP(_In_ UINT wCodePageID); -} -#endif - int main(int argc, char **argv) { #ifdef _WIN32 diff --git a/nob.h b/nob.h index 2bdb16b..325fa0f 100644 --- a/nob.h +++ b/nob.h @@ -157,6 +157,12 @@ #include #ifdef _WIN32 +// TODO: We currently mix ANSI (xxxA) and macro-based Windows APIs. By undefining +// UNICODE, generic APIs resolve to their ANSI variants, but some code directly +// calls xxxA functions. This inconsistency limits Unicode path support on Windows. +// A better approach would be to consistently use wide-character (W) APIs with +// explicit UTF-8 <-> UTF-16 conversion. +# undef UNICODE # define WIN32_LEAN_AND_MEAN # define _WINUSER_ # define _WINGDI_ @@ -166,6 +172,16 @@ # include # include # include +// TODO: SetConsoleOutputCP is declared in consoleapi2.h, but defining _WINCON_ +// prevented windows.h from including it. The manual include below is a temporary +// workaround. The correct fix is to remove all private SDK guards and only keep +// WIN32_LEAN_AND_MEAN. +# include +# undef _WINUSER_ +# undef _WINGDI_ +# undef _IMM_ +# undef _WINCON_ +# undef WIN32_LEAN_AND_MEAN #else # ifdef __APPLE__ # include @@ -821,8 +837,12 @@ NOBDEF char *nob_temp_running_executable_path(void); #endif // nob_cc_flags #ifndef nob_cc_output -# if defined(_MSC_VER) && !defined(__clang__) -# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("/Fe:%s", (output_path)), nob_temp_sprintf("/Fo:%s", (output_path))) +# if defined(_MSC_VER) +# if defined(__clang__) +# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("-o%s.exe", (output_path))) +# else +# define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, nob_temp_sprintf("/Fe:%s", (output_path)), nob_temp_sprintf("/Fo:%s", (output_path))) +# endif # else # define nob_cc_output(cmd, output_path) nob_cmd_append(cmd, "-o", (output_path)) # endif diff --git a/shared.h b/shared.h index f3bb3e1..49dc237 100644 --- a/shared.h +++ b/shared.h @@ -12,14 +12,25 @@ #if defined(__cplusplus) #if defined(_MSC_VER) - #define nob_cc_flags(cmd) cmd_append(cmd, "/std:c++20", "/TP", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") + #if defined(__clang__) + // TODO: Clang targeting MSVC in C++ mode warns about missing field initializers + // and missing braces when using C-style {0} initialization. Suppress for now. + #define nob_cc_flags(cmd) cmd_append(cmd, "-x", "c++", "-Wall", "-Wextra", "-Wswitch-enum", \ + "-Wno-missing-field-initializers", "-Wno-missing-braces", "-D_CRT_SECURE_NO_WARNINGS", "-I.") + #else + #define nob_cc_flags(cmd) cmd_append(cmd, "/utf-8", "/std:c++20", "/TP", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") + #endif #else #define nob_cc(cmd) cmd_append(cmd, "cc", "-x", "c++") #define nob_cc_flags(cmd) cmd_append(cmd, "-Wall", "-Wextra", "-Wno-missing-field-initializers", "-Wswitch-enum", "-ggdb", "-I."); #endif #else // __cplusplus #if defined(_MSC_VER) - #define nob_cc_flags(cmd) cmd_append(cmd, "/TC", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") + #if defined(__clang__) + #define nob_cc_flags(cmd) cmd_append(cmd, "-Wall", "-Wextra", "-Wswitch-enum", "-std=c99", "-D_CRT_SECURE_NO_WARNINGS", "-I.") + #else + #define nob_cc_flags(cmd) cmd_append(cmd, "/utf-8", "/TC", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") + #endif #elif defined(__APPLE__) || defined(__MACH__) // TODO: "-std=c99", "-D_POSIX_C_SOURCE=200112L" didn't work for MacOS, don't know why, don't really care that much at the moment. // Anybody who does feel free to investigate.