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