Sync with WRF developments
[WPS.git] / arch / configure_reader.py
blob69f71aa6e93c46c80e8ef5ec2c48f0da528679ab
1 #!/usr/bin/env python3
3 import argparse
4 import sys
5 import os
6 import re
7 import inspect
8 import platform
9 from shutil import which
11 archBlock = re.compile( r"(?:#[ ]*)(ARCH(?:.*\n)*?)(?:#{5,})", re.I )
12 kvPair = re.compile( r"^(\w+)(?:[ \t]*=[ \t]*)(.*?)$", re.I | re.M )
13 # Make this gnarly and complicated since configure.defaults has no standard formatting
14 # v start v OS V typical v MACOS
15 osAndArch = re.compile( r"^ARCH[ ]+(\w+)[ ]+((?:\w+.*?),|(?:[(].*?[)]))", re.I )
16 # Just grab the first two words, thats what you get
17 osAndArchAlt = re.compile( r"^ARCH[ ]+(\w+)[ ]+(\w+)", re.I )
19 referenceVar = re.compile( r"[$]([(])?(\w+)(?(1)[)])", re.I )
20 compileObject = re.compile( r"(\W)-c(\W)" )
22 class Stanza():
24 def __init__( self, lines ) :
25 self.lines_ = lines
26 self.os_ = None
27 self.arch_ = None
28 self.osArchLine_ = None
29 self.archs_ = []
30 self.kvPairs_ = {}
31 self.crossPlatform_ = False
32 self.skipCrossPlatform_ = True
33 self.serialOpt_ = False
34 self.smparOpt_ = False
35 self.dmparOpt_ = False
36 self.dmsmOpt_ = False
38 def parse( self ) :
39 self.osArchLine_ = self.lines_.partition("\n")[0]
40 # First get os & archs
41 osarchMatch = osAndArch.match( self.osArchLine_ )
43 if osarchMatch is None :
44 osarchMatch = osAndArchAlt.match( self.osArchLine_ )
45 if osarchMatch is None :
46 print( "Could not find OS and architecture info in " + self.osArchLine_ )
48 self.os_ = osarchMatch.group(1)
49 self.archs_ = osarchMatch.group(2).strip(",").split( " " )
51 if ( self.os_.lower() != platform.system().lower() or
52 platform.machine() not in self.archs_ ) :
53 self.crossPlatform_ = True
55 # Allow cross platform or must not be cross platform
56 if not self.skipCrossPlatform_ or ( self.skipCrossPlatform_ and not self.crossPlatform_ ) :
58 # Find OpenMP/MPI compilation options
59 memOpts = self.osArchLine_.partition( "#" )[-1].split( " " )
60 # print( memOpts )
61 self.serialOpt_ = "serial" in memOpts
62 self.smparOpt_ = "smpar" in memOpts
63 self.dmparOpt_ = "dmpar" in memOpts
64 self.dmsmOpt_ = "dm+sm" in memOpts
66 for kvPairMatch in kvPair.finditer( self.lines_ ) :
67 self.kvPairs_[ kvPairMatch.group(1) ] = kvPairMatch.group(2)
68 self.removeComments( kvPairMatch.group(1) )
70 # Now sanitize
71 self.sanitize()
73 ######################################################################################################################
75 ## search and replace $(<var>) and $<var> instances
77 ######################################################################################################################
78 def dereference( self, field, fatal=False ) :
79 # print( "Dereferencing " + field )
81 if field in self.kvPairs_ :
82 prevField = self.kvPairs_[field]
84 for refVarIter in referenceVar.finditer( prevField ) :
85 envSub = None
87 if refVarIter is not None :
88 # Grab group 1 and check that it is in our kv pairs
89 refVar = refVarIter.group(2)
90 # print( "Found variable {0} in field {1}".format( refVar, field ) )
91 if refVar not in self.kvPairs_ :
92 # Try to use the environment variables
93 if refVar in os.environ :
94 envSub = os.environ[ refVar ]
95 else:
96 if fatal :
97 # print( "Could not rereference : " + refVar )
98 exit(1)
99 else:
100 continue
103 # This is an environment variable
104 if envSub is not None :
105 self.kvPairs_[field] = self.kvPairs_[field].replace(
106 "{var}".format( var=refVarIter.group(0) ),
107 envSub
109 # This is a kv pair, recurse
110 else :
111 # Recursively deref
112 self.dereference( refVar, fatal )
114 # Replace in original
115 self.kvPairs_[field] = self.kvPairs_[field].replace(
116 "{var}".format( var=refVarIter.group(0) ),
117 self.kvPairs_[refVar]
120 def removeReferences( self, field, specifics=[] ) :
121 if field in self.kvPairs_ :
122 if specifics :
123 for specific in specifics :
124 self.kvPairs_[ field ] = self.kvPairs_[ field ].replace(
125 "$({var})".format( var=specific ),
128 else :
129 self.kvPairs_[ field ] = referenceVar.sub( "", self.kvPairs_[ field ] )
132 def removeComments( self, field ) :
133 if field in self.kvPairs_ :
134 self.kvPairs_[ field ] = self.kvPairs_[ field ].split( "#", 1 )[0]
136 def splitIntoFieldAndFlags( self, field ) :
137 # Fix flags being mixed with programs
138 if field in self.kvPairs_ :
139 fieldValue = self.kvPairs_[ field ]
141 self.kvPairs_[field] = fieldValue.partition(" ")[0]
142 self.kvPairs_[field + "_FLAGS"] = fieldValue.partition(" ")[1]
144 ######################################################################################################################
146 ## Clean up the stanza so kv pairs can be used as-is
148 ######################################################################################################################
149 def sanitize( self ) :
150 # Fix problematic variables
151 self.dereference( "DM_FC" )
152 self.dereference( "DM_CC" )
153 self.removeReferences( "FCBASEOPTS_NO_G" )
154 # Get rid of all these mixed up flags, these are handled by cmake natively or
155 # just in the wrong place
156 self.removeReferences( "FCBASEOPTS", [ "FCDEBUG", "FORMAT_FREE", "BYTESWAPIO", ] )
157 self.removeReferences( "FFLAGS", [ "FORMAT_FREE", "FORMAT_FIXED" ] )
158 self.removeReferences( "F77FLAGS", [ "FORMAT_FREE", "FORMAT_FIXED" ] )
159 # # Now deref
160 self.dereference( "FCBASEOPTS" )
162 # Remove rogue compile commands that should *NOT* even be here
163 keysToSanitize = [
164 "ARFLAGS","ARFLAGS",
165 "CC",
166 "CFLAGS_LOCAL",
167 "CFLAGS",
168 "COMPRESSION_INC",
169 "COMPRESSION_LIBS",
170 "CPP",
171 "CPPFLAGS",
172 "DM_CC",
173 "DM_FC",
174 "ESMF_LDFLAG",
175 "F77FLAGS",
176 "FC",
177 "FCBASEOPTS_NO_G",
178 "FCBASEOPTS",
179 "FCOPTIM",
180 "FCSUFFIX",
181 "FDEFS",
182 "FFLAGS",
183 "FNGFLAGS",
184 "FORMAT_FIXED",
185 "FORMAT_FREE",
186 "LD",
187 "LDFLAGS_LOCAL",
188 "LDFLAGS",
189 "MODULE_SRCH_FLAG",
190 "RLFLAGS",
191 "SCC",
192 "SFC",
193 "TRADFLAG",
196 for keyToSan in keysToSanitize :
197 if keyToSan in self.kvPairs_ :
198 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_COMP_L", "" )
199 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_COMP_I", "" )
200 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_FC", "" )
201 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_CC", "" )
202 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_FDEFS", "" )
203 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_MPI", "" )
204 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_COMPAT_FLAGS", "" )
205 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_CPPFLAGS", "" )
206 self.kvPairs_[ keyToSan ] = self.kvPairs_[ keyToSan ].replace( "CONFIGURE_TRADFLAG", "" )
208 self.kvPairs_[ keyToSan ] = compileObject.sub( r"\1\2", self.kvPairs_[ keyToSan ] ).strip()
211 # Now fix certain ones that are mixing programs with flags all mashed into one option
212 self.splitIntoFieldAndFlags( "SFC" )
213 self.splitIntoFieldAndFlags( "SCC" )
214 self.splitIntoFieldAndFlags( "DM_FC" )
215 self.splitIntoFieldAndFlags( "DM_CC" )
216 self.splitIntoFieldAndFlags( "CPP" )
217 self.splitIntoFieldAndFlags( "M4" )
219 # Now deref all the rest
220 for key in self.kvPairs_ :
221 self.dereference( key )
222 # And for final measure strip
223 self.kvPairs_[ key ] = self.kvPairs_[ key ].strip()
225 def serialCompilersAvailable( self ) :
226 return which( self.kvPairs_["SFC"] ) is not None and which( self.kvPairs_["SCC"] ) is not None
228 def dmCompilersAvailable( self ) :
229 return which( self.kvPairs_["DM_FC"] ) is not None and which( self.kvPairs_["DM_CC"] ) is not None
231 ######################################################################################################################
233 ## string representation to view as option
235 ######################################################################################################################
236 def __str__( self ):
237 # base = """OS {os:<8} ARCHITECTURES {archs:<20}
238 # >> SFC = {SFC:<12}
239 # >> SCC = {SCC:<12}
240 # >> CCOMP = {CCOMP:<12}
241 # >> DM_FC = {DM_FC:<12}
242 # >> DM_CC = {DM_CC:<12}
243 # """
244 base = """ {os:<10} {recSFC} {SFC:<11} / {recSCC} {SCC:<11} / {recDM_FC} {DM_FC:<11} / {recDM_CC} {DM_CC:<11}"""
245 text = inspect.cleandoc( base ).format(
246 os=str(self.os_),
247 recSFC =( "!!" if which( self.kvPairs_["SFC"] ) is None else (" " * 2 ) ),
248 recSCC =( "!!" if which( self.kvPairs_["SCC"] ) is None else (" " * 2 ) ),
249 recDM_FC=( "!!" if which( self.kvPairs_["DM_FC"] ) is None else (" " * 2 ) ),
250 recDM_CC=( "!!" if which( self.kvPairs_["DM_CC"] ) is None else (" " * 2 ) ),
251 # archs=str(self.archs_),
252 SFC=str( self.kvPairs_["SFC"] ),
253 SCC=str( self.kvPairs_["SCC"] ),
254 DM_FC=str( self.kvPairs_["DM_FC"] ),
255 DM_CC=str( self.kvPairs_["DM_CC"] )
257 # text += "\n" + "\n".join( [ "{key:<18} = {value}".format( key=key, value=value) for key, value in self.kvPairs_.items() ] )
258 return text
260 ######################################################################################################################
262 ## Find first apparent difference between two stanzas
264 ######################################################################################################################
265 @staticmethod
266 def findFirstDifference( rhStanza, lhStanza, maxLength=32 ) :
267 diff = False
268 value = ""
269 valuesToCheck = [
270 "ARCH_LOCAL",
271 "BYTESWAPIO",
272 "CFLAGS_LOCAL",
273 "CFLAGS",
274 "DM_CC_FLAGS",
275 "DM_CC",
276 "DM_FC_FLAGS",
277 "DM_FC",
278 "FCBASEOPTS",
279 "FCDEBUG",
280 "FCNOOPT",
281 "FCOPTIM",
282 "FFLAGS",
283 "M4_FLAGS",
284 "SCC",
285 "SFC"
287 for rhKey, rhValue in rhStanza.kvPairs_.items() :
288 if rhKey in valuesToCheck and rhKey in lhStanza.kvPairs_ :
289 # Qualifies for difference
290 if rhValue != lhStanza.kvPairs_[rhKey] :
291 diff = True
292 value = "{key:<12} = {value}".format( key=rhKey, value=lhStanza.kvPairs_[rhKey] )
294 # Truncate
295 value = ( value[:maxLength] + "..." ) if len( value ) > maxLength else value
297 return diff, value
299 ########################################################################################################################
301 ## Option handling
303 ########################################################################################################################
304 def getOptionsParser() :
305 parser = argparse.ArgumentParser( )
307 # https://stackoverflow.com/a/24181138
308 requiredNamed = parser.add_argument_group( "required named arguments" )
310 requiredNamed.add_argument(
311 "-c", "--config",
312 dest="configFile",
313 help="configure.defaults file holding all stanza configurations",
314 type=str,
315 required=True
317 requiredNamed.add_argument(
318 "-t", "--template",
319 dest="cmakeTemplateFile",
320 help="cmake template file for configuring stanza into cmake syntax",
321 type=str,
322 required=True
324 requiredNamed.add_argument(
325 "-o", "--output",
326 dest="outputConfigFile",
327 help="cmake output toolchain config file for selected stanza",
328 type=str,
329 required=True
332 parser.add_argument(
333 "-p", "--preselect",
334 dest="preselect",
335 help="Use preselected stanza configuration, if multiple match grabs the first one",
336 type=str,
337 default=None
340 parser.add_argument(
341 "-x", "--skipCMakeOptions",
342 dest="skipCMakeOptions",
343 help="Skip query of available CMake options",
344 default=False,
345 const=True,
346 action='store_const'
348 parser.add_argument(
349 "-s", "--source",
350 dest="sourceCMakeFile",
351 help="Required unless -x/--skipCMakeOptions set, project cmake source file used to determine available options",
352 type=str,
353 default=None
356 return parser
359 class Options(object):
360 """Empty namespace"""
361 pass
363 ########################################################################################################################
365 ## Select stanza to operate on
367 ########################################################################################################################
368 def selectStanza( options ) :
370 fp = open( options.configFile, 'r' )
371 lines = fp.read()
372 fp.close()
374 # Now grab the blocks and parse
375 stanzas = []
376 # Gather all stanzas available
377 for stanzaBlock in archBlock.finditer( lines ) :
378 stanza = Stanza( stanzaBlock.group(1) )
379 stanza.parse()
381 if not stanza.crossPlatform_ and stanza.serialCompilersAvailable() and ( stanza.dmCompilersAvailable() or ( stanza.serialOpt_ or stanza.smparOpt_ ) ) :
382 if "DESCRIPTION" not in stanza.kvPairs_ :
383 # Of course WPS configure.defaults is different than WRF so descriptions are embedded in the comments
384 stanza.kvPairs_[ "DESCRIPTION" ] = stanza.osArchLine_.partition( "," )[ -1 ].partition( "#" )[0].strip()
385 stanzas.append( stanza )
387 idxSelection = 0
388 if options.preselect is None :
389 # Query for selected
390 stanzaIdx = 0
391 uniqueConfigs = {}
392 for stanza in stanzas :
393 stanzaConfig = str( stanza )
394 stanzaId = "{idx:<3} ".format( idx=stanzaIdx )
395 if stanzaConfig not in uniqueConfigs :
396 uniqueConfigs[ stanzaConfig ] = { "stanza" : stanza, "idx" : stanzaIdx }
398 print( stanzaId + stanzaConfig + stanza.kvPairs_[ "DESCRIPTION" ] )
399 # else :
400 # diff, value = Stanza.findFirstDifference( uniqueConfigs[ stanzaConfig ]["stanza"], stanza )
401 # if diff :
402 # print( stanzaId + stanzaConfig + "@{idx} diff => {value}".format( idx=uniqueConfigs[ stanzaConfig ][ "idx" ], value=value ) )
403 # else :
404 # print( stanzaId + stanzaConfig + "[no difference]" )
405 stanzaIdx += 1
406 print( "!! - Compiler not found, some configurations will not work and will be hidden" )
407 stringSelection = input( "Select configuration [0-{stop}] Default [0] (note !!) : ".format( stop=( stanzaIdx-1) ) )
408 idxSelection = int( stringSelection if stringSelection.isdigit() else 0 )
409 if idxSelection < 0 or idxSelection > stanzaIdx - 1 :
410 print( "Invalid configuration selection!" )
411 exit(1)
412 else :
413 for stanza in stanzas :
414 if options.preselect.lower() in stanza.kvPairs_["DESCRIPTION"].lower() :
415 print( str( stanza ) + stanza.kvPairs_[ "DESCRIPTION"] )
416 break
417 else :
418 idxSelection += 1
419 if idxSelection == len( stanzas ) :
420 print( "Error: Stanza configuration with description '{0}' does not exist. Preselect failed.".format( options.preselect ) )
421 exit(1)
423 stanzaCfg = stanzas[idxSelection]
425 return stanzaCfg
427 ########################################################################################################################
429 ## Select enum-like string for string-based cmake options
431 ########################################################################################################################
432 def getStringOptionSelection( topLevelCmake, searchString, destinationOption, defaultIndex=0 ) :
433 topLevelCmakeFP = open( topLevelCmake, "r" )
434 topLevelCmakeLines = topLevelCmakeFP.read()
435 topLevelCmakeFP.close()
437 stringOptionsMatch = re.search(
438 r"set\s*[(]\s*" + searchString + r"\s*(.*?)[)]",
439 topLevelCmakeLines,
440 re.I | re.S | re.M
442 if stringOptionsMatch is None :
443 print( "Syntax error in parsing " + searchString + " from " + topLevelCmake )
444 exit(1)
446 options = [ option.split( "#", 1 )[0].strip() for option in stringOptionsMatch.group(1).split( "\n" ) ]
447 # Weed out empties
448 options = [ option for option in options if option ]
450 optionsFmt = "\n\t" + "\n\t".join( [ "{idx} : {opt}".format( idx=options.index( opt ), opt=opt ) for opt in options ] )
451 stringSelection = input( "Select option for {option} from {optionsSource} [0-{max}] {opts} \nDefault [{defIdx}] : ".format(
452 option=destinationOption,
453 optionsSource=searchString,
454 max=len(options)-1,
455 opts=optionsFmt,
456 defIdx=defaultIndex
459 selection = int( stringSelection if stringSelection.isdigit() else defaultIndex )
461 if selection < 0 or selection > len(options) :
462 print( "Invalid option selection for " + searchString + "!" )
463 exit(1)
465 return options[selection]
467 ########################################################################################################################
469 ## Aggregate and allow toggle of various suboptions in alternate menu
471 ########################################################################################################################
472 def getSubOptions( topLevelCmake, ignoreOptions ) :
473 topLevelCmakeFP = open( topLevelCmake, "r" )
474 topLevelCmakeLines = topLevelCmakeFP.read()
475 topLevelCmakeFP.close()
477 stringOptionsMatch = re.finditer(
478 r"set\s*[(]\s*(\w+)\s*(ON|OFF)\s*CACHE\s*BOOL\s*\"(.*?)\"\s*[)]",
479 topLevelCmakeLines,
480 re.I | re.M
482 # Remove commented ones and ones that don't follow pattern set( <OPT> ON|OFF CACHE BOOL "<OPT>" )
483 options = [ [ option.group( 1 ), option.group( 2 ) ] for option in stringOptionsMatch if option.group( 1 ) == option.group( 3 ) and option.group(0).split( "#", 1 )[0].strip() ]
485 # Remove ignore options
486 options = [ option for option in options if option[0] not in ignoreOptions ]
487 subOptions = {}
489 if options :
490 subOptionQuit = False
491 optionToggleIdx = -1
493 # Print menu
494 optionStr = "{idx:<3} {option:<24} : {value:<5}"
495 print( optionStr.format( idx="ID", option="Option", value="Default" ) )
496 for opt in options :
497 print( optionStr.format( idx=options.index(opt), option=opt[0], value=opt[1] ) )
499 print( "Enter ID to toggle option on or off, q to quit : " )
500 # Loop until q, toggle from default not current value
501 while not subOptionQuit :
502 optionToggleIdx = input()
503 try:
504 optionToggleIdx = int( optionToggleIdx )
505 if optionToggleIdx < 0 or optionToggleIdx >= len( options ) :
506 print( "Not a valid index" )
507 else:
508 subOptions[ options[optionToggleIdx][0] ] = "ON" if not ( options[optionToggleIdx][1] == "ON" ) else "OFF"
509 print( "Set {option} to {value}".format( option=options[optionToggleIdx][0], value=subOptions[ options[optionToggleIdx][0] ] ) )
510 except ValueError as err :
511 subOptionQuit = optionToggleIdx.lower() == "q"
513 return subOptions
515 def main() :
517 parser = getOptionsParser()
518 options = Options()
519 parser.parse_args( namespace=options )
521 stanzaCfg = selectStanza( options )
523 additionalOptions = {}
524 if not options.skipCMakeOptions :
525 if options.sourceCMakeFile is None :
526 print( "Error: Project source cmake file required for project specific options." )
527 exit(1)
528 else:
529 additionalOptions = projectSpecificOptions( options, stanzaCfg )
531 generateCMakeToolChainFile( options.cmakeTemplateFile, options.outputConfigFile, stanzaCfg, additionalOptions )
533 ########################################################################################################################
534 ########################################################################################################################
536 ## ABOVE THIS BREAK THINGS ARE EXACTLY THE SAME AS WRF/WPS
537 ## BELOW THIS BREAK THINGS DIFFER
539 ########################################################################################################################
540 ########################################################################################################################
542 def generateCMakeToolChainFile( cmakeToolChainTemplate, output, stanza, optionsDict={} ) :
543 cmakeToolChainTemplateFP = open( cmakeToolChainTemplate, "r" )
544 cmakeToolChainTemplateLines = cmakeToolChainTemplateFP.read()
545 cmakeToolChainTemplateFP.close()
547 configStanza = cmakeToolChainTemplateLines.format(
548 CPP=stanza.kvPairs_["CPP"],
549 CPPFLAGS=stanza.kvPairs_["CPPFLAGS"],
550 CPP_FLAGS=stanza.kvPairs_["CPP_FLAGS"],
551 # BYTESWAPIO=stanza.kvPairs_["BYTESWAPIO"],
552 CFLAGS=stanza.kvPairs_["CFLAGS"],
553 FFLAGS=stanza.kvPairs_["FFLAGS"],
554 DM_CC=stanza.kvPairs_["DM_CC"],
555 DM_FC=stanza.kvPairs_["DM_FC"],
556 DM_FC_FLAGS=stanza.kvPairs_["DM_FC_FLAGS"],
557 DM_CC_FLAGS=stanza.kvPairs_["DM_CC_FLAGS"],
558 # FCBASEOPTS=stanza.kvPairs_["FCBASEOPTS"],
559 # FCDEBUG=stanza.kvPairs_["FCDEBUG"],
560 # FCNOOPT=stanza.kvPairs_["FCNOOPT"],
561 # FCOPTIM=stanza.kvPairs_["FCOPTIM"],
562 # M4_FLAGS=stanza.kvPairs_["M4_FLAGS"],
563 SCC=stanza.kvPairs_["SCC"],
564 SFC=stanza.kvPairs_["SFC"],
565 SCC_FLAGS=stanza.kvPairs_["SCC_FLAGS"],
566 SFC_FLAGS=stanza.kvPairs_["SFC_FLAGS"]
569 # Extra stufff not from stanza but options
570 fmtOption = "set( {opt:<32} {value:<12} CACHE STRING \"Set by configuration\" FORCE )"
571 configStanza += "\n" + "\n".join( [ fmtOption.format( opt=key, value=value ) for key, value in optionsDict.items() ] )
573 outputFP = open( output, "w" )
574 outputFP.write( configStanza )
575 outputFP.close()
577 def projectSpecificOptions( options, stanzaCfg ) :
579 # These are yes
580 yesValues = [ "yes", "y", "true", "1" ]
581 # Acceptable no values
582 noValues = [ "no", "n", "false", "0" ]
584 ##############################################################################
585 # Decompose the weird way to write the logic for DM/SM
586 USE_MPI = False
587 if ( stanzaCfg.serialOpt_ or stanzaCfg.smparOpt_ ) and ( stanzaCfg.dmparOpt_ or stanzaCfg.dmsmOpt_ ) :
588 # togglable
589 # we can safely check this since the user would not have been able to select this stanza if it couldn't be disabled
590 if stanzaCfg.dmCompilersAvailable() :
591 useMPI = not( input( "[DM] Use MPI? Default [Y] [Y/n] : " ).lower() in noValues )
592 else :
593 useMPI = False
594 else:
595 # User has no choice in the matter
596 useMPI = ( stanzaCfg.dmparOpt_ or stanzaCfg.dmsmOpt_ )
598 useOpenMP = False
599 if ( stanzaCfg.serialOpt_ or stanzaCfg.dmparOpt_ ) and ( stanzaCfg.smparOpt_ or stanzaCfg.dmsmOpt_ ):
600 # togglable
601 useOpenMP = input( "[SM] Use OpenMP? Default [N] [y/N] : " ).lower() in yesValues
602 else:
603 # User has no choice in the matter
604 useOpenMP = ( stanzaCfg.smparOpt_ or stanzaCfg.dmsmOpt_ )
606 ##############################################################################
608 buildExt = input( "[EXT] Build external? Default [N] [y/N] : " ).lower() in yesValues
610 additionalOptions = {
611 # "WRF_CORE" : coreOption,
612 # "WRF_NESTING" : nestingOption,
613 # "WRF_CASE" : caseOption,
614 "USE_OPENMP" : "ON" if useOpenMP else "OFF",
615 "USE_MPI" : "ON" if useMPI else "OFF",
616 "BUILD_EXTERNALS" : "ON" if buildExt else "OFF"
619 return additionalOptions
623 if __name__ == '__main__' :
624 main()