@@ -200,6 +200,31 @@ void chain_echo(Chain chain);
200
200
chain_run_sync(chain); \
201
201
} while(0)
202
202
203
+ // TODO: REBUILD_URSELF does not distinguish MSVC and MinGW setups on Windows
204
+ #ifndef REBUILD_URSELF
205
+ # if _WIN32
206
+ # define REBUILD_URSELF (binary_path , source_path ) CMD("cl.exe", source_path)
207
+ # else
208
+ # define REBUILD_URSELF (binary_path , source_path ) CMD("cc", "-o", binary_path, source_path)
209
+ # endif
210
+ #endif
211
+
212
+ #define GO_REBUILD_URSELF (argc , argv ) \
213
+ do { \
214
+ const char *source_path = __FILE__; \
215
+ assert(argc >= 1); \
216
+ const char *binary_path = argv[0]; \
217
+ \
218
+ if (is_path1_modified_after_path2(source_path, binary_path)) { \
219
+ RENAME(binary_path, CONCAT(binary_path, ".old")); \
220
+ REBUILD_URSELF(binary_path, source_path); \
221
+ CMD(binary_path); \
222
+ exit(0); \
223
+ } \
224
+ } while(0)
225
+
226
+ void rebuild_urself (const char * binary_path , const char * source_path );
227
+
203
228
int path_is_dir (Cstr path );
204
229
#define IS_DIR (path ) path_is_dir(path)
205
230
@@ -214,6 +239,13 @@ void path_mkdirs(Cstr_Array path);
214
239
path_mkdirs(path); \
215
240
} while (0)
216
241
242
+ void path_rename (Cstr old_path , Cstr new_path );
243
+ #define RENAME (old_path , new_path ) \
244
+ do { \
245
+ INFO("RENAME: %s -> %s", old_path, new_path); \
246
+ path_rename(old_path, new_path); \
247
+ } while (0)
248
+
217
249
void path_rm (Cstr path );
218
250
#define RM (path ) \
219
251
do { \
@@ -909,6 +941,21 @@ int path_is_dir(Cstr path)
909
941
#endif // _WIN32
910
942
}
911
943
944
+ void path_rename (const char * old_path , const char * new_path )
945
+ {
946
+ #ifdef _WIN32
947
+ if (!MoveFileEx (old_path , new_path , MOVEFILE_REPLACE_EXISTING )) {
948
+ PANIC ("could not rename %s to %s: %s" , old_path , new_path ,
949
+ GetLastErrorAsString ());
950
+ }
951
+ #else
952
+ if (rename (old_path , new_path ) < 0 ) {
953
+ PANIC ("could not rename %s to %s: %s" , old_path , new_path ,
954
+ strerror (errno ));
955
+ }
956
+ #endif // _WIN32
957
+ }
958
+
912
959
void path_mkdirs (Cstr_Array path )
913
960
{
914
961
if (path .count == 0 ) {
@@ -977,6 +1024,41 @@ void path_rm(Cstr path)
977
1024
}
978
1025
}
979
1026
1027
+ int is_path1_modified_after_path2 (const char * path1 , const char * path2 )
1028
+ {
1029
+ #ifdef _WIN32
1030
+ FILETIME path1_time , path2_time ;
1031
+
1032
+ Fd path1_fd = fd_open_for_read (path1 );
1033
+ if (!GetFileTime (path1_fd , NULL , NULL , & path1_time )) {
1034
+ PANIC ("could not get time of %s: %s" , path1 , GetLastErrorAsString ());
1035
+ }
1036
+ fd_close (path1_fd );
1037
+
1038
+ Fd path2_fd = fd_open_for_read (path2 );
1039
+ if (!GetFileTime (path2_fd , NULL , NULL , & path2_time )) {
1040
+ PANIC ("could not get time of %s: %s" , path2 , GetLastErrorAsString ());
1041
+ }
1042
+ fd_close (path2_fd );
1043
+
1044
+ return CompareFileTime (& path1 , & path2 ) == 1 ;
1045
+ #else
1046
+ struct stat statbuf = {0 };
1047
+
1048
+ if (stat (path1 , & statbuf ) < 0 ) {
1049
+ PANIC ("could not stat %s: %s\n" , path1 , strerror (errno ));
1050
+ }
1051
+ int path1_time = statbuf .st_mtime ;
1052
+
1053
+ if (stat (path2 , & statbuf ) < 0 ) {
1054
+ PANIC ("could not stat %s: %s\n" , path2 , strerror (errno ));
1055
+ }
1056
+ int path2_time = statbuf .st_mtime ;
1057
+
1058
+ return path1_time > path2_time ;
1059
+ #endif
1060
+ }
1061
+
980
1062
void VLOG (FILE * stream , Cstr tag , Cstr fmt , va_list args )
981
1063
{
982
1064
fprintf (stream , "[%s] " , tag );
0 commit comments