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 if self.petsc_arch.find('valgrind')>=0: 242 subst['mpiexec']='petsc_mpiexec_valgrind ' + self.conf['MPIEXEC'] 243 else: 244 subst['mpiexec']=self.conf['MPIEXEC'] 245 subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path 246 subst['diff']=self.conf['DIFF'] 247 subst['rm']=self.conf['RM'] 248 subst['grep']=self.conf['GREP'] 249 subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR'] 250 subst['wpetsc_dir']=self.conf['wPETSC_DIR'] 251 252 return subst 253 254 def getCmds(self,subst,i): 255 """ 256 Generate bash script using template found next to this file. 257 This file is read in at constructor time to avoid file I/O 258 """ 259 indent=" " 260 nindent=i # the start and has to be consistent with below 261 cmdLines="" 262 # MPI is the default -- but we have a few odd commands 263 if not subst.has_key('command'): 264 cmd=indent*nindent+self._substVars(subst,example_template.mpitest) 265 else: 266 cmd=indent*nindent+self._substVars(subst,example_template.commandtest) 267 cmdLines=cmdLines+cmd+"\n\n" 268 269 if not subst['filter_output']: 270 cmd=indent*nindent+self._substVars(subst,example_template.difftest) 271 else: 272 cmd=indent*nindent+self._substVars(subst,example_template.filterdifftest) 273 cmdLines=cmdLines+cmd+"\n" 274 return cmdLines 275 276 def _substVars(self,subst,origStr): 277 """ 278 Substitute varial 279 """ 280 Str=origStr 281 for subkey in subst: 282 if type(subst[subkey])!=types.StringType: continue 283 patt="@"+subkey.upper()+"@" 284 Str=re.sub(patt,subst[subkey],Str) 285 return Str 286 287 def genRunScript(self,testname,root,isRun,srcDict): 288 """ 289 Generate bash script using template found next to this file. 290 This file is read in at constructor time to avoid file I/O 291 """ 292 # runscript_dir directory has to be consistent with gmakefile 293 testDict=srcDict[testname] 294 rpath=self.relpath(self.petsc_dir,root) 295 runscript_dir=os.path.join(self.testroot_dir,rpath) 296 if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir) 297 fh=open(os.path.join(runscript_dir,testname+".sh"),"w") 298 petscvarfile=os.path.join(self.arch_dir,'lib','petsc','conf','petscvariables') 299 300 subst=self.getSubstVars(testDict,rpath,testname) 301 302 #Handle runfiles 303 if subst['localrunfiles']: 304 for lfile in subst['localrunfiles'].split(): 305 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 306 shutil.copy(fullfile,runscript_dir) 307 # Check subtests for local runfiles 308 if testDict.has_key("subtests"): 309 for stest in testDict["subtests"]: 310 if testDict[stest].has_key('localrunfiles'): 311 for lfile in testDict[stest]['localrunfiles'].split(): 312 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 313 shutil.copy(fullfile,self.runscript_dir) 314 315 # Now substitute the key variables into the header and footer 316 header=self._substVars(subst,example_template.header) 317 footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer) 318 319 # Start writing the file 320 fh.write(header+"\n") 321 322 # If there is a TODO or a SKIP then we do it before writing out the 323 # rest of the command (which is useful for working on the test) 324 # SKIP and TODO can be for the source file or for the runs 325 if srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 326 if srcDict.has_key("TODO"): 327 todo=re.sub("@TODOCOMMENT@",srcDict['TODO'],example_template.todoline) 328 fh.write(todo+"\ntotal=1; todo=1\n") 329 fh.write(footer+"\n") 330 fh.write("exit\n\n\n") 331 elif srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 332 skip=re.sub("@SKIPCOMMENT@",srcDict['SKIP'],example_template.skipline) 333 fh.write(skip+"\ntotal=1; skip=1\n") 334 fh.write(footer+"\n") 335 fh.write("exit\n\n\n") 336 elif not isRun: 337 skip=re.sub("@SKIPCOMMENT@",testDict['SKIP'],example_template.skipline) 338 fh.write(skip+"\ntotal=1; skip=1\n") 339 fh.write(footer+"\n") 340 fh.write("exit\n\n\n") 341 elif testDict.has_key('TODO'): 342 todo=re.sub("@TODOCOMMENT@",testDict['TODO'],example_template.todoline) 343 fh.write(todo+"\ntotal=1; todo=1\n") 344 fh.write(footer+"\n") 345 fh.write("exit\n\n\n") 346 347 # Need to handle loops 348 i=8 # for loop counters 349 j=0 # for indentation 350 351 doForP=False 352 if "{{" in subst['args']+subst['nsize']: 353 doForP=True 354 flinesP,dlinesP,i,j=self.getFor(subst,i,j) 355 fh.write(flinesP+"\n") 356 357 # Subtests are special 358 if testDict.has_key("subtests"): 359 substP=subst # Subtests can inherit args but be careful 360 if not substP.has_key("arg"): substP["arg"]="" 361 jorig=j 362 for stest in testDict["subtests"]: 363 j=jorig 364 subst=substP 365 subst.update(testDict[stest]) 366 subst['nsize']=str(subst['nsize']) 367 if not testDict[stest].has_key('args'): testDict[stest]['args']="" 368 subst['args']=substP['args']+testDict[stest]['args'] 369 doFor=False 370 if "{{" in subst['args']+subst['nsize']: 371 doFor=True 372 flines,dlines,i,j=self.getFor(subst,i,j) 373 fh.write(flines+"\n") 374 fh.write(self.getCmds(subst,j)+"\n") 375 if doFor: fh.write(dlines+"\n") 376 else: 377 fh.write(self.getCmds(subst,j)+"\n") 378 if doForP: fh.write(dlinesP+"\n") 379 380 fh.write(footer+"\n") 381 os.chmod(os.path.join(runscript_dir,testname+".sh"),0755) 382 return 383 384 def genScriptsAndInfo(self,exfile,root,srcDict): 385 """ 386 Generate scripts from the source file, determine if built, etc. 387 For every test in the exfile with info in the srcDict: 388 1. Determine if it needs to be run for this arch 389 2. Generate the script 390 3. Generate the data needed to write out the makefile in a 391 convenient way 392 All tests are *always* run, but some may be SKIP'd per the TAP standard 393 """ 394 debug=False 395 fileIsTested=False 396 execname=self.getExecname(exfile,root) 397 isBuilt=self._isBuilt(exfile,srcDict) 398 for test in srcDict: 399 if test in self.buildkeys: continue 400 if debug: print self.nameSpace(exfile,root), test 401 srcDict[test]['execname']=execname # Convenience in generating scripts 402 isRun=self._isRun(srcDict[test]) 403 self.genRunScript(test,root,isRun,srcDict) 404 srcDict[test]['isrun']=isRun 405 if isRun: fileIsTested=True 406 self.addToTests(test,root,exfile,execname,srcDict[test]) 407 408 # This adds to datastructure for building deps 409 if fileIsTested and isBuilt: self.addToSources(exfile,root,srcDict) 410 #print self.nameSpace(exfile,root), fileIsTested 411 return 412 413 def _isBuilt(self,exfile,srcDict): 414 """ 415 Determine if this file should be built. 416 """ 417 # Get the language based on file extension 418 lang=self.getLanguage(exfile) 419 if (lang=="F" or lang=="F90") and not self.have_fortran: 420 srcDict["SKIP"]="Fortran required for this test" 421 return False 422 if lang=="cu" and not self.conf.has_key('PETSC_HAVE_CUDA'): 423 srcDict["SKIP"]="CUDA required for this test" 424 return False 425 if lang=="cxx" and not self.conf.has_key('PETSC_HAVE_CXX'): 426 srcDict["SKIP"]="C++ required for this test" 427 return False 428 429 # Deprecated source files 430 if srcDict.has_key("TODO"): return False 431 432 # isRun can work with srcDict to handle the requires 433 if srcDict.has_key("requires"): 434 if len(srcDict["requires"])>0: 435 return self._isRun(srcDict) 436 437 return True 438 439 440 def _isRun(self,testDict): 441 """ 442 Based on the requirements listed in the src file and the petscconf.h 443 info, determine whether this test should be run or not. 444 """ 445 indent=" " 446 debug=False 447 448 # MPI requirements 449 if testDict.has_key('nsize'): 450 if testDict['nsize']>1 and self.conf.has_key('MPI_IS_MPIUNI'): 451 if debug: print indent+"Cannot run parallel tests" 452 testDict['SKIP']="Parallel test with serial build" 453 return False 454 455 # The requirements for the test are the sum of all the run subtests 456 if testDict.has_key('subtests'): 457 if not testDict.has_key('requires'): testDict['requires']="" 458 for stest in testDict['subtests']: 459 if testDict[stest].has_key('requires'): 460 testDict['requires']=testDict['requires']+" "+testDict[stest]['requires'] 461 462 463 # Now go through all requirements 464 if testDict.has_key('requires'): 465 for requirement in testDict['requires'].split(): 466 requirement=requirement.strip() 467 if not requirement: continue 468 if debug: print indent+"Requirement: ", requirement 469 isNull=False 470 if requirement.startswith("!"): 471 requirement=requirement[1:]; isNull=True 472 # Precision requirement for reals 473 if requirement in self.precision_types: 474 if self.conf['PETSC_PRECISION']==requirement: 475 testDict['SKIP']="not "+requirement+" required" 476 if isNull: return False 477 else: 478 testDict['SKIP']=requirement+" required" 479 return False 480 # Precision requirement for ints 481 if requirement in self.integer_types: 482 if requirement=="int32": 483 if self.conf['PETSC_SIZEOF_INT']==4: 484 testDict['SKIP']="not int32 required" 485 if isNull: return False 486 else: 487 testDict['SKIP']="int32 required" 488 return False 489 if requirement=="int64": 490 if self.conf['PETSC_SIZEOF_INT']==8: 491 testDict['SKIP']="NOT int64 required" 492 if isNull: return False 493 else: 494 testDict['SKIP']="int64 required" 495 return False 496 # Datafilespath 497 if requirement=="datafilespath": 498 testDict['SKIP']="Requires DATAFILESPATH" 499 return False 500 # Defines -- not sure I have comments matching 501 if "define(" in requirement.lower(): 502 reqdef=requirement.split("(")[1].split(")")[0] 503 val=(reqdef.split()[1] if " " in reqdef else "") 504 if self.conf.has_key(reqdef): 505 if val: 506 if self.conf[reqdef]==val: 507 if isNull: 508 testDict['SKIP']="Null requirement not met: "+requirement 509 return False 510 else: 511 testDict['SKIP']="Required: "+requirement 512 return False 513 else: 514 if isNull: 515 testDict['SKIP']="Null requirement not met: "+requirement 516 return False 517 else: 518 return True 519 else: 520 testDict['SKIP']="Requirement not met: "+requirement 521 return False 522 523 # Rest should be packages that we can just get from conf 524 if requirement == "complex": petscconfvar="PETSC_USE_COMPLEX" 525 else: petscconfvar="PETSC_HAVE_"+requirement.upper() 526 if self.conf.get(petscconfvar): 527 if isNull: 528 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 529 return False 530 elif not isNull: 531 if debug: print "requirement not found: ", requirement 532 testDict['SKIP']=petscconfvar+" requirement not met" 533 return False 534 535 return True 536 537 def genPetscTests_summarize(self,dataDict): 538 """ 539 Required method to state what happened 540 """ 541 if not self.summarize: return 542 indent=" " 543 fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt') 544 fh=open(fhname,"w") 545 #print "See ", fhname 546 for root in dataDict: 547 relroot=self.relpath(self.petsc_dir,root) 548 pkg=relroot.split("/")[1] 549 fh.write(relroot+"\n") 550 allSrcs=[] 551 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 552 for exfile in dataDict[root]: 553 # Basic information 554 fullfile=os.path.join(root,exfile) 555 rfile=self.relpath(self.petsc_dir,fullfile) 556 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 557 fh.write(indent+exfile+indent*4+builtStatus+"\n") 558 559 for test in dataDict[root][exfile]: 560 if test in self.buildkeys: continue 561 line=indent*2+test 562 fh.write(line+"\n") 563 # Looks nice to have the keys in order 564 #for key in dataDict[root][exfile][test]: 565 for key in "isrun abstracted nsize args requires script".split(): 566 if not dataDict[root][exfile][test].has_key(key): continue 567 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 568 fh.write(line+"\n") 569 fh.write("\n") 570 fh.write("\n") 571 fh.write("\n") 572 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 573 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 574 fh.close() 575 return 576 577 def genPetscTests(self,root,dirs,files,dataDict): 578 """ 579 Go through and parse the source files in the directory to generate 580 the examples based on the metadata contained in the source files 581 """ 582 debug=False 583 # Use examplesAnalyze to get what the makefles think are sources 584 #self.examplesAnalyze(root,dirs,files,anlzDict) 585 586 dataDict[root]={} 587 588 for exfile in files: 589 #TST: Until we replace files, still leaving the orginals as is 590 #if not exfile.startswith("new_"+"ex"): continue 591 if not exfile.startswith("ex"): continue 592 593 # Convenience 594 fullex=os.path.join(root,exfile) 595 relpfile=self.relpath(self.petsc_dir,fullex) 596 if debug: print relpfile 597 dataDict[root].update(testparse.parseTestFile(fullex)) 598 # Need to check and make sure tests are in the file 599 # if verbosity>=1: print relpfile 600 if dataDict[root].has_key(exfile): 601 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 602 603 return 604 605 def walktree(self,top,action="printFiles"): 606 """ 607 Walk a directory tree, starting from 'top' 608 """ 609 #print "action", action 610 # Goal of action is to fill this dictionary 611 dataDict={} 612 for root, dirs, files in os.walk(top, topdown=False): 613 if not "examples" in root: continue 614 if not os.path.isfile(os.path.join(root,"makefile")): continue 615 bname=os.path.basename(root.rstrip("/")) 616 if bname=="tests" or bname=="tutorials": 617 eval("self."+action+"(root,dirs,files,dataDict)") 618 if type(top) != types.StringType: 619 raise TypeError("top must be a string") 620 # Now summarize this dictionary 621 eval("self."+action+"_summarize(dataDict)") 622 return dataDict 623 624 def gen_gnumake(self, fd): 625 """ 626 Overwrite of the method in the base PETSc class 627 """ 628 def write(stem, srcs): 629 for lang in LANGS: 630 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 631 for pkg in PKGS: 632 srcs = self.gen_pkg(pkg) 633 write('testsrcs-' + pkg, srcs) 634 return self.gendeps 635 636 def gen_pkg(self, pkg): 637 """ 638 Overwrite of the method in the base PETSc class 639 """ 640 return self.sources[pkg] 641 642 def write_gnumake(self,dataDict): 643 """ 644 Write out something similar to files from gmakegen.py 645 646 There is not a lot of has_key type checking because 647 should just work and need to know if there are bugs 648 649 Test depends on script which also depends on source 650 file, but since I don't have a good way generating 651 acting on a single file (oops) just depend on 652 executable which in turn will depend on src file 653 """ 654 # Different options for how to set up the targets 655 compileExecsFirst=False 656 657 # Open file 658 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 659 fd = open(arch_files, 'w') 660 661 # Write out the sources 662 gendeps = self.gen_gnumake(fd) 663 664 # Write out the tests and execname targets 665 fd.write("\n#Tests and executables\n") # Delimiter 666 667 for pkg in PKGS: 668 # These grab the ones that are built 669 for lang in LANGS: 670 testdeps=[] 671 for ftest in self.tests[pkg][lang]: 672 test=os.path.basename(ftest) 673 basedir=os.path.dirname(ftest) 674 testdeps.append(self.nameSpace(test,basedir)) 675 fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n") 676 fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang)) 677 678 # test targets 679 for ftest in self.tests[pkg][lang]: 680 test=os.path.basename(ftest) 681 basedir=os.path.dirname(ftest) 682 testdir="${TESTDIR}/"+basedir+"/" 683 nmtest=self.nameSpace(test,basedir) 684 rundir=os.path.join(testdir,test) 685 #print test, nmtest 686 script=test+".sh" 687 688 # Deps 689 exfile=self.tests[pkg][lang][ftest]['exfile'] 690 fullex=os.path.join(self.petsc_dir,exfile) 691 localexec=self.tests[pkg][lang][ftest]['exec'] 692 execname=os.path.join(testdir,localexec) 693 fullscript=os.path.join(testdir,script) 694 tmpfile=os.path.join(testdir,test,test+".tmp") 695 696 # *.counts depends on the script and either executable (will 697 # be run) or the example source file (SKIP or TODO) 698 fd.write('%s.counts : %s %s\n' 699 % (os.path.join('$(TESTDIR)/counts', nmtest), 700 fullscript, 701 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)) 702 # Now write the args: 703 fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 704 705 fd.close() 706 return 707 708 def writeHarness(self,output,dataDict): 709 """ 710 This is set up to write out multiple harness even if only gnumake 711 is supported now 712 """ 713 eval("self.write_"+output+"(dataDict)") 714 return 715 716def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 717 if output is None: 718 output = 'gnumake' 719 720 721 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 722 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 723 pEx.writeHarness(output,dataDict) 724 725if __name__ == '__main__': 726 import optparse 727 parser = optparse.OptionParser() 728 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 729 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 730 parser.add_option('--output', help='Location to write output file', default=None) 731 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') 732 opts, extra_args = parser.parse_args() 733 if extra_args: 734 import sys 735 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 736 exit(1) 737 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 738