@@ -115,6 +115,8 @@ class InstallOptions:
115
115
# Command line arguments
116
116
non_interactive : bool = False
117
117
refresh_all : bool = False
118
+ force_rebuild : bool = False
119
+ remove_build_dir : bool = True
118
120
119
121
120
122
# Constant for option descriptions
@@ -160,7 +162,9 @@ class InstallOptions:
160
162
"jetbrains_run_config_dir" : "Directory where JetBrains run configurations will be stored." ,
161
163
"boost_src_dir" : "Directory where the source files of the Boost libraries are located." ,
162
164
"non_interactive" : "Whether to use all default options without interactive prompts." ,
163
- "refresh_all" : "Call the command to refresh dependencies for all configurations"
165
+ "refresh_all" : "Call the command to refresh dependencies for all configurations" ,
166
+ "force_rebuild" : "Whether to force a rebuild of all dependencies, even if they are already built." ,
167
+ "remove_build_dir" : "Whether to remove the build directory of dependencies after installation." ,
164
168
}
165
169
166
170
@@ -466,11 +470,28 @@ def is_macos(self):
466
470
"""
467
471
return os .name == "posix" and sys .platform .startswith ("darwin" )
468
472
469
- def cmake_workflow (self , src_dir , build_type , build_dir , install_dir , extra_args = None , cc_flags = None , cxx_flags = None ):
473
+ def cmake_workflow (self , src_dir , build_type , build_dir , install_dir , extra_args = None , cc_flags = None ,
474
+ cxx_flags = None , force_rebuild = False , remove_build_dir = True ):
470
475
"""
471
476
Configures and builds a CMake project.
472
477
"""
473
478
479
+ # Check if we can skip the build
480
+ if self .is_non_empty_dir (install_dir ):
481
+ if force_rebuild or self .prompt_option ("force_rebuild" ):
482
+ print (f"Force rebuild requested. Removing existing install directory { install_dir } ." )
483
+ shutil .rmtree (install_dir , ignore_errors = True )
484
+ if self .is_non_empty_dir (build_dir ):
485
+ print (f"Removing existing build directory { build_dir } ." )
486
+ shutil .rmtree (build_dir , ignore_errors = True )
487
+ else :
488
+ print (f"Install directory { install_dir } already exists and is not empty. Skipping build." )
489
+ return
490
+ if self .is_non_empty_dir (build_dir ):
491
+ shutil .rmtree (build_dir , ignore_errors = True )
492
+ if self .is_non_empty_dir (install_dir ):
493
+ shutil .rmtree (install_dir , ignore_errors = True )
494
+
474
495
# Adjust any potential CMake flags from extra_args
475
496
if cc_flags is None :
476
497
cc_flags = ""
@@ -593,6 +614,8 @@ def cmake_workflow(self, src_dir, build_type, build_dir, install_dir, extra_args
593
614
if cmake_build_type :
594
615
install_args .extend (["--config" , cmake_build_type ])
595
616
self .run_cmd (install_args )
617
+ if remove_build_dir and self .prompt_option ('remove_build_dir' ):
618
+ shutil .rmtree (build_dir , ignore_errors = True )
596
619
597
620
def is_executable (self , path ):
598
621
if not os .path .exists (path ):
@@ -606,6 +629,14 @@ def is_executable(self, path):
606
629
else :
607
630
return os .access (path , os .X_OK )
608
631
632
+ def is_non_empty_dir (self , path ):
633
+ """
634
+ Checks if the given path is a non-empty directory.
635
+ :param path: The path to check.
636
+ :return: bool: True if the path is a non-empty directory, False otherwise.
637
+ """
638
+ return os .path .exists (path ) and os .path .isdir (path ) and len (os .listdir (path )) > 0
639
+
609
640
@lru_cache (maxsize = 1 )
610
641
def get_vs_install_locations (self ):
611
642
p = os .environ .get ('ProgramFiles(x86)' , r"C:\Program Files (x86)" )
@@ -1087,8 +1118,10 @@ def install_llvm(self):
1087
1118
self .prompt_option ("llvm_commit" )
1088
1119
os .makedirs (self .options .llvm_src_dir , exist_ok = True )
1089
1120
self .run_cmd ([self .options .git_path , "init" ], self .options .llvm_src_dir )
1090
- self .run_cmd ([self .options .git_path , "remote" , "add" , "origin" , self .options .llvm_repo ], self .options .llvm_src_dir )
1091
- self .run_cmd ([self .options .git_path , "fetch" , "--depth" , "1" , "origin" , self .options .llvm_commit ], self .options .llvm_src_dir )
1121
+ self .run_cmd ([self .options .git_path , "remote" , "add" , "origin" , self .options .llvm_repo ],
1122
+ self .options .llvm_src_dir )
1123
+ self .run_cmd ([self .options .git_path , "fetch" , "--depth" , "1" , "origin" , self .options .llvm_commit ],
1124
+ self .options .llvm_src_dir )
1092
1125
self .run_cmd ([self .options .git_path , "checkout" , "FETCH_HEAD" ], self .options .llvm_src_dir )
1093
1126
1094
1127
llvm_subproject_dir = os .path .join (self .options .llvm_src_dir , "llvm" )
@@ -1283,7 +1316,6 @@ def create_cmake_presets(self):
1283
1316
new_preset ["cacheVariables" ]["GIT_EXECUTABLE" ] = self .options .git_path
1284
1317
new_preset ["cacheVariables" ]["GIT_ROOT" ] = os .path .dirname (self .options .git_path )
1285
1318
1286
-
1287
1319
# Update cache variables path prefixes with their relative equivalents
1288
1320
mrdocs_src_dir_parent = os .path .dirname (self .options .mrdocs_src_dir )
1289
1321
if mrdocs_src_dir_parent == self .options .mrdocs_src_dir :
@@ -1365,7 +1397,7 @@ def install_mrdocs(self):
1365
1397
f"-D{ arg } =-fsanitize={ flag_name } -fno-sanitize-recover={ flag_name } -fno-omit-frame-pointer" )
1366
1398
1367
1399
self .cmake_workflow (self .options .mrdocs_src_dir , self .options .mrdocs_build_type , self .options .mrdocs_build_dir ,
1368
- self .options .mrdocs_install_dir , extra_args )
1400
+ self .options .mrdocs_install_dir , extra_args , force_rebuild = True , remove_build_dir = False )
1369
1401
1370
1402
if self .options .mrdocs_build_dir and self .prompt_option ("mrdocs_run_tests" ):
1371
1403
# Look for ctest path relative to the cmake path
@@ -2120,6 +2152,7 @@ def refresh_all(self):
2120
2152
print (f"Running bootstrap refresh with arguments: { args } " )
2121
2153
subprocess .run (args , check = True )
2122
2154
2155
+
2123
2156
def get_command_line_args ():
2124
2157
"""
2125
2158
Parses command line arguments and returns them as a dictionary.
0 commit comments