@@ -69,7 +69,7 @@ class InstallOptions:
69
69
mrdocs_build_tests : bool = True
70
70
mrdocs_system_install : bool = field (default_factory = lambda : not running_from_mrdocs_source_dir ())
71
71
mrdocs_install_dir : str = field (
72
- default_factory = lambda : "<mrdocs-src-dir>/install/<mrdocs-build-type:lower>-<os:lower>- <cc:basename>" if running_from_mrdocs_source_dir () else "" )
72
+ default_factory = lambda : "<mrdocs-src-dir>/install/<mrdocs-build-type:lower>-<os:lower>< \" - \" :if(cc)> <cc:basename>" if running_from_mrdocs_source_dir () else "" )
73
73
mrdocs_run_tests : bool = True
74
74
75
75
# Third-party dependencies
@@ -82,15 +82,6 @@ class InstallOptions:
82
82
duktape_build_dir : str = "<duktape-src-dir>/build/<duktape-build-type:lower><\" -\" :if(cc)><cc:basename>"
83
83
duktape_install_dir : str = "<duktape-src-dir>/install/<duktape-build-type:lower><\" -\" :if(cc)><cc:basename>"
84
84
85
- # Libxml2
86
- libxml2_src_dir : str = "<third-party-src-dir>/libxml2"
87
- # purposefully does not depend on mrdocs-build-type because we only need the executable
88
- libxml2_build_type : str = "Release"
89
- libxml2_build_dir : str = "<libxml2-src-dir>/build/<libxml2-build-type:lower><\" -\" :if(cc)><cc:basename>"
90
- libxml2_install_dir : str = "<libxml2-src-dir>/install/<libxml2-build-type:lower><\" -\" :if(cc)><cc:basename>"
91
- libxml2_repo : str = "https://github.com/GNOME/libxml2"
92
- libxml2_branch : str = "v2.12.6"
93
-
94
85
# LLVM
95
86
llvm_src_dir : str = "<third-party-src-dir>/llvm-project"
96
87
llvm_build_type : str = "<mrdocs-build-type>"
@@ -99,6 +90,14 @@ class InstallOptions:
99
90
llvm_repo : str = "https://github.com/llvm/llvm-project.git"
100
91
llvm_commit : str = "dd7a3d4d798e30dfe53b5bbbbcd9a23c24ea1af9"
101
92
93
+ # Libxml2
94
+ libxml2_src_dir : str = "<third-party-src-dir>/libxml2"
95
+ libxml2_build_type : str = "Release" # purposefully does not depend on mrdocs-build-type because we only need the executable
96
+ libxml2_build_dir : str = "<libxml2-src-dir>/build/<libxml2-build-type:lower><\" -\" :if(cc)><cc:basename>"
97
+ libxml2_install_dir : str = "<libxml2-src-dir>/install/<libxml2-build-type:lower><\" -\" :if(cc)><cc:basename>"
98
+ libxml2_repo : str = "https://github.com/GNOME/libxml2"
99
+ libxml2_branch : str = "v2.12.6"
100
+
102
101
# Information to create run configurations
103
102
generate_run_configs : bool = field (default_factory = lambda : running_from_mrdocs_source_dir ())
104
103
jetbrains_run_config_dir : str = "<mrdocs-src-dir>/.run"
@@ -107,6 +106,7 @@ class InstallOptions:
107
106
# Meta
108
107
non_interactive : bool = False
109
108
109
+
110
110
# Constant for option descriptions
111
111
INSTALL_OPTION_DESCRIPTIONS = {
112
112
"cc" : "Path to the C compiler executable. Leave empty for default." ,
@@ -117,7 +117,7 @@ class InstallOptions:
117
117
"mrdocs_src_dir" : "MrDocs source directory." ,
118
118
"mrdocs_repo" : "URL of the MrDocs repository to clone." ,
119
119
"mrdocs_branch" : "Branch or tag of the MrDocs repository to use." ,
120
- "mrdocs_build_type" : "CMake build type for MrDocs (Release, Debug, RelWithDebInfo, MilRelSize, DebWithOpt )." ,
120
+ "mrdocs_build_type" : "CMake build type for MrDocs (Release, Debug, RelWithDebInfo, MilRelSize)." ,
121
121
"mrdocs_use_user_presets" : "Whether to use CMake User Presets for building MrDocs." ,
122
122
"mrdocs_preset_name" : "Name of the CMake User Preset to use for MrDocs." ,
123
123
"mrdocs_build_dir" : "Directory where MrDocs will be built." ,
@@ -128,17 +128,17 @@ class InstallOptions:
128
128
"third_party_src_dir" : "Directory for all third-party source dependencies." ,
129
129
"duktape_src_dir" : "Directory for the Duktape source code." ,
130
130
"duktape_url" : "Download URL for the Duktape source archive." ,
131
- "duktape_build_type" : "CMake build type for Duktape. (Release, Debug, RelWithDebInfo, MilRelSize, DebWithOpt )" ,
131
+ "duktape_build_type" : "CMake build type for Duktape. (Release, Debug, RelWithDebInfo, MilRelSize)" ,
132
132
"duktape_build_dir" : "Directory where Duktape will be built." ,
133
133
"duktape_install_dir" : "Directory where Duktape will be installed." ,
134
134
"libxml2_src_dir" : "Directory for the libxml2 source code." ,
135
- "libxml2_build_type" : "CMake build type for libxml2. (Release, Debug, RelWithDebInfo, MilRelSize, DebWithOpt )" ,
135
+ "libxml2_build_type" : "CMake build type for libxml2: Release always recommended . (Release, Debug, RelWithDebInfo, MilRelSize)" ,
136
136
"libxml2_build_dir" : "Directory where libxml2 will be built." ,
137
137
"libxml2_install_dir" : "Directory where libxml2 will be installed." ,
138
138
"libxml2_repo" : "URL of the libxml2 repository to clone." ,
139
139
"libxml2_branch" : "Branch or tag of libxml2 to use." ,
140
140
"llvm_src_dir" : "Directory for the LLVM project source code." ,
141
- "llvm_build_type" : "CMake build type for LLVM. (Release, Debug, RelWithDebInfo, MilRelSize, DebWithOpt )" ,
141
+ "llvm_build_type" : "CMake build type for LLVM. (Release, Debug, RelWithDebInfo, MilRelSize)" ,
142
142
"llvm_build_dir" : "Directory where LLVM will be built." ,
143
143
"llvm_install_dir" : "Directory where LLVM will be installed." ,
144
144
"llvm_repo" : "URL of the LLVM project repository to clone." ,
@@ -177,7 +177,7 @@ def prompt_string(self, prompt, default):
177
177
Prompts the user for a string input with a default value.
178
178
179
179
:param prompt: The prompt message to display to the user.
180
- : param default: The default value to use if the user does not provide input.
180
+ :param default: The default value to use if the user does not provide input.
181
181
:return:
182
182
"""
183
183
if self .options .non_interactive and default is not None :
@@ -190,7 +190,10 @@ def prompt_string(self, prompt, default):
190
190
RESET = "\033 [0m"
191
191
if self .supports_ansi ():
192
192
prompt = f"{ BLUE } { prompt } { RESET } "
193
- inp = input (f"{ prompt } ({ default } ): " )
193
+ if default :
194
+ prompt += f" ({ default } )"
195
+ prompt += f": "
196
+ inp = input (prompt )
194
197
result = inp .strip () or default
195
198
return result
196
199
@@ -333,7 +336,7 @@ def reprompt_option(self, name):
333
336
334
337
def prompt_build_type_option (self , name ):
335
338
value = self .prompt_option (name )
336
- valid_build_types = ["Debug" , "Release" , "RelWithDebInfo" , "DebWithOpt" , " MinSizeRel" ]
339
+ valid_build_types = ["Debug" , "Release" , "RelWithDebInfo" , "MinSizeRel" ]
337
340
for t in valid_build_types :
338
341
if t .lower () == value .lower ():
339
342
setattr (self .options , name , t )
@@ -430,28 +433,24 @@ def is_macos(self):
430
433
def cmake_workflow (self , src_dir , build_type , build_dir , install_dir , extra_args = None ):
431
434
"""
432
435
Configures and builds a CMake project.
433
- :param src: The source directory containing the CMakeLists.txt file.
434
- :param build: The build directory where the project will be built.
435
- :param extra_args: Additional arguments to pass to the CMake configuration command.
436
- :return: None
437
436
"""
438
437
config_args = [self .options .cmake_path , "-S" , src_dir ]
439
438
440
439
if self .options .cc and self .options .cxx :
441
440
config_args .extend (["-DCMAKE_C_COMPILER=" + self .options .cc ,
442
441
"-DCMAKE_CXX_COMPILER=" + self .options .cxx ])
443
442
444
- # "DebWithOpt " is not a valid type. However, we interpret it as a special case
443
+ # "OptimizedDebug " is not a valid build type. We interpret it as a special case
445
444
# where the build type is Debug and optimizations are enabled.
446
- # This is not very different from RelWithDebInfo on Unix, but ensures
447
- # Debug flags are used on Windows.
448
- build_type_is_debwithopt = build_type .lower () == 'debwithopt '
449
- cmake_build_type = build_type if not build_type_is_debwithopt else "Debug"
445
+ # This is equivalent to RelWithDebInfo on Unix, but ensures
446
+ # Debug flags and the Debug ABI are used on Windows.
447
+ build_type_is_optimizeddebug = build_type .lower () == 'optimizeddebug '
448
+ cmake_build_type = build_type if not build_type_is_optimizeddebug else "Debug"
450
449
if build_dir :
451
450
config_args .extend (["-B" , build_dir ])
452
451
if build_type :
453
452
config_args .extend ([f"-DCMAKE_BUILD_TYPE={ cmake_build_type } " ])
454
- if build_type_is_debwithopt :
453
+ if build_type_is_optimizeddebug :
455
454
if self .is_windows ():
456
455
config_args .extend (["-DCMAKE_CXX_FLAGS=/DWIN32 /D_WINDOWS /Ob1 /O2 /Zi" ,
457
456
"-DCMAKE_C_FLAGS=/DWIN32 /D_WINDOWS /Ob1 /O2 /Zi" ])
@@ -514,7 +513,8 @@ def check_compilers(self):
514
513
if not os .path .isabs (getattr (self .options , option )):
515
514
exec = shutil .which (getattr (self .options , option ))
516
515
if exec is None :
517
- raise FileNotFoundError (f"{ option } executable '{ getattr (self .options , option )} ' not found in PATH." )
516
+ raise FileNotFoundError (
517
+ f"{ option } executable '{ getattr (self .options , option )} ' not found in PATH." )
518
518
setattr (self .options , option , exec )
519
519
if not self .is_executable (getattr (self .options , option )):
520
520
raise FileNotFoundError (f"{ option } executable not found at { getattr (self .options , option )} ." )
@@ -524,7 +524,7 @@ def check_tools(self):
524
524
for tool in tools :
525
525
self .check_tool (tool )
526
526
527
- def setup_mrdocs_dir (self ):
527
+ def setup_mrdocs_src_dir (self ):
528
528
self .prompt_option ("mrdocs_src_dir" )
529
529
if not os .path .isabs (self .options .mrdocs_src_dir ):
530
530
self .options .mrdocs_src_dir = os .path .abspath (self .options .mrdocs_src_dir )
@@ -582,6 +582,14 @@ def setup_third_party_dir(self):
582
582
self .prompt_dependency_path_option ("third_party_src_dir" )
583
583
os .makedirs (self .options .third_party_src_dir , exist_ok = True )
584
584
585
+ def is_abi_compatible (self , build_type_a , build_type_b ):
586
+ if not self .is_windows ():
587
+ return True
588
+ # On Windows, Debug and Release builds are not ABI compatible
589
+ build_type_a_is_debug = build_type_a .lower () == "debug"
590
+ build_type_b_is_debug = build_type_b .lower () == "debug"
591
+ return build_type_a_is_debug == build_type_b_is_debug
592
+
585
593
def install_duktape (self ):
586
594
self .prompt_dependency_path_option ("duktape_src_dir" )
587
595
if not os .path .exists (self .options .duktape_src_dir ):
@@ -614,6 +622,16 @@ def install_duktape(self):
614
622
else :
615
623
print (f"Warning: { duk_config_path } does not exist. Skipping patch." )
616
624
self .prompt_build_type_option ("duktape_build_type" )
625
+ if not self .is_abi_compatible (self .options .mrdocs_build_type , self .options .duktape_build_type ):
626
+ if self .options .mrdocs_build_type .lower () == "debug" :
627
+ # User asked for Release dependency, so we do the best we can and change it to
628
+ # an optimized debug build.
629
+ self .options .duktape_build_type = "OptimizedDebug"
630
+ else :
631
+ # User asked for a Debug dependency with Release build type for MrDocs.
632
+ # The dependency should just copy the release type here. Other options wouldn't make sense
633
+ # because we can't even debug it.
634
+ self .options .duktape_build_type = self .options .mrdocs_build_type
617
635
self .prompt_dependency_path_option ("duktape_build_dir" )
618
636
self .prompt_dependency_path_option ("duktape_install_dir" )
619
637
self .cmake_workflow (self .options .duktape_src_dir , self .options .duktape_build_type ,
@@ -686,6 +704,12 @@ def install_llvm(self):
686
704
patch_path = os .path .join (llvm_patches , patch_file )
687
705
shutil .copy (patch_path , llvm_subproject_dir )
688
706
self .prompt_build_type_option ("llvm_build_type" )
707
+ # Same logic as for Duktape
708
+ if not self .is_abi_compatible (self .options .mrdocs_build_type , self .options .llvm_build_type ):
709
+ if self .options .mrdocs_build_type .lower () == "debug" :
710
+ self .options .llvm_build_type = "OptimizedDebug"
711
+ else :
712
+ self .options .llvm_build_type = self .options .mrdocs_build_type
689
713
self .prompt_dependency_path_option ("llvm_build_dir" )
690
714
self .prompt_dependency_path_option ("llvm_install_dir" )
691
715
cmake_preset = f"{ self .options .llvm_build_type .lower ()} -win" if self .is_windows () else f"{ self .options .llvm_build_type .lower ()} -unix"
@@ -714,6 +738,9 @@ def create_cmake_presets(self):
714
738
user_presets = json .load (f )
715
739
716
740
# Come up with a nice user preset name
741
+ is_debug_fast = self .options .mrdocs_build_type .lower () == "debug" and self .options .llvm_build_type != self .options .mrdocs_build_type
742
+ if is_debug_fast :
743
+ self .default_options .mrdocs_preset_name += "-fast"
717
744
self .prompt_option ("mrdocs_preset_name" )
718
745
719
746
# Upsert the preset in the "configurePresets" array of objects
@@ -728,24 +755,30 @@ def create_cmake_presets(self):
728
755
OSDisplayName = hostSystemName
729
756
if OSDisplayName == "Darwin" :
730
757
OSDisplayName = "macOS"
758
+
759
+ # Preset inherits from the parent preset based on the build type
731
760
parent_preset_name = "debug"
732
- if self .options .mrdocs_build_type .lower () == "release " :
761
+ if self .options .mrdocs_build_type .lower () != "debug " :
733
762
parent_preset_name = "release"
734
- elif self .options .mrdocs_build_type .lower () == "relwithdebinfo" :
735
- parent_preset_name = "relwithdebinfo"
736
- build_type_is_debwithopt = self .options .mrdocs_build_type .lower () == 'debwithopt'
737
- cmake_build_type = self .options .mrdocs_build_type if not build_type_is_debwithopt else "Debug"
738
- display_name = f"{ self .options .mrdocs_build_type } { OSDisplayName } "
763
+ if self .options .mrdocs_build_type .lower () == "relwithdebinfo" :
764
+ parent_preset_name = "relwithdebinfo"
765
+
766
+ # Nice display name for the preset
767
+ display_name = f"{ self .options .mrdocs_build_type } "
768
+ if self .options .mrdocs_build_type .lower () == "debug" and self .options .llvm_build_type != self .options .mrdocs_build_type :
769
+ display_name += " with Optimized Dependencies"
770
+ display_name += f" ({ OSDisplayName } )"
739
771
if self .options .cc :
740
772
display_name += f" ({ os .path .basename (self .options .cc )} )"
773
+
741
774
new_preset = {
742
775
"name" : self .options .mrdocs_preset_name ,
743
776
"displayName" : display_name ,
744
777
"description" : f"Preset for building MrDocs in { self .options .mrdocs_build_type } mode with the { os .path .basename (self .options .cc ) if self .options .cc else 'default' } compiler in { OSDisplayName } ." ,
745
778
"inherits" : parent_preset_name ,
746
779
"binaryDir" : "${sourceDir}/build/${presetName}" ,
747
780
"cacheVariables" : {
748
- "CMAKE_BUILD_TYPE" : cmake_build_type ,
781
+ "CMAKE_BUILD_TYPE" : self . options . mrdocs_build_type ,
749
782
"LLVM_ROOT" : self .options .llvm_install_dir ,
750
783
"Clang_ROOT" : self .options .llvm_install_dir ,
751
784
"duktape_ROOT" : self .options .duktape_install_dir ,
@@ -808,16 +841,16 @@ def create_cmake_presets(self):
808
841
809
842
def install_mrdocs (self ):
810
843
if not self .options .mrdocs_use_user_presets :
811
- # Build directory specified in the preset
812
844
self .prompt_option ("mrdocs_build_dir" )
813
845
else :
814
846
self .options .mrdocs_build_dir = os .path .join (self .options .mrdocs_src_dir , "build" ,
815
847
self .options .mrdocs_preset_name )
816
848
self .default_options .mrdocs_build_dir = self .options .mrdocs_build_dir
817
849
818
850
if not self .prompt_option ("mrdocs_system_install" ):
819
- # Build directory specified in the preset
820
- # self.prompt_option("mrdocs_build_dir")
851
+ if self .options .mrdocs_use_user_presets :
852
+ self .default_options .mrdocs_install_dir = os .path .join (self .options .mrdocs_src_dir , "install" ,
853
+ self .options .mrdocs_preset_name )
821
854
self .prompt_option ("mrdocs_install_dir" )
822
855
823
856
extra_args = []
@@ -947,7 +980,8 @@ def generate_clion_run_configs(self, configs):
947
980
if 'folder' in config :
948
981
attrib ["folderName" ] = config ["folder" ]
949
982
clion_config = ET .SubElement (root , "configuration" , attrib )
950
- ET .SubElement (clion_config , "option" , name = "SCRIPT_TEXT" , value = f"bash { shlex .quote (config ['script' ])} " )
983
+ ET .SubElement (clion_config , "option" , name = "SCRIPT_TEXT" ,
984
+ value = f"bash { shlex .quote (config ['script' ])} " )
951
985
ET .SubElement (clion_config , "option" , name = "INDEPENDENT_SCRIPT_PATH" , value = "true" )
952
986
ET .SubElement (clion_config , "option" , name = "SCRIPT_PATH" , value = config ["script" ])
953
987
ET .SubElement (clion_config , "option" , name = "SCRIPT_OPTIONS" , value = "" )
@@ -1005,7 +1039,8 @@ def generate_clion_run_configs(self, configs):
1005
1039
if 'folder' in config :
1006
1040
attrib ["folderName" ] = config ["folder" ]
1007
1041
clion_config = ET .SubElement (root , "configuration" , attrib )
1008
- ET .SubElement (clion_config , "option" , name = "SCRIPT_TEXT" , value = f"{ shlex .quote (config ['script' ])} { ' ' .join (shlex .quote (arg ) for arg in config ['args' ])} " )
1042
+ ET .SubElement (clion_config , "option" , name = "SCRIPT_TEXT" ,
1043
+ value = f"{ shlex .quote (config ['script' ])} { ' ' .join (shlex .quote (arg ) for arg in config ['args' ])} " )
1009
1044
ET .SubElement (clion_config , "option" , name = "INDEPENDENT_SCRIPT_PATH" , value = "true" )
1010
1045
ET .SubElement (clion_config , "option" , name = "SCRIPT_PATH" , value = config ["script" ])
1011
1046
ET .SubElement (clion_config , "option" , name = "SCRIPT_OPTIONS" , value = "" )
@@ -1345,12 +1380,12 @@ def generate_run_configs(self):
1345
1380
def install_all (self ):
1346
1381
self .check_compilers ()
1347
1382
self .check_tools ()
1348
- self .setup_mrdocs_dir ()
1383
+ self .setup_mrdocs_src_dir ()
1349
1384
self .setup_third_party_dir ()
1350
1385
self .install_duktape ()
1386
+ self .install_llvm ()
1351
1387
if self .prompt_option ("mrdocs_build_tests" ):
1352
1388
self .install_libxml2 ()
1353
- self .install_llvm ()
1354
1389
self .create_cmake_presets ()
1355
1390
self .install_mrdocs ()
1356
1391
if self .prompt_option ("generate_run_configs" ):
0 commit comments