From 82b9df0dac6e05fb933534cd4c52c3f3af3ba96c Mon Sep 17 00:00:00 2001 From: rexim Date: Tue, 24 Mar 2026 21:31:05 +0700 Subject: [PATCH] Release v3.8.0 - Add NOB_CLIT() - Fix compliation on MSVC with /TP --- .github/workflows/nob.yaml | 7 +++-- how_to/001_basic_usage/.gitignore | 3 +- nob.c | 12 ++++++-- nob.h | 49 +++++++++++++++++++------------ shared.h | 2 +- tasks/20260317-165339/TASK.md | 2 +- 6 files changed, 49 insertions(+), 26 deletions(-) diff --git a/.github/workflows/nob.yaml b/.github/workflows/nob.yaml index 0da45677..6d227985 100644 --- a/.github/workflows/nob.yaml +++ b/.github/workflows/nob.yaml @@ -38,6 +38,9 @@ jobs: ${{ matrix.cc }} -x ${{ matrix.lang }} -o nob nob.c ./nob windows: + strategy: + matrix: + mode: ["/TC", "/std:c++20 /TP"] runs-on: windows-latest steps: - name: Clone GIT repo @@ -50,12 +53,12 @@ jobs: # https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#create-your-own-command-prompt-shortcut run: | call "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat" - cl.exe /Fe:nob nob.c + cl.exe ${{ matrix.mode }} /Fe:nob nob.c nob.exe - name: Build how_to-s shell: cmd run: | call "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat" cd how_to/ - cl.exe /Fe:nob nob.c + cl.exe ${{ matrix.mode }} /Fe:nob nob.c nob.exe diff --git a/how_to/001_basic_usage/.gitignore b/how_to/001_basic_usage/.gitignore index 59c52e12..d877715f 100644 --- a/how_to/001_basic_usage/.gitignore +++ b/how_to/001_basic_usage/.gitignore @@ -1,3 +1,4 @@ nob nob.old -build/ \ No newline at end of file +build/ +*.obj diff --git a/nob.c b/nob.c index cab99ecc..58c05001 100644 --- a/nob.c +++ b/nob.c @@ -162,6 +162,16 @@ 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 @@ -172,8 +182,6 @@ int main(int argc, char **argv) set_log_handler(cancer_log_handler); - Cmd cmd = {0}; - const char *program_name = shift(argv, argc); const char *command_name = "test"; if (argc > 0) command_name = shift(argv, argc); diff --git a/nob.h b/nob.h index 8b01c57c..1a9285cb 100644 --- a/nob.h +++ b/nob.h @@ -1,4 +1,4 @@ -/* nob - v3.7.0 - Public Domain - https://github.com/tsoding/nob.h +/* nob - v3.8.0 - Public Domain - https://github.com/tsoding/nob.h This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea. @@ -303,7 +303,7 @@ typedef struct { NOBDEF bool nob_walk_dir_opt(const char *root, Nob_Walk_Func func, Nob_Walk_Dir_Opt); -#define nob_walk_dir(root, func, ...) nob_walk_dir_opt((root), (func), (Nob_Walk_Dir_Opt){__VA_ARGS__}) +#define nob_walk_dir(root, func, ...) nob_walk_dir_opt((root), (func), NOB_CLIT(Nob_Walk_Dir_Opt){__VA_ARGS__}) typedef struct { char *name; @@ -585,14 +585,14 @@ typedef struct { typedef struct { const char *stdin_path; } Nob_Chain_Begin_Opt; -#define nob_chain_begin(chain, ...) nob_chain_begin_opt((chain), (Nob_Chain_Begin_Opt) { __VA_ARGS__ }) +#define nob_chain_begin(chain, ...) nob_chain_begin_opt((chain), NOB_CLIT(Nob_Chain_Begin_Opt) { __VA_ARGS__ }) NOBDEF bool nob_chain_begin_opt(Nob_Chain *chain, Nob_Chain_Begin_Opt opt); typedef struct { bool err2out; bool dont_reset; } Nob_Chain_Cmd_Opt; -#define nob_chain_cmd(chain, cmd, ...) nob_chain_cmd_opt((chain), (cmd), (Nob_Chain_Cmd_Opt) { __VA_ARGS__ }) +#define nob_chain_cmd(chain, cmd, ...) nob_chain_cmd_opt((chain), (cmd), NOB_CLIT(Nob_Chain_Cmd_Opt) { __VA_ARGS__ }) NOBDEF bool nob_chain_cmd_opt(Nob_Chain *chain, Nob_Cmd *cmd, Nob_Chain_Cmd_Opt opt); typedef struct { @@ -601,7 +601,7 @@ typedef struct { const char *stdout_path; const char *stderr_path; } Nob_Chain_End_Opt; -#define nob_chain_end(chain, ...) nob_chain_end_opt((chain), (Nob_Chain_End_Opt) { __VA_ARGS__ }) +#define nob_chain_end(chain, ...) nob_chain_end_opt((chain), NOB_CLIT(Nob_Chain_End_Opt) { __VA_ARGS__ }) NOBDEF bool nob_chain_end_opt(Nob_Chain *chain, Nob_Chain_End_Opt opt); // Get amount of processors on the machine. @@ -614,7 +614,7 @@ NOBDEF uint64_t nob_nanos_since_unspecified_epoch(void); // Same as nob_cmd_run_opt but using cool variadic macro to set the default options. // See https://x.com/vkrajacic/status/1749816169736073295 for more info on how to use such macros. -#define nob_cmd_run(cmd, ...) nob_cmd_run_opt((cmd), (Nob_Cmd_Opt){__VA_ARGS__}) +#define nob_cmd_run(cmd, ...) nob_cmd_run_opt((cmd), NOB_CLIT(Nob_Cmd_Opt){__VA_ARGS__}) // DEPRECATED: // @@ -651,9 +651,16 @@ typedef struct { // use it as a C string. NOBDEF void nob_cmd_render(Nob_Cmd cmd, Nob_String_Builder *render); -NOBDEF void nob__cmd_append(Nob_Cmd *cmd, size_t n, ...); +// Compound Literal +#if defined(__cplusplus) + #define NOB_CLIT(type) type +#else + #define NOB_CLIT(type) (type) +#endif + +NOBDEF void nob__cmd_append(Nob_Cmd *cmd, ...); #define nob_cmd_append(cmd, ...) \ - nob__cmd_append(cmd, (sizeof((const char*[]){__VA_ARGS__})/sizeof(const char*)), __VA_ARGS__) + nob__cmd_append(cmd, __VA_ARGS__, (const char*)-1) // TODO: nob_cmd_extend() evaluates other_cmd twice // It can be fixed by turning nob_cmd_extend() call into a statement. @@ -950,12 +957,13 @@ static Nob_Proc nob__cmd_start_process(Nob_Cmd cmd, Nob_Fd *fdin, Nob_Fd *fdout, // Any messages with the level below nob_minimal_log_level are going to be suppressed. Nob_Log_Level nob_minimal_log_level = NOB_INFO; -NOBDEF void nob__cmd_append(Nob_Cmd *cmd, size_t n, ...) +NOBDEF void nob__cmd_append(Nob_Cmd *cmd, ...) { va_list args; - va_start(args, n); - for (size_t i = 0; i < n; ++i) { + va_start(args, cmd); + for (;;) { const char *arg = va_arg(args, const char *); + if (arg == (const char*)-1) break; nob_da_append(cmd, arg); } va_end(args); @@ -2020,7 +2028,7 @@ bool nob__walk_dir_opt_impl(Nob_String_Builder *file_path, Nob_Walk_Func func, s // Pre-order walking if (!opt.post_order) { - if (!func((Nob_Walk_Entry) { + if (!func(NOB_CLIT(Nob_Walk_Entry) { .path = file_path->items, .type = file_type, .level = level, @@ -2067,7 +2075,7 @@ bool nob__walk_dir_opt_impl(Nob_String_Builder *file_path, Nob_Walk_Func func, s // Post-order walking if (opt.post_order) { - if (!func((Nob_Walk_Entry) { + if (!func(NOB_CLIT(Nob_Walk_Entry) { .path = file_path->items, .type = file_type, .level = level, @@ -2159,7 +2167,7 @@ NOBDEF Nob_File_Type nob_get_file_type(const char *path) DWORD attr = GetFileAttributesA(path); if (attr == INVALID_FILE_ATTRIBUTES) { nob_log(NOB_ERROR, "Could not get file attributes of %s: %s", path, nob_win32_error_message(GetLastError())); - return -1; + return (Nob_File_Type)-1; } if (attr & FILE_ATTRIBUTE_DIRECTORY) return NOB_FILE_DIRECTORY; @@ -2754,8 +2762,8 @@ NOBDEF char *nob_temp_dir_name(const char *path) return nob_temp_strndup(path, i + 1); #else if (!path) path = ""; // Treating NULL as empty. - char *drive = nob_temp_alloc(_MAX_DRIVE); - char *dir = nob_temp_alloc(_MAX_DIR); + char *drive = (char*) nob_temp_alloc(_MAX_DRIVE); + char *dir = (char*) nob_temp_alloc(_MAX_DIR); // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) errno_t ret = _splitpath_s(path, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); NOB_ASSERT(ret == 0); @@ -2777,8 +2785,8 @@ NOBDEF char *nob_temp_file_name(const char *path) return s+i; #else if (!path) path = ""; // Treating NULL as empty. - char *fname = nob_temp_alloc(_MAX_FNAME); - char *ext = nob_temp_alloc(_MAX_EXT); + char *fname = (char*)nob_temp_alloc(_MAX_FNAME); + char *ext = (char*)nob_temp_alloc(_MAX_EXT); // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) errno_t ret = _splitpath_s(path, NULL, 0, NULL, 0, fname, _MAX_FNAME, ext, _MAX_EXT); NOB_ASSERT(ret == 0); @@ -2792,7 +2800,7 @@ NOBDEF char *nob_temp_file_ext(const char *path) return strrchr(nob_temp_file_name(path), '.'); #else if (!path) path = ""; // Treating NULL as empty. - char *ext = nob_temp_alloc(_MAX_EXT); + char *ext = (char*)nob_temp_alloc(_MAX_EXT); // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/8e46eyt7(v=vs.100) errno_t ret = _splitpath_s(path, NULL, 0, NULL, 0, NULL, 0, ext, _MAX_EXT); NOB_ASSERT(ret == 0); @@ -2946,6 +2954,7 @@ NOBDEF char *nob_temp_running_executable_path(void) #define procs_wait_and_reset nob_procs_wait_and_reset #define procs_append_with_flush nob_procs_append_with_flush #define procs_flush nob_procs_flush + #define CLIT NOB_CLIT #define Cmd Nob_Cmd #define Cmd_Redirect Nob_Cmd_Redirect #define Cmd_Opt Nob_Cmd_Opt @@ -3012,6 +3021,8 @@ NOBDEF char *nob_temp_running_executable_path(void) /* Revision history: + 3.8.0 (2026-03-24) Add NOB_CLIT() + Fix compliation on MSVC with /TP 3.7.0 (2026-03-20) Add nob_sb_append_sv() 3.6.0 (2026-03-16) Add nob_sv_chop_suffix() Deprecate nob_sv_end_with() diff --git a/shared.h b/shared.h index f444dd19..f3bb3e10 100644 --- a/shared.h +++ b/shared.h @@ -12,7 +12,7 @@ #if defined(__cplusplus) #if defined(_MSC_VER) - #define nob_cc_flags(cmd) cmd_append(cmd, "/TP", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") + #define nob_cc_flags(cmd) cmd_append(cmd, "/std:c++20", "/TP", "/W4", "/nologo", "/D_CRT_SECURE_NO_WARNINGS", "-I.") #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."); diff --git a/tasks/20260317-165339/TASK.md b/tasks/20260317-165339/TASK.md index 6f0aa9b4..a417235f 100644 --- a/tasks/20260317-165339/TASK.md +++ b/tasks/20260317-165339/TASK.md @@ -1,6 +1,6 @@ # MSVC C++ was never tried -- STATUS: OPEN +- STATUS: CLOSED - PRIORITY: 100 - TAGS: bug,msvc