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