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"),0777) 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 testDict['SKIP']="Non-complex build required" 472 if isNull: return False 473 else: 474 testDict['SKIP']="Complex build required" 475 return False 476 # Precision requirement for reals 477 if requirement in self.precision_types: 478 if self.conf['PETSC_PRECISION']==requirement: 479 testDict['SKIP']="not "+requirement+" required" 480 if isNull: return False 481 else: 482 testDict['SKIP']=requirement+" required" 483 return False 484 # Precision requirement for ints 485 if requirement in self.integer_types: 486 if requirement=="int32": 487 if self.conf['PETSC_SIZEOF_INT']==4: 488 testDict['SKIP']="not int32 required" 489 if isNull: return False 490 else: 491 testDict['SKIP']="int32 required" 492 return False 493 if requirement=="int64": 494 if self.conf['PETSC_SIZEOF_INT']==8: 495 testDict['SKIP']="NOT int64 required" 496 if isNull: return False 497 else: 498 testDict['SKIP']="int64 required" 499 return False 500 # Datafilespath 501 if requirement=="datafilespath": 502 testDict['SKIP']="Requires DATAFILESPATH" 503 return False 504 # Defines -- not sure I have comments matching 505 if "define(" in requirement.lower(): 506 reqdef=requirement.split("(")[1].split(")")[0] 507 val=(reqdef.split()[1] if " " in reqdef else "") 508 if self.conf.has_key(reqdef): 509 if val: 510 if self.conf[reqdef]==val: 511 if isNull: 512 testDict['SKIP']="Null requirement not met: "+requirement 513 return False 514 else: 515 testDict['SKIP']="Required: "+requirement 516 return False 517 else: 518 if isNull: 519 testDict['SKIP']="Null requirement not met: "+requirement 520 return False 521 else: 522 return True 523 else: 524 testDict['SKIP']="Requirement not met: "+requirement 525 return False 526 527 # Rest should be packages that we can just get from conf 528 petscconfvar="PETSC_HAVE_"+requirement.upper() 529 if self.conf.get(petscconfvar): 530 if isNull: 531 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 532 return False 533 else: 534 if debug: print "requirement not found: ", requirement 535 testDict['SKIP']=petscconfvar+" requirement not met" 536 return False 537 538 return True 539 540 def genPetscTests_summarize(self,dataDict): 541 """ 542 Required method to state what happened 543 """ 544 if not self.summarize: return 545 indent=" " 546 fhname="GenPetscTests_summarize.txt" 547 fh=open(fhname,"w") 548 #print "See ", fhname 549 for root in dataDict: 550 relroot=self.relpath(self.petsc_dir,root) 551 pkg=relroot.split("/")[1] 552 fh.write(relroot+"\n") 553 allSrcs=[] 554 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 555 for exfile in dataDict[root]: 556 # Basic information 557 fullfile=os.path.join(root,exfile) 558 rfile=self.relpath(self.petsc_dir,fullfile) 559 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 560 fh.write(indent+exfile+indent*4+builtStatus+"\n") 561 562 for test in dataDict[root][exfile]: 563 if test in self.buildkeys: continue 564 line=indent*2+test 565 fh.write(line+"\n") 566 # Looks nice to have the keys in order 567 #for key in dataDict[root][exfile][test]: 568 for key in "isrun abstracted nsize args requires script".split(): 569 if not dataDict[root][exfile][test].has_key(key): continue 570 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 571 fh.write(line+"\n") 572 fh.write("\n") 573 fh.write("\n") 574 fh.write("\n") 575 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 576 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 577 fh.close() 578 return 579 580 def genPetscTests(self,root,dirs,files,dataDict): 581 """ 582 Go through and parse the source files in the directory to generate 583 the examples based on the metadata contained in the source files 584 """ 585 debug=False 586 # Use examplesAnalyze to get what the makefles think are sources 587 #self.examplesAnalyze(root,dirs,files,anlzDict) 588 589 dataDict[root]={} 590 591 for exfile in files: 592 #TST: Until we replace files, still leaving the orginals as is 593 #if not exfile.startswith("new_"+"ex"): continue 594 if not exfile.startswith("ex"): continue 595 596 # Convenience 597 fullex=os.path.join(root,exfile) 598 relpfile=self.relpath(self.petsc_dir,fullex) 599 if debug: print relpfile 600 dataDict[root].update(testparse.parseTestFile(fullex)) 601 # Need to check and make sure tests are in the file 602 # if verbosity>=1: print relpfile 603 if dataDict[root].has_key(exfile): 604 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 605 606 return 607 608 def walktree(self,top,action="printFiles"): 609 """ 610 Walk a directory tree, starting from 'top' 611 """ 612 #print "action", action 613 # Goal of action is to fill this dictionary 614 dataDict={} 615 for root, dirs, files in os.walk(top, topdown=False): 616 if not "examples" in root: continue 617 if not os.path.isfile(os.path.join(root,"makefile")): continue 618 bname=os.path.basename(root.rstrip("/")) 619 if bname=="tests" or bname=="tutorials": 620 eval("self."+action+"(root,dirs,files,dataDict)") 621 if type(top) != types.StringType: 622 raise TypeError("top must be a string") 623 # Now summarize this dictionary 624 eval("self."+action+"_summarize(dataDict)") 625 return dataDict 626 627 def gen_gnumake(self, fd,prefix='srcs-'): 628 """ 629 Overwrite of the method in the base PETSc class 630 """ 631 def write(stem, srcs): 632 fd.write('%s :=\n' % stem) 633 for lang in LANGS: 634 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 635 fd.write('%(stem)s += $(%(stem)s.%(lang)s)\n' % dict(stem=stem, lang=lang)) 636 for pkg in PKGS: 637 srcs = self.gen_pkg(pkg) 638 write(prefix + pkg, srcs) 639 return self.gendeps 640 641 def gen_pkg(self, pkg): 642 """ 643 Overwrite of the method in the base PETSc class 644 """ 645 return self.sources[pkg] 646 647 def write_gnumake(self,dataDict): 648 """ 649 Write out something similar to files from gmakegen.py 650 651 There is not a lot of has_key type checking because 652 should just work and need to know if there are bugs 653 654 Test depends on script which also depends on source 655 file, but since I don't have a good way generating 656 acting on a single file (oops) just depend on 657 executable which in turn will depend on src file 658 """ 659 # Open file 660 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 661 arg_files = self.arch_path('lib','petsc','conf', 'testargfiles') 662 fd = open(arch_files, 'w') 663 fa = open(arg_files, 'w') 664 665 # Write out the sources 666 gendeps = self.gen_gnumake(fd,prefix="testsrcs-") 667 668 # Write out the tests and execname targets 669 fd.write("\n#Tests and executables\n") # Delimiter 670 testdeps=" ".join(["test-"+pkg for pkg in PKGS]) 671 testexdeps=" ".join(["test-ex-"+pkg for pkg in PKGS]) 672 fd.write("test: testinit testex testpkgs report_tests\n") # Main test target 673 fd.write("testpkgs: "+testdeps+"\n") # The test for the pkgs 674 # Testinit handles the logging 675 fd.write("testinit:\n") 676 fd.write("\t-@rm -f ${PETSC_ARCH}/tests/test.log\n") 677 fd.write("\t-@touch ${PETSC_ARCH}/tests/test.log\n") 678 # Add executables to build right way to make the `make test` look 679 # nicer 680 fd.write("testex: "+testexdeps+"\n") # Main test target 681 682 for pkg in PKGS: 683 # These grab the ones that are built 684 # Package tests 685 testdeps=" ".join(["test-"+pkg+"-"+lang for lang in LANGS]) 686 fd.write("test-"+pkg+": "+testdeps+"\n") 687 testexdeps=" ".join(["test-ex-"+pkg+"-"+lang for lang in LANGS]) 688 fd.write("test-ex-"+pkg+": "+testexdeps+"\n") 689 # This needs work 690 if self.single_ex: 691 execname=pkg+"-ex" 692 fd.write(execname+": "+" ".join(self.objects[pkg])+"\n\n") 693 for lang in LANGS: 694 testdeps="" 695 for ftest in self.tests[pkg][lang]: 696 test=os.path.basename(ftest) 697 basedir=os.path.dirname(ftest) 698 testdeps=testdeps+" "+self.nameSpace(test,basedir) 699 fd.write("test-"+pkg+"-"+lang+":"+testdeps+"\n") 700 701 # test targets 702 for ftest in self.tests[pkg][lang]: 703 test=os.path.basename(ftest) 704 basedir=os.path.dirname(ftest) 705 testdir="${TESTDIR}/"+basedir+"/" 706 nmtest=self.nameSpace(test,basedir) 707 rundir=os.path.join(testdir,test) 708 #print test, nmtest 709 script=test+".sh" 710 711 # Deps 712 exfile=self.tests[pkg][lang][ftest]['exfile'] 713 fullex=os.path.join(self.petsc_dir,exfile) 714 localexec=self.tests[pkg][lang][ftest]['exec'] 715 execname=os.path.join(testdir,localexec) 716 717 # SKIP and TODO tests do not depend on exec 718 if exfile in self.sources[pkg][lang]['srcs']: 719 #print "Found dep: "+exfile, execname 720 fd.write(nmtest+": "+execname+"\n") 721 else: 722 # Still add dependency to file 723 fd.write(nmtest+": "+fullex+"\n") 724 cmd=testdir+"/"+script+" ${TESTFLAGS} | tee -a ${PETSC_ARCH}/tests/test.log" 725 fd.write("\t-@"+cmd+"\n") 726 # Now write the args: 727 fa.write(nmtest+"_ARGS='"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 728 729 # executable targets -- add these to build earlier 730 testexdeps="" 731 if not self.single_ex: 732 for exfile in self.sources[pkg][lang]['srcs']: 733 localexec=os.path.basename(os.path.splitext(exfile)[0]) 734 basedir=os.path.dirname(exfile) 735 testdir="${TESTDIR}/"+basedir+"/" 736 execname=os.path.join(testdir,localexec) 737 testexdeps=testexdeps+" "+execname 738 fd.write("test-ex-"+pkg+"-"+lang+":"+testexdeps+"\n") 739 740 for exfile in self.sources[pkg][lang]['srcs']: 741 root=os.path.join(self.petsc_dir,os.path.dirname(exfile)) 742 basedir=os.path.dirname(exfile) 743 testdir="${TESTDIR}/"+basedir+"/" 744 base=os.path.basename(exfile) 745 objfile=testdir+os.path.splitext(base)[0]+".o" 746 linker=self.getLanguage(exfile)[0].upper()+"LINKER" 747 if self.sources[pkg][lang].has_key(exfile): 748 # Dependency for file 749 objfile=objfile+" "+self.sources[pkg][lang][exfile] 750 print objfile 751 if not self.single_ex: 752 localexec=os.path.basename(os.path.splitext(exfile)[0]) 753 execname=os.path.join(testdir,localexec) 754 localobj=os.path.basename(objfile) 755 petsc_lib="${PETSC_"+pkg.upper()+"_LIB}" 756 fd.write("\n"+execname+": "+objfile+" ${libpetscall}\n") 757 # There should be a better way here 758 line="\t-cd "+testdir+"; ${"+linker+"} -o "+localexec+" "+localobj+" "+petsc_lib 759 fd.write(line+"\n") 760 linker=self.getLanguage(exfile)[0].upper()+"LINKER" 761 762 fd.write("helptests:\n\t -@grep '^[a-z]' ${generatedtest} | cut -f1 -d:\n") 763 # Write out tests 764 return 765 766 def writeHarness(self,output,dataDict): 767 """ 768 This is set up to write out multiple harness even if only gnumake 769 is supported now 770 """ 771 eval("self.write_"+output+"(dataDict)") 772 return 773 774def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 775 if output is None: 776 output = 'gnumake' 777 778 779 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 780 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 781 pEx.writeHarness(output,dataDict) 782 783if __name__ == '__main__': 784 import optparse 785 parser = optparse.OptionParser() 786 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 787 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 788 parser.add_option('--output', help='Location to write output file', default=None) 789 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') 790 opts, extra_args = parser.parse_args() 791 if extra_args: 792 import sys 793 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 794 exit(1) 795 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 796