8 archBlock
= re
.compile( r
"(?:#[ ]*)(ARCH(?:.*\n)*?)(?:#{5,})", re
.I
)
9 kvPair
= re
.compile( r
"^(\w+)(?:[ \t]*=[ \t]*)(.*?)$", re
.I | re
.M
)
10 # Make this gnarly and complicated since configure.defaults has no standard formatting
11 # v start v OS V typical v MACOS
12 osAndArch
= re
.compile( r
"^ARCH[ ]+(\w+)[ ]+((?:\w+.*?),|(?:[(].*?[)]))", re
.I
)
13 # Just grab the first two words, thats what you get
14 osAndArchAlt
= re
.compile( r
"^ARCH[ ]+(\w+)[ ]+(\w+)", re
.I
)
16 referenceVar
= re
.compile( r
"[$][(](\w+)[)]", re
.I
)
20 def __init__( self
, lines
) :
27 # First get os & archs
28 osarchMatch
= osAndArch
.match( self
.lines_
)
30 if osarchMatch
is None :
31 osarchMatch
= osAndArchAlt
.match( self
.lines_
)
32 if osarchMatch
is None :
33 print( "Could not find OS and architecture info in " + self
.lines_
.partition("\n")[0] )
35 self
.os_
= osarchMatch
.group(1)
36 self
.archs_
= osarchMatch
.group(2).strip(",").split( " " )
38 for kvPairMatch
in kvPair
.finditer( self
.lines_
) :
39 self
.kvPairs_
[ kvPairMatch
.group(1) ] = kvPairMatch
.group(2)
40 self
.removeComments( kvPairMatch
.group(1) )
45 def dereference( self
, field
, fatal
=False ) :
46 if field
in self
.kvPairs_
:
47 prevField
= self
.kvPairs_
[field
]
49 for refVarIter
in referenceVar
.finditer( prevField
) :
50 if refVarIter
is not None :
51 # Grab group 1 and check that it is in our kv pairs
52 refVar
= refVarIter
.group(1)
53 if refVar
not in self
.kvPairs_
:
55 print( "Could not rereference : " + refVar
)
61 self
.dereference( refVar
, fatal
)
64 self
.kvPairs_
[field
] = self
.kvPairs_
[field
].replace(
65 "$({var})".format( var
=refVar
),
69 def removeReferences( self
, field
, specifics
=[] ) :
70 if field
in self
.kvPairs_
:
72 for specific
in specifics
:
73 self
.kvPairs_
[ field
] = self
.kvPairs_
[ field
].replace(
74 "$({var})".format( var
=specific
),
78 self
.kvPairs_
[ field
] = referenceVar
.sub( "", self
.kvPairs_
[ field
] )
81 def removeComments( self
, field
) :
82 if field
in self
.kvPairs_
:
83 self
.kvPairs_
[ field
] = self
.kvPairs_
[ field
].split( "#", 1 )[0]
85 def splitIntoFieldAndFlags( self
, field
) :
86 # Fix flags being mixed with programs
87 if field
in self
.kvPairs_
:
88 fieldValue
= self
.kvPairs_
[ field
]
90 self
.kvPairs_
[field
] = fieldValue
.partition(" ")[0]
91 self
.kvPairs_
[field
+ "_FLAGS"] = fieldValue
.partition(" ")[1]
93 def sanitize( self
) :
94 # Fix problematic variables
95 self
.dereference( "DM_FC" )
96 self
.dereference( "DM_CC" )
97 # self.removeReferences( "FCBASEOPTS_NO_G" )
98 # Get rid of all these mixed up flags, these are handled by cmake natively or
99 # just in the wrong place
100 self
.removeReferences( "FFLAGS", [ "FORMAT_FREE", "FORMAT_FIXED" ] )
101 self
.removeReferences( "F77FLAGS", [ "FORMAT_FREE", "FORMAT_FIXED" ] )
103 # self.dereference( "FCBASEOPTS" )
105 # Now fix certain ones that are mixing programs with flags all mashed into one option
106 self
.splitIntoFieldAndFlags( "DM_FC" )
107 self
.splitIntoFieldAndFlags( "DM_CC" )
108 self
.splitIntoFieldAndFlags( "M4" )
110 # Remove rogue compile commands that should *NOT* even be here
135 for keyToSan
in keysToSanitize
:
136 if keyToSan
in self
.kvPairs_
:
137 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_COMP_L", "" )
138 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_COMP_I", "" )
139 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_FC", "" )
140 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_CC", "" )
141 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_FDEFS", "" )
142 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_MPI", "" )
143 self
.kvPairs_
[ keyToSan
] = self
.kvPairs_
[ keyToSan
].replace( "CONFIGURE_COMPAT_FLAGS", "" )
145 # Now deref all the rest
146 for key
in self
.kvPairs_
:
147 self
.dereference( key
)
148 # And for final measure strip
149 self
.kvPairs_
[ key
] = self
.kvPairs_
[ key
].strip()
152 # base = """OS {os:<8} ARCHITECTURES {archs:<20}
155 # >> CCOMP = {CCOMP:<12}
156 # >> DM_FC = {DM_FC:<12}
157 # >> DM_CC = {DM_CC:<12}
159 # print( self.kvPairs_ )
160 base
= """{rec} {os:<10} {SFC:<11} / {SCC:<11} / {DM_FC:<11} / {DM_CC:<11}"""
161 text
= inspect
.cleandoc( base
).format(
163 rec
=( "!!" if platform
.system().lower() != self
.os_
.lower() else "Ok" ),
164 # archs=str(self.archs_),
165 SFC
=str( self
.kvPairs_
["SFC"].partition(" ")[0] ),
166 SCC
=str( self
.kvPairs_
["SCC"].partition(" ")[0] ),
167 # CCOMP=str( self.kvPairs_["CCOMP"].partition(" ")[0] ),
168 DM_FC
=str( self
.kvPairs_
["DM_FC"].partition(" ")[0] ),
169 DM_CC
=str( self
.kvPairs_
["DM_CC"].partition(" ")[0] )
171 # text += "\n" + "\n".join( [ "{key:<18} = {value}".format( key=key, value=value) for key, value in self.kvPairs_.items() ] )
175 def findFirstDifference( rhStanza
, lhStanza
, maxLength
=32 ) :
196 for rhKey
, rhValue
in rhStanza
.kvPairs_
.items() :
197 if rhKey
in valuesToCheck
and rhKey
in lhStanza
.kvPairs_
:
198 # Qualifies for difference
199 if rhValue
!= lhStanza
.kvPairs_
[rhKey
] :
201 value
= "{key:<12} = {value}".format( key
=rhKey
, value
=lhStanza
.kvPairs_
[rhKey
] )
204 value
= ( value
[:maxLength
] + "..." ) if len( value
) > maxLength
else value
209 def getStringOptionSelection( topLevelCmake
, searchString
) :
210 topLevelCmakeFP
= open( topLevelCmake
, "r" )
211 topLevelCmakeLines
= topLevelCmakeFP
.read()
212 topLevelCmakeFP
.close()
214 stringOptionsMatch
= re
.search(
215 r
"set\s*[(]\s*" + searchString
+ r
"\s*(.*?)[)]",
219 if stringOptionsMatch
is None :
220 print( "Syntax error in parsing " + searchString
+ " from " + topLevelCmake
)
223 options
= [ option
.split( "#", 1 )[0].strip() for option
in stringOptionsMatch
.group(1).split( "\n" ) ]
225 options
= [ option
for option
in options
if option
]
227 optionsFmt
= ", ".join( [ "{idx} : {opt}".format( idx
=options
.index( opt
), opt
=opt
) for opt
in options
] )
228 selection
= int( input( "Select string options [0-{max}] ({opts}) : ".format( max=len(options
)-1, opts
=optionsFmt
) ) )
230 if selection
< 0 or selection
> len(options
) :
231 print( "Invalid option selection for " + searchString
+ "!" )
234 return options
[selection
]
236 def generateCMakeToolChainFile( cmakeToolChainTemplate
, output
, stanza
, optionsDict
={} ) :
237 cmakeToolChainTemplateFP
= open( cmakeToolChainTemplate
, "r" )
238 cmakeToolChainTemplateLines
= cmakeToolChainTemplateFP
.read()
239 cmakeToolChainTemplateFP
.close()
241 configStanza
= cmakeToolChainTemplateLines
.format(
242 CPPFLAGS
=stanza
.kvPairs_
["CPPFLAGS"],
243 # BYTESWAPIO=stanza.kvPairs_["BYTESWAPIO"],
244 CFLAGS
=stanza
.kvPairs_
["CFLAGS"],
245 FFLAGS
=stanza
.kvPairs_
["FFLAGS"],
246 DM_CC
=stanza
.kvPairs_
["DM_CC"],
247 DM_FC
=stanza
.kvPairs_
["DM_FC"],
248 DM_FC_FLAGS
=stanza
.kvPairs_
["DM_FC_FLAGS"],
249 DM_CC_FLAGS
=stanza
.kvPairs_
["DM_CC_FLAGS"],
250 # FCBASEOPTS=stanza.kvPairs_["FCBASEOPTS"],
251 # FCDEBUG=stanza.kvPairs_["FCDEBUG"],
252 # FCNOOPT=stanza.kvPairs_["FCNOOPT"],
253 # FCOPTIM=stanza.kvPairs_["FCOPTIM"],
254 # M4_FLAGS=stanza.kvPairs_["M4_FLAGS"],
255 SCC
=stanza
.kvPairs_
["SCC"],
256 SFC
=stanza
.kvPairs_
["SFC"]
259 # Extra stufff not from stanza but options
260 fmtOption
= "set( {opt:<32} {value:<12} CACHE STRING \"Set by configuration\" FORCE )"
261 configStanza
+= "\n" + "\n".join( [ fmtOption
.format( opt
=key
, value
=value
) for key
, value
in optionsDict
.items() ] )
263 outputFP
= open( output
, "w" )
264 outputFP
.write( configStanza
)
268 configFile
= sys
.argv
[1]
269 cmakeTemplateFile
= sys
.argv
[2]
270 cmakeConfigFile
= sys
.argv
[3]
271 cmakeFile
= sys
.argv
[4]
273 # coreOption = getStringOptionSelection( cmakeFile, "WRF_CORE_OPTIONS" )
274 # nestingOption = getStringOptionSelection( cmakeFile, "WRF_NESTING_OPTIONS" )
275 # caseOption = getStringOptionSelection( cmakeFile, "WRF_CASE_OPTIONS" )
278 yesValues
= [ "yes", "y", "true", "1" ]
280 #!TODO Expand this for all wrf options
281 useMPI
= input( "[DM] Use MPI? [Y/n] : " ).lower() in yesValues
282 useOpenMP
= input( "[SM] Use OpenMP? [Y/n] : " ).lower() in yesValues
283 buildExt
= input( "[EXT] Build external? [Y/n] : " ).lower() in yesValues
286 fp
= open( configFile
, 'r' )
290 # Now grab the blocks and parse
294 for stanzaBlock
in archBlock
.finditer( lines
) :
295 stanza
= Stanza( stanzaBlock
.group(1) )
298 stanzas
.append( stanza
)
299 stanzaConfig
= str( stanza
)
300 stanzaId
= "{idx:<3} ".format( idx
=stanzaIdx
)
301 if stanzaConfig
not in uniqueConfigs
:
302 uniqueConfigs
[ stanzaConfig
] = { "stanza" : stanza
, "idx" : stanzaIdx
}
303 print( stanzaId
+ stanzaConfig
+ "[first entry]" )
305 diff
, value
= Stanza
.findFirstDifference( uniqueConfigs
[ stanzaConfig
]["stanza"], stanza
)
307 print( stanzaId
+ stanzaConfig
+ "@{idx} diff => {value}".format( idx
=uniqueConfigs
[ stanzaConfig
][ "idx" ], value
=value
) )
309 print( stanzaId
+ stanzaConfig
+ "[no difference]" )
312 print( "!! - Not recommended for your system" )
314 idxSelection
= int( input( "Select configuration [0-{stop}] (note !!) : ".format( stop
=( stanzaIdx
-1) ) ) )
315 if idxSelection
< 0 or idxSelection
> stanzaIdx
- 1 :
316 print( "Invalid configuration selection!" )
319 additionalOptions
= {
320 # "WRF_CORE" : coreOption,
321 # "WRF_NESTING" : nestingOption,
322 # "WRF_CASE" : caseOption,
323 "USE_OPENMP" : "ON" if useOpenMP
else "OFF",
324 "USE_MPI" : "ON" if useMPI
else "OFF",
325 "BUILD_EXTERNALS" : "ON" if buildExt
else "OFF"
327 generateCMakeToolChainFile( cmakeTemplateFile
, cmakeConfigFile
, stanzas
[idxSelection
], additionalOptions
)
332 if __name__
== '__main__' :