1#!/usr/bin/env python 2 3import os,shutil, string, re 4from distutils.sysconfig import parse_makefile 5import sys 6import logging, time 7import types 8sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 9from cmakegen import Mistakes, stripsplit, AUTODIRS, SKIPDIRS 10from cmakegen import defaultdict # collections.defaultdict, with fallback for python-2.4 11from gmakegen import * 12 13import inspect 14thisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 15sys.path.insert(0,thisscriptdir) 16import testparse 17import example_template 18 19class generateExamples(Petsc): 20 """ 21 gmakegen.py has basic structure for finding the files, writing out 22 the dependencies, etc. 23 """ 24 def __init__(self,petsc_dir=None, petsc_arch=None, verbose=False, single_ex=False): 25 super(generateExamples, self).__init__(petsc_dir=None, petsc_arch=None, verbose=False) 26 27 self.single_ex=single_ex 28 self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch) 29 self.ptNaming=True 30 # Whether to write out a useful debugging 31 #if verbose: self.summarize=True 32 self.summarize=True 33 34 # For help in setting the requirements 35 self.precision_types="single double quad int32".split() 36 self.integer_types="int32 int64".split() 37 self.languages="fortran cuda cxx".split() # Always requires C so do not list 38 39 # Things that are not test 40 self.buildkeys=testparse.buildkeys 41 42 # Adding a dictionary for storing sources, objects, and tests 43 # to make building the dependency tree easier 44 self.sources={} 45 self.objects={} 46 self.tests={} 47 for pkg in PKGS: 48 self.sources[pkg]={} 49 self.objects[pkg]=[] 50 self.tests[pkg]={} 51 for lang in LANGS: 52 self.sources[pkg][lang]={} 53 self.sources[pkg][lang]['srcs']=[] 54 self.tests[pkg][lang]={} 55 56 # Do some initialization 57 self.testroot_dir=os.path.join(self.arch_dir,"tests") 58 if not os.path.isdir(self.testroot_dir): os.makedirs(self.testroot_dir) 59 return 60 61 def nameSpace(self,srcfile,srcdir): 62 """ 63 Because the scripts have a non-unique naming, the pretty-printing 64 needs to convey the srcdir and srcfile. There are two ways of doing this. 65 """ 66 if self.ptNaming: 67 cdir=srcdir.split('src')[1].lstrip("/").rstrip("/") 68 prefix=cdir.replace('/examples/','_').replace("/","_")+"-" 69 nameString=prefix+srcfile 70 else: 71 #nameString=srcdir+": "+srcfile 72 nameString=srcfile 73 return nameString 74 75 def getLanguage(self,srcfile): 76 """ 77 Based on the source, determine associated language as found in gmakegen.LANGS 78 Can we just return srcext[1:\] now? 79 """ 80 langReq=None 81 srcext=os.path.splitext(srcfile)[-1] 82 if srcext in ".F90".split(): langReq="F90" 83 if srcext in ".F".split(): langReq="F" 84 if srcext in ".cxx".split(): langReq="cxx" 85 if srcext == ".cu": langReq="cu" 86 if srcext == ".c": langReq="c" 87 #if not langReq: print "ERROR: ", srcext, srcfile 88 return langReq 89 90 def getArgLabel(self,testDict): 91 """ 92 In all of the arguments in the test dictionary, create a simple 93 string for searching within the makefile system. For simplicity in 94 search, remove "-", for strings, etc. 95 Also, concatenate the arg commands 96 For now, ignore nsize -- seems hard to search for anyway 97 """ 98 # Collect all of the args associated with a test 99 argStr=("" if not testDict.has_key('args') else testDict['args']) 100 if testDict.has_key('subtests'): 101 for stest in testDict["subtests"]: 102 sd=testDict[stest] 103 argStr=argStr+("" if not sd.has_key('args') else sd['args']) 104 105 # Now go through and cleanup 106 argStr=re.sub('{{(.*?)}}',"",argStr) 107 argStr=re.sub('-'," ",argStr) 108 for digit in string.digits: argStr=re.sub(digit," ",argStr) 109 argStr=re.sub("\.","",argStr) 110 argStr=re.sub(",","",argStr) 111 argStr=re.sub('\+',' ',argStr) 112 argStr=re.sub(' +',' ',argStr) # Remove repeated white space 113 return argStr.strip() 114 115 def addToSources(self,exfile,root,srcDict): 116 """ 117 Put into data structure that allows easy generation of makefile 118 """ 119 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 120 fullfile=os.path.join(root,exfile) 121 relpfile=self.relpath(self.petsc_dir,fullfile) 122 lang=self.getLanguage(exfile) 123 if not lang: return 124 self.sources[pkg][lang]['srcs'].append(relpfile) 125 if srcDict.has_key('depends'): 126 depSrc=srcDict['depends'] 127 depObj=os.path.splitext(depSrc)[0]+".o" 128 self.sources[pkg][lang][exfile]=depObj 129 130 # In gmakefile, ${TESTDIR} var specifies the object compilation 131 testsdir=self.relpath(self.petsc_dir,root)+"/" 132 objfile="${TESTDIR}/"+testsdir+os.path.splitext(exfile)[0]+".o" 133 self.objects[pkg].append(objfile) 134 return 135 136 def addToTests(self,test,root,exfile,execname,testDict): 137 """ 138 Put into data structure that allows easy generation of makefile 139 Organized by languages to allow testing of languages 140 """ 141 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 142 #nmtest=self.nameSpace(test,root) 143 rpath=self.relpath(self.petsc_dir,root) 144 nmtest=os.path.join(rpath,test) 145 lang=self.getLanguage(exfile) 146 if not lang: return 147 self.tests[pkg][lang][nmtest]={} 148 self.tests[pkg][lang][nmtest]['exfile']=os.path.join(rpath,exfile) 149 self.tests[pkg][lang][nmtest]['exec']=execname 150 self.tests[pkg][lang][nmtest]['argLabel']=self.getArgLabel(testDict) 151 return 152 153 def getFor(self,subst,i,j): 154 """ 155 Get the for and done lines 156 """ 157 forlines="" 158 donlines="" 159 indent=" " 160 nsizeStr=subst['nsize'] 161 for loop in re.findall('{{(.*?)}}',subst['nsize']): 162 lindex=string.ascii_lowercase[i] 163 forline=indent*j+"for "+lindex+" in '"+loop+"'; do" 164 nsizeStr=re.sub("{{"+loop+"}}","${"+lindex+"}",nsizeStr) 165 donline=indent*j+"done" 166 forlines=forlines+forline+"\n" 167 donlines=donlines+donline+"\n" 168 i=i+1 169 j=j+1 170 subst['nsize']=nsizeStr 171 argStr=subst['args'] 172 for loop in re.findall('{{(.*?)}}',subst['args']): 173 lindex=string.ascii_lowercase[i] 174 forline=indent*j+"for "+lindex+" in '"+loop+"'; do" 175 argStr=re.sub("{{"+loop+"}}","${"+lindex+"}",argStr) 176 donline=indent*j+"done" 177 forlines=forlines+forline+"\n" 178 donlines=donlines+donline+"\n" 179 i=i+1 180 j=j+1 181 subst['args']=argStr 182 183 # The do lines have reverse order with respect to indentation 184 dl=donlines.rstrip("\n").split("\n") 185 dl.reverse() 186 donlines="\n".join(dl)+"\n" 187 188 return forlines,donlines,i,j 189 190 191 def getExecname(self,exfile,root): 192 """ 193 Generate bash script using template found next to this file. 194 This file is read in at constructor time to avoid file I/O 195 """ 196 rpath=self.relpath(self.petsc_dir,root) 197 if self.single_ex: 198 execname=rpath.split("/")[1]+"-ex" 199 else: 200 execname=os.path.splitext(exfile)[0] 201 return execname 202 203 def getSubstVars(self,testDict,rpath,testname): 204 """ 205 Create a dictionary with all of the variables that get substituted 206 into the template commands found in example_template.py 207 TODO: Cleanup 208 """ 209 subst={} 210 # Handle defaults 211 if not testDict.has_key('nsize'): testDict['nsize']=1 212 if not testDict.has_key('filter'): testDict['filter']="" 213 if not testDict.has_key('filter_output'): testDict['filter_output']="" 214 if not testDict.has_key('localrunfiles'): testDict['localrunfiles']="" 215 if not testDict.has_key('args'): testDict['args']="" 216 defroot=(re.sub("run","",testname) if testname.startswith("run") else testname) 217 if not "_" in defroot: defroot=defroot+"_1" 218 if not testDict.has_key('redirect_file'): testDict['redirect_file']=defroot+".tmp" 219 if not testDict.has_key('output_file'): testDict['output_file']="output/"+defroot+".out" 220 221 # Setup the variables in template_string that need to be substituted 222 subst['srcdir']=os.path.join(self.petsc_dir,rpath) 223 subst['label']=self.nameSpace(defroot,subst['srcdir']) 224 subst['redirect_file']=testDict['redirect_file'] 225 subst['output_file']=os.path.join(subst['srcdir'],testDict['output_file']) 226 subst['exec']="../"+testDict['execname'] 227 subst['filter']="'"+testDict['filter']+"'" # Quotes are tricky 228 subst['filter_output']=testDict['filter_output'] 229 subst['localrunfiles']=testDict['localrunfiles'] 230 subst['testroot']=self.testroot_dir 231 subst['testname']=testname 232 233 # Be careful with this 234 if testDict.has_key('command'): subst['command']=testDict['command'] 235 236 # These can have for loops and are treated separately later 237 if testDict.has_key('nsize'): subst['nsize']=str(testDict['nsize']) 238 if testDict.has_key('args'): subst['args']=testDict['args'] 239 240 #Conf vars 241 subst['mpiexec']=self.conf['MPIEXEC'] # make sure PETSC_DIR is defined! 242 subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path 243 subst['diff']=self.conf['DIFF'] 244 subst['rm']=self.conf['RM'] 245 subst['grep']=self.conf['GREP'] 246 subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR'] 247 subst['wpetsc_dir']=self.conf['wPETSC_DIR'] 248 249 return subst 250 251 def getCmds(self,subst,i): 252 """ 253 Generate bash script using template found next to this file. 254 This file is read in at constructor time to avoid file I/O 255 """ 256 indent=" " 257 nindent=i # the start and has to be consistent with below 258 cmdLines="" 259 # MPI is the default -- but we have a few odd commands 260 if not subst.has_key('command'): 261 cmd=indent*nindent+self._substVars(subst,example_template.mpitest) 262 else: 263 cmd=indent*nindent+self._substVars(subst,example_template.commandtest) 264 cmdLines=cmdLines+cmd+"\n\n" 265 266 if not subst['filter_output']: 267 cmd=indent*nindent+self._substVars(subst,example_template.difftest) 268 else: 269 cmd=indent*nindent+self._substVars(subst,example_template.filterdifftest) 270 cmdLines=cmdLines+cmd+"\n" 271 return cmdLines 272 273 def _substVars(self,subst,origStr): 274 """ 275 Substitute varial 276 """ 277 Str=origStr 278 for subkey in subst: 279 if type(subst[subkey])!=types.StringType: continue 280 patt="@"+subkey.upper()+"@" 281 Str=re.sub(patt,subst[subkey],Str) 282 return Str 283 284 def genRunScript(self,testname,root,isRun,srcDict): 285 """ 286 Generate bash script using template found next to this file. 287 This file is read in at constructor time to avoid file I/O 288 """ 289 # runscript_dir directory has to be consistent with gmakefile 290 testDict=srcDict[testname] 291 rpath=self.relpath(self.petsc_dir,root) 292 runscript_dir=os.path.join(self.testroot_dir,rpath) 293 if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir) 294 fh=open(os.path.join(runscript_dir,testname+".sh"),"w") 295 petscvarfile=os.path.join(self.arch_dir,'lib','petsc','conf','petscvariables') 296 297 subst=self.getSubstVars(testDict,rpath,testname) 298 299 #Handle runfiles 300 if subst['localrunfiles']: 301 for lfile in subst['localrunfiles'].split(): 302 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 303 shutil.copy(fullfile,runscript_dir) 304 # Check subtests for local runfiles 305 if testDict.has_key("subtests"): 306 for stest in testDict["subtests"]: 307 if testDict[stest].has_key('localrunfiles'): 308 for lfile in testDict[stest]['localrunfiles'].split(): 309 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 310 shutil.copy(fullfile,self.runscript_dir) 311 312 # Now substitute the key variables into the header and footer 313 header=self._substVars(subst,example_template.header) 314 footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer) 315 316 # Start writing the file 317 fh.write(header+"\n") 318 319 # If there is a TODO or a SKIP then we do it before writing out the 320 # rest of the command (which is useful for working on the test) 321 # SKIP and TODO can be for the source file or for the runs 322 if srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 323 if srcDict.has_key("TODO"): 324 todo=re.sub("@TODOCOMMENT@",srcDict['TODO'],example_template.todoline) 325 fh.write(todo+"\ntotal=1; todo=1\n") 326 fh.write(footer+"\n") 327 fh.write("exit\n\n\n") 328 elif srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 329 skip=re.sub("@SKIPCOMMENT@",srcDict['SKIP'],example_template.skipline) 330 fh.write(skip+"\ntotal=1; skip=1\n") 331 fh.write(footer+"\n") 332 fh.write("exit\n\n\n") 333 elif not isRun: 334 skip=re.sub("@SKIPCOMMENT@",testDict['SKIP'],example_template.skipline) 335 fh.write(skip+"\ntotal=1; skip=1\n") 336 fh.write(footer+"\n") 337 fh.write("exit\n\n\n") 338 elif testDict.has_key('TODO'): 339 todo=re.sub("@TODOCOMMENT@",testDict['TODO'],example_template.todoline) 340 fh.write(todo+"\ntotal=1; todo=1\n") 341 fh.write(footer+"\n") 342 fh.write("exit\n\n\n") 343 344 # Need to handle loops 345 i=8 # for loop counters 346 j=0 # for indentation 347 348 doForP=False 349 if "{{" in subst['args']+subst['nsize']: 350 doForP=True 351 flinesP,dlinesP,i,j=self.getFor(subst,i,j) 352 fh.write(flinesP+"\n") 353 354 # Subtests are special 355 if testDict.has_key("subtests"): 356 substP=subst # Subtests can inherit args but be careful 357 if not substP.has_key("arg"): substP["arg"]="" 358 jorig=j 359 for stest in testDict["subtests"]: 360 j=jorig 361 subst=substP 362 subst.update(testDict[stest]) 363 subst['nsize']=str(subst['nsize']) 364 if not testDict[stest].has_key('args'): testDict[stest]['args']="" 365 subst['args']=substP['args']+testDict[stest]['args'] 366 doFor=False 367 if "{{" in subst['args']+subst['nsize']: 368 doFor=True 369 flines,dlines,i,j=self.getFor(subst,i,j) 370 fh.write(flines+"\n") 371 fh.write(self.getCmds(subst,j)+"\n") 372 if doFor: fh.write(dlines+"\n") 373 else: 374 fh.write(self.getCmds(subst,j)+"\n") 375 if doForP: fh.write(dlinesP+"\n") 376 377 fh.write(footer+"\n") 378 os.chmod(os.path.join(runscript_dir,testname+".sh"),0755) 379 return 380 381 def genScriptsAndInfo(self,exfile,root,srcDict): 382 """ 383 Generate scripts from the source file, determine if built, etc. 384 For every test in the exfile with info in the srcDict: 385 1. Determine if it needs to be run for this arch 386 2. Generate the script 387 3. Generate the data needed to write out the makefile in a 388 convenient way 389 All tests are *always* run, but some may be SKIP'd per the TAP standard 390 """ 391 debug=False 392 fileIsTested=False 393 execname=self.getExecname(exfile,root) 394 isBuilt=self._isBuilt(exfile,srcDict) 395 for test in srcDict: 396 if test in self.buildkeys: continue 397 if debug: print self.nameSpace(exfile,root), test 398 srcDict[test]['execname']=execname # Convenience in generating scripts 399 isRun=self._isRun(srcDict[test]) 400 self.genRunScript(test,root,isRun,srcDict) 401 srcDict[test]['isrun']=isRun 402 if isRun: fileIsTested=True 403 self.addToTests(test,root,exfile,execname,srcDict[test]) 404 405 # This adds to datastructure for building deps 406 if fileIsTested and isBuilt: self.addToSources(exfile,root,srcDict) 407 #print self.nameSpace(exfile,root), fileIsTested 408 return 409 410 def _isBuilt(self,exfile,srcDict): 411 """ 412 Determine if this file should be built. 413 """ 414 # Get the language based on file extension 415 lang=self.getLanguage(exfile) 416 if (lang=="F" or lang=="F90") and not self.have_fortran: 417 srcDict["SKIP"]="Fortran required for this test" 418 return False 419 if lang=="cu" and not self.conf.has_key('PETSC_HAVE_CUDA'): 420 srcDict["SKIP"]="CUDA required for this test" 421 return False 422 if lang=="cxx" and not self.conf.has_key('PETSC_HAVE_CXX'): 423 srcDict["SKIP"]="C++ required for this test" 424 return False 425 426 # Deprecated source files 427 if srcDict.has_key("TODO"): return False 428 429 # isRun can work with srcDict to handle the requires 430 if srcDict.has_key("requires"): 431 if len(srcDict["requires"])>0: 432 return self._isRun(srcDict) 433 434 return True 435 436 437 def _isRun(self,testDict): 438 """ 439 Based on the requirements listed in the src file and the petscconf.h 440 info, determine whether this test should be run or not. 441 """ 442 indent=" " 443 debug=False 444 445 # MPI requirements 446 if testDict.has_key('nsize'): 447 if testDict['nsize']>1 and self.conf.has_key('MPI_IS_MPIUNI'): 448 if debug: print indent+"Cannot run parallel tests" 449 testDict['SKIP']="Parallel test with serial build" 450 return False 451 452 # The requirements for the test are the sum of all the run subtests 453 if testDict.has_key('subtests'): 454 if not testDict.has_key('requires'): testDict['requires']="" 455 for stest in testDict['subtests']: 456 if testDict[stest].has_key('requires'): 457 testDict['requires']=testDict['requires']+" "+testDict[stest]['requires'] 458 459 460 # Now go through all requirements 461 if testDict.has_key('requires'): 462 for requirement in testDict['requires'].split(): 463 requirement=requirement.strip() 464 if not requirement: continue 465 if debug: print indent+"Requirement: ", requirement 466 isNull=False 467 if requirement.startswith("!"): 468 requirement=requirement[1:]; isNull=True 469 # Precision requirement for reals 470 if requirement in self.precision_types: 471 if self.conf['PETSC_PRECISION']==requirement: 472 testDict['SKIP']="not "+requirement+" required" 473 if isNull: return False 474 else: 475 testDict['SKIP']=requirement+" required" 476 return False 477 # Precision requirement for ints 478 if requirement in self.integer_types: 479 if requirement=="int32": 480 if self.conf['PETSC_SIZEOF_INT']==4: 481 testDict['SKIP']="not int32 required" 482 if isNull: return False 483 else: 484 testDict['SKIP']="int32 required" 485 return False 486 if requirement=="int64": 487 if self.conf['PETSC_SIZEOF_INT']==8: 488 testDict['SKIP']="NOT int64 required" 489 if isNull: return False 490 else: 491 testDict['SKIP']="int64 required" 492 return False 493 # Datafilespath 494 if requirement=="datafilespath": 495 testDict['SKIP']="Requires DATAFILESPATH" 496 return False 497 # Defines -- not sure I have comments matching 498 if "define(" in requirement.lower(): 499 reqdef=requirement.split("(")[1].split(")")[0] 500 val=(reqdef.split()[1] if " " in reqdef else "") 501 if self.conf.has_key(reqdef): 502 if val: 503 if self.conf[reqdef]==val: 504 if isNull: 505 testDict['SKIP']="Null requirement not met: "+requirement 506 return False 507 else: 508 testDict['SKIP']="Required: "+requirement 509 return False 510 else: 511 if isNull: 512 testDict['SKIP']="Null requirement not met: "+requirement 513 return False 514 else: 515 return True 516 else: 517 testDict['SKIP']="Requirement not met: "+requirement 518 return False 519 520 # Rest should be packages that we can just get from conf 521 if requirement == "complex": petscconfvar="PETSC_USE_COMPLEX" 522 else: petscconfvar="PETSC_HAVE_"+requirement.upper() 523 if self.conf.get(petscconfvar): 524 if isNull: 525 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 526 return False 527 elif not isNull: 528 if debug: print "requirement not found: ", requirement 529 testDict['SKIP']=petscconfvar+" requirement not met" 530 return False 531 532 return True 533 534 def genPetscTests_summarize(self,dataDict): 535 """ 536 Required method to state what happened 537 """ 538 if not self.summarize: return 539 indent=" " 540 fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt') 541 fh=open(fhname,"w") 542 #print "See ", fhname 543 for root in dataDict: 544 relroot=self.relpath(self.petsc_dir,root) 545 pkg=relroot.split("/")[1] 546 fh.write(relroot+"\n") 547 allSrcs=[] 548 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 549 for exfile in dataDict[root]: 550 # Basic information 551 fullfile=os.path.join(root,exfile) 552 rfile=self.relpath(self.petsc_dir,fullfile) 553 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 554 fh.write(indent+exfile+indent*4+builtStatus+"\n") 555 556 for test in dataDict[root][exfile]: 557 if test in self.buildkeys: continue 558 line=indent*2+test 559 fh.write(line+"\n") 560 # Looks nice to have the keys in order 561 #for key in dataDict[root][exfile][test]: 562 for key in "isrun abstracted nsize args requires script".split(): 563 if not dataDict[root][exfile][test].has_key(key): continue 564 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 565 fh.write(line+"\n") 566 fh.write("\n") 567 fh.write("\n") 568 fh.write("\n") 569 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 570 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 571 fh.close() 572 return 573 574 def genPetscTests(self,root,dirs,files,dataDict): 575 """ 576 Go through and parse the source files in the directory to generate 577 the examples based on the metadata contained in the source files 578 """ 579 debug=False 580 # Use examplesAnalyze to get what the makefles think are sources 581 #self.examplesAnalyze(root,dirs,files,anlzDict) 582 583 dataDict[root]={} 584 585 for exfile in files: 586 #TST: Until we replace files, still leaving the orginals as is 587 #if not exfile.startswith("new_"+"ex"): continue 588 if not exfile.startswith("ex"): continue 589 590 # Convenience 591 fullex=os.path.join(root,exfile) 592 relpfile=self.relpath(self.petsc_dir,fullex) 593 if debug: print relpfile 594 dataDict[root].update(testparse.parseTestFile(fullex)) 595 # Need to check and make sure tests are in the file 596 # if verbosity>=1: print relpfile 597 if dataDict[root].has_key(exfile): 598 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 599 600 return 601 602 def walktree(self,top,action="printFiles"): 603 """ 604 Walk a directory tree, starting from 'top' 605 """ 606 #print "action", action 607 # Goal of action is to fill this dictionary 608 dataDict={} 609 for root, dirs, files in os.walk(top, topdown=False): 610 if not "examples" in root: continue 611 if not os.path.isfile(os.path.join(root,"makefile")): continue 612 bname=os.path.basename(root.rstrip("/")) 613 if bname=="tests" or bname=="tutorials": 614 eval("self."+action+"(root,dirs,files,dataDict)") 615 if type(top) != types.StringType: 616 raise TypeError("top must be a string") 617 # Now summarize this dictionary 618 eval("self."+action+"_summarize(dataDict)") 619 return dataDict 620 621 def gen_gnumake(self, fd): 622 """ 623 Overwrite of the method in the base PETSc class 624 """ 625 def write(stem, srcs): 626 for lang in LANGS: 627 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 628 for pkg in PKGS: 629 srcs = self.gen_pkg(pkg) 630 write('testsrcs-' + pkg, srcs) 631 return self.gendeps 632 633 def gen_pkg(self, pkg): 634 """ 635 Overwrite of the method in the base PETSc class 636 """ 637 return self.sources[pkg] 638 639 def write_gnumake(self,dataDict): 640 """ 641 Write out something similar to files from gmakegen.py 642 643 There is not a lot of has_key type checking because 644 should just work and need to know if there are bugs 645 646 Test depends on script which also depends on source 647 file, but since I don't have a good way generating 648 acting on a single file (oops) just depend on 649 executable which in turn will depend on src file 650 """ 651 # Different options for how to set up the targets 652 compileExecsFirst=False 653 654 # Open file 655 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 656 fd = open(arch_files, 'w') 657 658 # Write out the sources 659 gendeps = self.gen_gnumake(fd) 660 661 # Write out the tests and execname targets 662 fd.write("\n#Tests and executables\n") # Delimiter 663 664 for pkg in PKGS: 665 # These grab the ones that are built 666 for lang in LANGS: 667 testdeps=[] 668 for ftest in self.tests[pkg][lang]: 669 test=os.path.basename(ftest) 670 basedir=os.path.dirname(ftest) 671 testdeps.append(self.nameSpace(test,basedir)) 672 fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n") 673 fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang)) 674 675 # test targets 676 for ftest in self.tests[pkg][lang]: 677 test=os.path.basename(ftest) 678 basedir=os.path.dirname(ftest) 679 testdir="${TESTDIR}/"+basedir+"/" 680 nmtest=self.nameSpace(test,basedir) 681 rundir=os.path.join(testdir,test) 682 #print test, nmtest 683 script=test+".sh" 684 685 # Deps 686 exfile=self.tests[pkg][lang][ftest]['exfile'] 687 fullex=os.path.join(self.petsc_dir,exfile) 688 localexec=self.tests[pkg][lang][ftest]['exec'] 689 execname=os.path.join(testdir,localexec) 690 fullscript=os.path.join(testdir,script) 691 tmpfile=os.path.join(testdir,test,test+".tmp") 692 693 # *.counts depends on the script and either executable (will 694 # be run) or the example source file (SKIP or TODO) 695 fd.write('%s.counts : %s %s\n' 696 % (os.path.join('$(TESTDIR)/counts', nmtest), 697 fullscript, 698 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)) 699 # Now write the args: 700 fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 701 702 fd.close() 703 return 704 705 def writeHarness(self,output,dataDict): 706 """ 707 This is set up to write out multiple harness even if only gnumake 708 is supported now 709 """ 710 eval("self.write_"+output+"(dataDict)") 711 return 712 713def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 714 if output is None: 715 output = 'gnumake' 716 717 718 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 719 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 720 pEx.writeHarness(output,dataDict) 721 722if __name__ == '__main__': 723 import optparse 724 parser = optparse.OptionParser() 725 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 726 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 727 parser.add_option('--output', help='Location to write output file', default=None) 728 parser.add_option('-s', '--single_executable', dest='single_executable', action="store_false", help='Whether there should be single executable per src subdir. Default is false') 729 opts, extra_args = parser.parse_args() 730 if extra_args: 731 import sys 732 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 733 exit(1) 734 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 735