1- /* nob - v2.0.0 - Public Domain - https://github.com/tsoding/nob.h
1+ /* nob - v2.0.1 - Public Domain - https://github.com/tsoding/nob.h
22
33 This library is the next generation of the [NoBuild](https://github.com/tsoding/nobuild) idea.
44
161161# define _WINCON_
162162# include <windows.h>
163163# include <direct.h>
164+ # include <io.h>
164165# include <shellapi.h>
165166#else
166167# ifdef __APPLE__
@@ -659,6 +660,8 @@ NOBDEF char *nob_temp_running_executable_path(void);
659660# define nob_cc (cmd ) nob_cmd_append(cmd, "clang")
660661# elif defined(_MSC_VER )
661662# define nob_cc (cmd ) nob_cmd_append(cmd, "cl.exe")
663+ # elif defined(__TINYC__ )
664+ # define nob_cc (cmd ) nob_cmd_append(cmd, "tcc")
662665# endif
663666# else
664667# define nob_cc (cmd ) nob_cmd_append(cmd, "cc")
@@ -699,6 +702,8 @@ NOBDEF char *nob_temp_running_executable_path(void);
699702# define NOB_REBUILD_URSELF (binary_path , source_path ) "clang", "-o", binary_path, source_path
700703# elif defined(_MSC_VER )
701704# define NOB_REBUILD_URSELF (binary_path , source_path ) "cl.exe", nob_temp_sprintf("/Fe:%s", (binary_path)), source_path
705+ # elif defined(__TINYC__ )
706+ # define NOB_REBUILD_URSELF (binary_path , source_path ) "tcc", "-o", binary_path, source_path
702707# endif
703708# else
704709# define NOB_REBUILD_URSELF (binary_path , source_path ) "cc", "-o", binary_path, source_path
@@ -1602,19 +1607,18 @@ NOBDEF void nob_log(Nob_Log_Level level, const char *fmt, ...)
16021607 va_end (args );
16031608}
16041609
1605- bool nob__walk_dir_opt_impl (const char * root , Nob_Walk_Func func , size_t level , bool * stop , Nob_Walk_Dir_Opt opt )
1610+ bool nob__walk_dir_opt_impl (Nob_String_Builder * sb , Nob_Walk_Func func , size_t level , bool * stop , Nob_Walk_Dir_Opt opt )
16061611{
16071612#ifdef _WIN32
16081613 bool result = true;
1609- Nob_String_Builder sb = {0 };
16101614 WIN32_FIND_DATA data ;
16111615 HANDLE hFind = INVALID_HANDLE_VALUE ;
16121616
1613- Nob_File_Type type = nob_get_file_type (root );
1617+ Nob_File_Type type = nob_get_file_type (sb -> items );
16141618 if (type < 0 ) nob_return_defer (false);
16151619 Nob_Walk_Action action = NOB_WALK_CONT ;
16161620 if (!func ((Nob_Walk_Entry ) {
1617- .path = root ,
1621+ .path = sb -> items ,
16181622 .type = type ,
16191623 .data = opt .data ,
16201624 .level = level ,
@@ -1632,48 +1636,46 @@ bool nob__walk_dir_opt_impl(const char *root, Nob_Walk_Func func, size_t level,
16321636
16331637 {
16341638 size_t mark = nob_temp_save ();
1635- char * buffer = nob_temp_sprintf ("%s\\*" , root );
1639+ char * buffer = nob_temp_sprintf ("%s\\*" , sb -> items );
16361640 hFind = FindFirstFile (buffer , & data );
16371641 nob_temp_rewind (mark );
16381642 }
16391643
16401644 if (hFind == INVALID_HANDLE_VALUE ) {
1641- nob_log (NOB_ERROR , "Could not open directory %s: %s" , root , nob_win32_error_message (GetLastError ()));
1645+ nob_log (NOB_ERROR , "Could not open directory %s: %s" , sb -> items , nob_win32_error_message (GetLastError ()));
16421646 nob_return_defer (false);
16431647 }
16441648
1649+ size_t mark = sb -> count - 1 ;
16451650 for (;;) {
16461651 if (strcmp (data .cFileName , "." ) != 0 && strcmp (data .cFileName , ".." ) != 0 ) {
1647- sb .count = 0 ;
1648- nob_sb_appendf (& sb , "%s/%s" , root , data .cFileName );
1649- nob_sb_append_null (& sb );
1650- const char * path = sb .items ;
1651- if (!nob__walk_dir_opt_impl (path , func , level + 1 , stop , opt )) nob_return_defer (false);
1652+ sb -> count = mark ;
1653+ nob_sb_appendf (sb , "\\%s" , data .cFileName );
1654+ nob_sb_append_null (sb );
1655+ if (!nob__walk_dir_opt_impl (sb , func , level + 1 , stop , opt )) nob_return_defer (false);
16521656 if (* stop ) nob_return_defer (true);
16531657 }
16541658
16551659 if (!FindNextFile (hFind , & data )) {
16561660 if (GetLastError () == ERROR_NO_MORE_FILES ) nob_return_defer (true);
1657- nob_log (NOB_ERROR , "Could not read directory %s: %s" , root , nob_win32_error_message (GetLastError ()));
1661+ nob_log (NOB_ERROR , "Could not read directory %s: %s" , sb -> items , nob_win32_error_message (GetLastError ()));
16581662 nob_return_defer (false);
16591663 }
16601664 }
16611665
16621666defer :
16631667 FindClose (hFind );
1664- free (sb .items );
16651668 return result ;
16661669#else // POSIX
16671670 bool result = true;
16681671
16691672 DIR * dir = NULL ;
1670- Nob_String_Builder sb = {0 };
16711673
1672- Nob_File_Type type = nob_get_file_type (root );
1674+ Nob_File_Type type = nob_get_file_type (sb -> items );
16731675 if (type < 0 ) nob_return_defer (false);
16741676 Nob_Walk_Action action = NOB_WALK_CONT ;
16751677 if (!func ((Nob_Walk_Entry ) {
1676- .path = root ,
1678+ .path = sb -> items ,
16771679 .type = type ,
16781680 .data = opt .data ,
16791681 .level = level ,
@@ -1691,42 +1693,46 @@ bool nob__walk_dir_opt_impl(const char *root, Nob_Walk_Func func, size_t level,
16911693
16921694 struct dirent * ent = NULL ;
16931695
1694- dir = opendir (root );
1696+ dir = opendir (sb -> items );
16951697 if (dir == NULL ) {
1696- nob_log (NOB_ERROR , "Could not open directory %s: %s" , root , strerror (errno ));
1698+ nob_log (NOB_ERROR , "Could not open directory %s: %s" , sb -> items , strerror (errno ));
16971699 nob_return_defer (false);
16981700 }
16991701
1702+ size_t mark = sb -> count - 1 ;
17001703 errno = 0 ;
17011704 ent = readdir (dir );
17021705 while (ent != NULL ) {
17031706 if (strcmp (ent -> d_name , "." ) != 0 && strcmp (ent -> d_name , ".." ) != 0 ) {
1704- sb .count = 0 ;
1705- nob_sb_appendf (& sb , "%s/%s" , root , ent -> d_name );
1706- nob_sb_append_null (& sb );
1707- const char * path = sb .items ;
1708- if (!nob__walk_dir_opt_impl (path , func , level + 1 , stop , opt )) nob_return_defer (false);
1707+ sb -> count = mark ;
1708+ nob_sb_appendf (sb , "/%s" , ent -> d_name );
1709+ nob_sb_append_null (sb );
1710+ if (!nob__walk_dir_opt_impl (sb , func , level + 1 , stop , opt )) nob_return_defer (false);
17091711 if (* stop ) nob_return_defer (true);
17101712 }
17111713 ent = readdir (dir );
17121714 }
17131715
17141716 if (errno != 0 ) {
1715- nob_log (NOB_ERROR , "Could not read directory %s: %s" , root , strerror (errno ));
1717+ nob_log (NOB_ERROR , "Could not read directory %s: %s" , sb -> items , strerror (errno ));
17161718 nob_return_defer (false);
17171719 }
17181720
17191721defer :
17201722 if (dir ) closedir (dir );
1721- free (sb .items );
17221723 return result ;
17231724#endif // _WIN32
17241725}
17251726
17261727NOBDEF bool nob_walk_dir_opt (const char * root , Nob_Walk_Func func , Nob_Walk_Dir_Opt opt )
17271728{
17281729 bool stop = false;
1729- return nob__walk_dir_opt_impl (root , func , 0 , & stop , opt );
1730+ Nob_String_Builder sb = {0 };
1731+ nob_sb_appendf (& sb , "%s" , root );
1732+ nob_sb_append_null (& sb );
1733+ bool ok = nob__walk_dir_opt_impl (& sb , func , 0 , & stop , opt );
1734+ free (sb .items );
1735+ return ok ;
17301736}
17311737
17321738bool nob__read_entire_dir_visit (Nob_Walk_Entry entry )
@@ -2015,7 +2021,7 @@ NOBDEF int nob_needs_rebuild(const char *output_path, const char **input_paths,
20152021 nob_log (NOB_ERROR , "could not stat %s: %s" , output_path , strerror (errno ));
20162022 return -1 ;
20172023 }
2018- int output_path_time = statbuf .st_mtime ;
2024+ time_t output_path_time = statbuf .st_mtime ;
20192025
20202026 for (size_t i = 0 ; i < input_paths_count ; ++ i ) {
20212027 const char * input_path = input_paths [i ];
@@ -2024,7 +2030,7 @@ NOBDEF int nob_needs_rebuild(const char *output_path, const char **input_paths,
20242030 nob_log (NOB_ERROR , "could not stat %s: %s" , input_path , strerror (errno ));
20252031 return -1 ;
20262032 }
2027- int input_path_time = statbuf .st_mtime ;
2033+ time_t input_path_time = statbuf .st_mtime ;
20282034 // NOTE: if even a single input_path is fresher than output_path that's 100% rebuild
20292035 if (input_path_time > output_path_time ) return 1 ;
20302036 }
@@ -2082,7 +2088,7 @@ NOBDEF bool nob_read_entire_file(const char *path, Nob_String_Builder *sb)
20822088#ifndef _WIN32
20832089 m = ftell (f );
20842090#else
2085- m = _ftelli64 ( f );
2091+ m = _telli64 ( _fileno ( f ) );
20862092#endif
20872093 if (m < 0 ) nob_return_defer (false);
20882094 if (fseek (f , 0 , SEEK_SET ) < 0 ) nob_return_defer (false);
@@ -2441,7 +2447,7 @@ NOBDEF char *nob_temp_running_executable_path(void)
24412447 #define WALK_SKIP NOB_WALK_SKIP
24422448 #define WALK_STOP NOB_WALK_STOP
24432449 #define Walk_Action Nob_Walk_Action
2444- #define Walk_Func_Entry Nob_Walk_Func_Entry
2450+ #define Walk_Entry Nob_Walk_Entry
24452451 #define Walk_Func Nob_Walk_Func
24462452 #define Walk_Dir_Opt Nob_Walk_Dir_Opt
24472453 #define walk_dir nob_walk_dir
@@ -2540,7 +2546,12 @@ NOBDEF char *nob_temp_running_executable_path(void)
25402546/*
25412547 Revision history:
25422548
2543- 2.0.0 ( ) Remove minirent.h (by @rexim)
2549+ 2.0.1 (2026-01-07) Fix Walk_Entry naming (by @Sinha-Ujjawal)
2550+ Using single String Builder in nob__walk_dir_opt_impl (by @Sinha-Ujjawal)
2551+ Add tcc to nob_cc_*() and NOB_REBUILD_URSELF() macros (by @vylsaz)
2552+ Fix building nob_read_entire_file() with tcc on windows (by @vylsaz)
2553+ Fix Y2038 in nob_needs_rebuild() (by @lnvitesace)
2554+ 2.0.0 (2026-01-06) Remove minirent.h (by @rexim)
25442555 BACKWARD INCOMPATIBLE CHANGE!!! If you were using minirent.h from this library
25452556 just use it directly from https://github.com/tsoding/minirent
25462557 or consider using the New Directory Walking API.
0 commit comments