@@ -69,7 +69,7 @@ class InstallOptions:
6969 mrdocs_build_tests : bool = True
7070 mrdocs_system_install : bool = field (default_factory = lambda : not running_from_mrdocs_source_dir ())
7171 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 "" )
7373 mrdocs_run_tests : bool = True
7474
7575 # Third-party dependencies
@@ -82,15 +82,6 @@ class InstallOptions:
8282 duktape_build_dir : str = "<duktape-src-dir>/build/<duktape-build-type:lower><\" -\" :if(cc)><cc:basename>"
8383 duktape_install_dir : str = "<duktape-src-dir>/install/<duktape-build-type:lower><\" -\" :if(cc)><cc:basename>"
8484
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-
9485 # LLVM
9586 llvm_src_dir : str = "<third-party-src-dir>/llvm-project"
9687 llvm_build_type : str = "<mrdocs-build-type>"
@@ -99,6 +90,14 @@ class InstallOptions:
9990 llvm_repo : str = "https://github.com/llvm/llvm-project.git"
10091 llvm_commit : str = "dd7a3d4d798e30dfe53b5bbbbcd9a23c24ea1af9"
10192
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+
102101 # Information to create run configurations
103102 generate_run_configs : bool = field (default_factory = lambda : running_from_mrdocs_source_dir ())
104103 jetbrains_run_config_dir : str = "<mrdocs-src-dir>/.run"
@@ -107,6 +106,7 @@ class InstallOptions:
107106 # Meta
108107 non_interactive : bool = False
109108
109+
110110# Constant for option descriptions
111111INSTALL_OPTION_DESCRIPTIONS = {
112112 "cc" : "Path to the C compiler executable. Leave empty for default." ,
@@ -117,7 +117,7 @@ class InstallOptions:
117117 "mrdocs_src_dir" : "MrDocs source directory." ,
118118 "mrdocs_repo" : "URL of the MrDocs repository to clone." ,
119119 "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)." ,
121121 "mrdocs_use_user_presets" : "Whether to use CMake User Presets for building MrDocs." ,
122122 "mrdocs_preset_name" : "Name of the CMake User Preset to use for MrDocs." ,
123123 "mrdocs_build_dir" : "Directory where MrDocs will be built." ,
@@ -128,17 +128,17 @@ class InstallOptions:
128128 "third_party_src_dir" : "Directory for all third-party source dependencies." ,
129129 "duktape_src_dir" : "Directory for the Duktape source code." ,
130130 "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)" ,
132132 "duktape_build_dir" : "Directory where Duktape will be built." ,
133133 "duktape_install_dir" : "Directory where Duktape will be installed." ,
134134 "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)" ,
136136 "libxml2_build_dir" : "Directory where libxml2 will be built." ,
137137 "libxml2_install_dir" : "Directory where libxml2 will be installed." ,
138138 "libxml2_repo" : "URL of the libxml2 repository to clone." ,
139139 "libxml2_branch" : "Branch or tag of libxml2 to use." ,
140140 "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)" ,
142142 "llvm_build_dir" : "Directory where LLVM will be built." ,
143143 "llvm_install_dir" : "Directory where LLVM will be installed." ,
144144 "llvm_repo" : "URL of the LLVM project repository to clone." ,
@@ -177,7 +177,7 @@ def prompt_string(self, prompt, default):
177177 Prompts the user for a string input with a default value.
178178
179179 :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.
181181 :return:
182182 """
183183 if self .options .non_interactive and default is not None :
@@ -190,7 +190,10 @@ def prompt_string(self, prompt, default):
190190 RESET = "\033 [0m"
191191 if self .supports_ansi ():
192192 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 )
194197 result = inp .strip () or default
195198 return result
196199
@@ -333,7 +336,7 @@ def reprompt_option(self, name):
333336
334337 def prompt_build_type_option (self , name ):
335338 value = self .prompt_option (name )
336- valid_build_types = ["Debug" , "Release" , "RelWithDebInfo" , "DebWithOpt" , " MinSizeRel" ]
339+ valid_build_types = ["Debug" , "Release" , "RelWithDebInfo" , "MinSizeRel" ]
337340 for t in valid_build_types :
338341 if t .lower () == value .lower ():
339342 setattr (self .options , name , t )
@@ -430,28 +433,24 @@ def is_macos(self):
430433 def cmake_workflow (self , src_dir , build_type , build_dir , install_dir , extra_args = None ):
431434 """
432435 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
437436 """
438437 config_args = [self .options .cmake_path , "-S" , src_dir ]
439438
440439 if self .options .cc and self .options .cxx :
441440 config_args .extend (["-DCMAKE_C_COMPILER=" + self .options .cc ,
442441 "-DCMAKE_CXX_COMPILER=" + self .options .cxx ])
443442
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
445444 # 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"
450449 if build_dir :
451450 config_args .extend (["-B" , build_dir ])
452451 if build_type :
453452 config_args .extend ([f"-DCMAKE_BUILD_TYPE={ cmake_build_type } " ])
454- if build_type_is_debwithopt :
453+ if build_type_is_optimizeddebug :
455454 if self .is_windows ():
456455 config_args .extend (["-DCMAKE_CXX_FLAGS=/DWIN32 /D_WINDOWS /Ob1 /O2 /Zi" ,
457456 "-DCMAKE_C_FLAGS=/DWIN32 /D_WINDOWS /Ob1 /O2 /Zi" ])
@@ -514,7 +513,8 @@ def check_compilers(self):
514513 if not os .path .isabs (getattr (self .options , option )):
515514 exec = shutil .which (getattr (self .options , option ))
516515 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." )
518518 setattr (self .options , option , exec )
519519 if not self .is_executable (getattr (self .options , option )):
520520 raise FileNotFoundError (f"{ option } executable not found at { getattr (self .options , option )} ." )
@@ -524,7 +524,7 @@ def check_tools(self):
524524 for tool in tools :
525525 self .check_tool (tool )
526526
527- def setup_mrdocs_dir (self ):
527+ def setup_mrdocs_src_dir (self ):
528528 self .prompt_option ("mrdocs_src_dir" )
529529 if not os .path .isabs (self .options .mrdocs_src_dir ):
530530 self .options .mrdocs_src_dir = os .path .abspath (self .options .mrdocs_src_dir )
@@ -582,6 +582,14 @@ def setup_third_party_dir(self):
582582 self .prompt_dependency_path_option ("third_party_src_dir" )
583583 os .makedirs (self .options .third_party_src_dir , exist_ok = True )
584584
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+
585593 def install_duktape (self ):
586594 self .prompt_dependency_path_option ("duktape_src_dir" )
587595 if not os .path .exists (self .options .duktape_src_dir ):
@@ -614,6 +622,16 @@ def install_duktape(self):
614622 else :
615623 print (f"Warning: { duk_config_path } does not exist. Skipping patch." )
616624 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
617635 self .prompt_dependency_path_option ("duktape_build_dir" )
618636 self .prompt_dependency_path_option ("duktape_install_dir" )
619637 self .cmake_workflow (self .options .duktape_src_dir , self .options .duktape_build_type ,
@@ -686,6 +704,12 @@ def install_llvm(self):
686704 patch_path = os .path .join (llvm_patches , patch_file )
687705 shutil .copy (patch_path , llvm_subproject_dir )
688706 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
689713 self .prompt_dependency_path_option ("llvm_build_dir" )
690714 self .prompt_dependency_path_option ("llvm_install_dir" )
691715 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):
714738 user_presets = json .load (f )
715739
716740 # 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"
717744 self .prompt_option ("mrdocs_preset_name" )
718745
719746 # Upsert the preset in the "configurePresets" array of objects
@@ -728,24 +755,30 @@ def create_cmake_presets(self):
728755 OSDisplayName = hostSystemName
729756 if OSDisplayName == "Darwin" :
730757 OSDisplayName = "macOS"
758+
759+ # Preset inherits from the parent preset based on the build type
731760 parent_preset_name = "debug"
732- if self .options .mrdocs_build_type .lower () == "release " :
761+ if self .options .mrdocs_build_type .lower () != "debug " :
733762 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 } )"
739771 if self .options .cc :
740772 display_name += f" ({ os .path .basename (self .options .cc )} )"
773+
741774 new_preset = {
742775 "name" : self .options .mrdocs_preset_name ,
743776 "displayName" : display_name ,
744777 "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 } ." ,
745778 "inherits" : parent_preset_name ,
746779 "binaryDir" : "${sourceDir}/build/${presetName}" ,
747780 "cacheVariables" : {
748- "CMAKE_BUILD_TYPE" : cmake_build_type ,
781+ "CMAKE_BUILD_TYPE" : self . options . mrdocs_build_type ,
749782 "LLVM_ROOT" : self .options .llvm_install_dir ,
750783 "Clang_ROOT" : self .options .llvm_install_dir ,
751784 "duktape_ROOT" : self .options .duktape_install_dir ,
@@ -808,16 +841,16 @@ def create_cmake_presets(self):
808841
809842 def install_mrdocs (self ):
810843 if not self .options .mrdocs_use_user_presets :
811- # Build directory specified in the preset
812844 self .prompt_option ("mrdocs_build_dir" )
813845 else :
814846 self .options .mrdocs_build_dir = os .path .join (self .options .mrdocs_src_dir , "build" ,
815847 self .options .mrdocs_preset_name )
816848 self .default_options .mrdocs_build_dir = self .options .mrdocs_build_dir
817849
818850 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 )
821854 self .prompt_option ("mrdocs_install_dir" )
822855
823856 extra_args = []
@@ -947,7 +980,8 @@ def generate_clion_run_configs(self, configs):
947980 if 'folder' in config :
948981 attrib ["folderName" ] = config ["folder" ]
949982 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' ])} " )
951985 ET .SubElement (clion_config , "option" , name = "INDEPENDENT_SCRIPT_PATH" , value = "true" )
952986 ET .SubElement (clion_config , "option" , name = "SCRIPT_PATH" , value = config ["script" ])
953987 ET .SubElement (clion_config , "option" , name = "SCRIPT_OPTIONS" , value = "" )
@@ -1005,7 +1039,8 @@ def generate_clion_run_configs(self, configs):
10051039 if 'folder' in config :
10061040 attrib ["folderName" ] = config ["folder" ]
10071041 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' ])} " )
10091044 ET .SubElement (clion_config , "option" , name = "INDEPENDENT_SCRIPT_PATH" , value = "true" )
10101045 ET .SubElement (clion_config , "option" , name = "SCRIPT_PATH" , value = config ["script" ])
10111046 ET .SubElement (clion_config , "option" , name = "SCRIPT_OPTIONS" , value = "" )
@@ -1345,12 +1380,12 @@ def generate_run_configs(self):
13451380 def install_all (self ):
13461381 self .check_compilers ()
13471382 self .check_tools ()
1348- self .setup_mrdocs_dir ()
1383+ self .setup_mrdocs_src_dir ()
13491384 self .setup_third_party_dir ()
13501385 self .install_duktape ()
1386+ self .install_llvm ()
13511387 if self .prompt_option ("mrdocs_build_tests" ):
13521388 self .install_libxml2 ()
1353- self .install_llvm ()
13541389 self .create_cmake_presets ()
13551390 self .install_mrdocs ()
13561391 if self .prompt_option ("generate_run_configs" ):
0 commit comments