1#!/usr/bin/env python 2 3import os,shutil, string, re 4from distutils.sysconfig import parse_makefile 5import sys 6import logging, time 7import types 8sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 9from cmakegen import Mistakes, stripsplit, AUTODIRS, SKIPDIRS 10from cmakegen import defaultdict # collections.defaultdict, with fallback for python-2.4 11from gmakegen import * 12 13import inspect 14thisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 15sys.path.insert(0,thisscriptdir) 16import testparse 17import example_template 18 19class generateExamples(Petsc): 20 """ 21 gmakegen.py has basic structure for finding the files, writing out 22 the dependencies, etc. 23 """ 24 def __init__(self,petsc_dir=None, petsc_arch=None, verbose=False, single_ex=False): 25 super(generateExamples, self).__init__(petsc_dir=None, petsc_arch=None, verbose=False) 26 27 self.single_ex=single_ex 28 self.arch_dir=os.path.join(self.petsc_dir,self.petsc_arch) 29 self.ptNaming=True 30 # Whether to write out a useful debugging 31 #if verbose: self.summarize=True 32 self.summarize=True 33 34 # For help in setting the requirements 35 self.precision_types="single double quad int32".split() 36 self.integer_types="int32 int64".split() 37 self.languages="fortran cuda cxx".split() # Always requires C so do not list 38 39 # Things that are not test 40 self.buildkeys=testparse.buildkeys 41 42 # Adding a dictionary for storing sources, objects, and tests 43 # to make building the dependency tree easier 44 self.sources={} 45 self.objects={} 46 self.tests={} 47 for pkg in PKGS: 48 self.sources[pkg]={} 49 self.objects[pkg]=[] 50 self.tests[pkg]={} 51 for lang in LANGS: 52 self.sources[pkg][lang]={} 53 self.sources[pkg][lang]['srcs']=[] 54 self.tests[pkg][lang]={} 55 56 # Do some initialization 57 self.testroot_dir=os.path.join(self.arch_dir,"tests") 58 if not os.path.isdir(self.testroot_dir): os.makedirs(self.testroot_dir) 59 return 60 61 def nameSpace(self,srcfile,srcdir): 62 """ 63 Because the scripts have a non-unique naming, the pretty-printing 64 needs to convey the srcdir and srcfile. There are two ways of doing this. 65 """ 66 if self.ptNaming: 67 cdir=srcdir.split('src')[1].lstrip("/").rstrip("/") 68 prefix=cdir.replace('/examples/','_').replace("/","_")+"-" 69 nameString=prefix+srcfile 70 else: 71 #nameString=srcdir+": "+srcfile 72 nameString=srcfile 73 return nameString 74 75 def getLanguage(self,srcfile): 76 """ 77 Based on the source, determine associated language as found in gmakegen.LANGS 78 Can we just return srcext[1:\] now? 79 """ 80 langReq=None 81 srcext=os.path.splitext(srcfile)[-1] 82 if srcext in ".F90".split(): langReq="F90" 83 if srcext in ".F".split(): langReq="F" 84 if srcext in ".cxx".split(): langReq="cxx" 85 if srcext == ".cu": langReq="cu" 86 if srcext == ".c": langReq="c" 87 #if not langReq: print "ERROR: ", srcext, srcfile 88 return langReq 89 90 def getArgLabel(self,testDict): 91 """ 92 In all of the arguments in the test dictionary, create a simple 93 string for searching within the makefile system. For simplicity in 94 search, remove "-", for strings, etc. 95 Also, concatenate the arg commands 96 For now, ignore nsize -- seems hard to search for anyway 97 """ 98 # Collect all of the args associated with a test 99 argStr=("" if not testDict.has_key('args') else testDict['args']) 100 if testDict.has_key('subtests'): 101 for stest in testDict["subtests"]: 102 sd=testDict[stest] 103 argStr=argStr+("" if not sd.has_key('args') else sd['args']) 104 105 # Now go through and cleanup 106 argStr=re.sub('{{(.*?)}}',"",argStr) 107 argStr=re.sub('-'," ",argStr) 108 for digit in string.digits: argStr=re.sub(digit," ",argStr) 109 argStr=re.sub("\.","",argStr) 110 argStr=re.sub(",","",argStr) 111 argStr=re.sub('\+',' ',argStr) 112 argStr=re.sub(' +',' ',argStr) # Remove repeated white space 113 return argStr.strip() 114 115 def addToSources(self,exfile,root,srcDict): 116 """ 117 Put into data structure that allows easy generation of makefile 118 """ 119 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 120 fullfile=os.path.join(root,exfile) 121 relpfile=self.relpath(self.petsc_dir,fullfile) 122 lang=self.getLanguage(exfile) 123 if not lang: return 124 self.sources[pkg][lang]['srcs'].append(relpfile) 125 if srcDict.has_key('depends'): 126 depSrc=srcDict['depends'] 127 depObj=os.path.splitext(depSrc)[0]+".o" 128 self.sources[pkg][lang][exfile]=depObj 129 130 # In gmakefile, ${TESTDIR} var specifies the object compilation 131 testsdir=self.relpath(self.petsc_dir,root)+"/" 132 objfile="${TESTDIR}/"+testsdir+os.path.splitext(exfile)[0]+".o" 133 self.objects[pkg].append(objfile) 134 return 135 136 def addToTests(self,test,root,exfile,execname,testDict): 137 """ 138 Put into data structure that allows easy generation of makefile 139 Organized by languages to allow testing of languages 140 """ 141 pkg=self.relpath(self.petsc_dir,root).split("/")[1] 142 #nmtest=self.nameSpace(test,root) 143 rpath=self.relpath(self.petsc_dir,root) 144 nmtest=os.path.join(rpath,test) 145 lang=self.getLanguage(exfile) 146 if not lang: return 147 self.tests[pkg][lang][nmtest]={} 148 self.tests[pkg][lang][nmtest]['exfile']=os.path.join(rpath,exfile) 149 self.tests[pkg][lang][nmtest]['exec']=execname 150 self.tests[pkg][lang][nmtest]['argLabel']=self.getArgLabel(testDict) 151 return 152 153 def getFor(self,subst,i,j): 154 """ 155 Get the for and done lines 156 """ 157 forlines="" 158 donlines="" 159 indent=" " 160 nsizeStr=subst['nsize'] 161 for loop in re.findall('{{(.*?)}}',subst['nsize']): 162 lindex=string.ascii_lowercase[i] 163 forline=indent*j+"for "+lindex+" in '"+loop+"'; do" 164 nsizeStr=re.sub("{{"+loop+"}}","${"+lindex+"}",nsizeStr) 165 donline=indent*j+"done" 166 forlines=forlines+forline+"\n" 167 donlines=donlines+donline+"\n" 168 i=i+1 169 j=j+1 170 subst['nsize']=nsizeStr 171 argStr=subst['args'] 172 for loop in re.findall('{{(.*?)}}',subst['args']): 173 lindex=string.ascii_lowercase[i] 174 forline=indent*j+"for "+lindex+" in '"+loop+"'; do" 175 argStr=re.sub("{{"+loop+"}}","${"+lindex+"}",argStr) 176 donline=indent*j+"done" 177 forlines=forlines+forline+"\n" 178 donlines=donlines+donline+"\n" 179 i=i+1 180 j=j+1 181 subst['args']=argStr 182 183 # The do lines have reverse order with respect to indentation 184 dl=donlines.rstrip("\n").split("\n") 185 dl.reverse() 186 donlines="\n".join(dl)+"\n" 187 188 return forlines,donlines,i,j 189 190 191 def getExecname(self,exfile,root): 192 """ 193 Generate bash script using template found next to this file. 194 This file is read in at constructor time to avoid file I/O 195 """ 196 rpath=self.relpath(self.petsc_dir,root) 197 if self.single_ex: 198 execname=rpath.split("/")[1]+"-ex" 199 else: 200 execname=os.path.splitext(exfile)[0] 201 return execname 202 203 def getSubstVars(self,testDict,rpath,testname): 204 """ 205 Create a dictionary with all of the variables that get substituted 206 into the template commands found in example_template.py 207 TODO: Cleanup 208 """ 209 subst={} 210 # Handle defaults 211 if not testDict.has_key('nsize'): testDict['nsize']=1 212 if not testDict.has_key('filter'): testDict['filter']="" 213 if not testDict.has_key('filter_output'): testDict['filter_output']="" 214 if not testDict.has_key('localrunfiles'): testDict['localrunfiles']="" 215 if not testDict.has_key('args'): testDict['args']="" 216 defroot=(re.sub("run","",testname) if testname.startswith("run") else testname) 217 if not "_" in defroot: defroot=defroot+"_1" 218 if not testDict.has_key('redirect_file'): testDict['redirect_file']=defroot+".tmp" 219 if not testDict.has_key('output_file'): testDict['output_file']="output/"+defroot+".out" 220 221 # Setup the variables in template_string that need to be substituted 222 subst['srcdir']=os.path.join(self.petsc_dir,rpath) 223 subst['label']=self.nameSpace(defroot,subst['srcdir']) 224 subst['redirect_file']=testDict['redirect_file'] 225 subst['output_file']=os.path.join(subst['srcdir'],testDict['output_file']) 226 subst['exec']="../"+testDict['execname'] 227 subst['filter']="'"+testDict['filter']+"'" # Quotes are tricky 228 subst['filter_output']=testDict['filter_output'] 229 subst['localrunfiles']=testDict['localrunfiles'] 230 subst['testroot']=self.testroot_dir 231 subst['testname']=testname 232 233 # Be careful with this 234 if testDict.has_key('command'): subst['command']=testDict['command'] 235 236 # These can have for loops and are treated separately later 237 if testDict.has_key('nsize'): subst['nsize']=str(testDict['nsize']) 238 if testDict.has_key('args'): subst['args']=testDict['args'] 239 240 #Conf vars 241 subst['mpiexec']=self.conf['MPIEXEC'] # make sure PETSC_DIR is defined! 242 subst['petsc_dir']=self.petsc_dir # not self.conf['PETSC_DIR'] as this could be windows path 243 subst['diff']=self.conf['DIFF'] 244 subst['rm']=self.conf['RM'] 245 subst['grep']=self.conf['GREP'] 246 subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR'] 247 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('@TESTROOT@',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" or lang=="F90") 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 # Precision requirement for reals 469 if requirement in self.precision_types: 470 if self.conf['PETSC_PRECISION']==requirement: 471 testDict['SKIP']="not "+requirement+" required" 472 if isNull: return False 473 else: 474 testDict['SKIP']=requirement+" required" 475 return False 476 # Precision requirement for ints 477 if requirement in self.integer_types: 478 if requirement=="int32": 479 if self.conf['PETSC_SIZEOF_INT']==4: 480 testDict['SKIP']="not int32 required" 481 if isNull: return False 482 else: 483 testDict['SKIP']="int32 required" 484 return False 485 if requirement=="int64": 486 if self.conf['PETSC_SIZEOF_INT']==8: 487 testDict['SKIP']="NOT int64 required" 488 if isNull: return False 489 else: 490 testDict['SKIP']="int64 required" 491 return False 492 # Datafilespath 493 if requirement=="datafilespath": 494 testDict['SKIP']="Requires DATAFILESPATH" 495 return False 496 # Defines -- not sure I have comments matching 497 if "define(" in requirement.lower(): 498 reqdef=requirement.split("(")[1].split(")")[0] 499 val=(reqdef.split()[1] if " " in reqdef else "") 500 if self.conf.has_key(reqdef): 501 if val: 502 if self.conf[reqdef]==val: 503 if isNull: 504 testDict['SKIP']="Null requirement not met: "+requirement 505 return False 506 else: 507 testDict['SKIP']="Required: "+requirement 508 return False 509 else: 510 if isNull: 511 testDict['SKIP']="Null requirement not met: "+requirement 512 return False 513 else: 514 return True 515 else: 516 testDict['SKIP']="Requirement not met: "+requirement 517 return False 518 519 # Rest should be packages that we can just get from conf 520 if requirement == "complex": petscconfvar="PETSC_USE_COMPLEX" 521 else: petscconfvar="PETSC_HAVE_"+requirement.upper() 522 if self.conf.get(petscconfvar): 523 if isNull: 524 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 525 return False 526 elif not isNull: 527 if debug: print "requirement not found: ", requirement 528 testDict['SKIP']=petscconfvar+" requirement not met" 529 return False 530 531 return True 532 533 def genPetscTests_summarize(self,dataDict): 534 """ 535 Required method to state what happened 536 """ 537 if not self.summarize: return 538 indent=" " 539 fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt') 540 fh=open(fhname,"w") 541 #print "See ", fhname 542 for root in dataDict: 543 relroot=self.relpath(self.petsc_dir,root) 544 pkg=relroot.split("/")[1] 545 fh.write(relroot+"\n") 546 allSrcs=[] 547 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 548 for exfile in dataDict[root]: 549 # Basic information 550 fullfile=os.path.join(root,exfile) 551 rfile=self.relpath(self.petsc_dir,fullfile) 552 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 553 fh.write(indent+exfile+indent*4+builtStatus+"\n") 554 555 for test in dataDict[root][exfile]: 556 if test in self.buildkeys: continue 557 line=indent*2+test 558 fh.write(line+"\n") 559 # Looks nice to have the keys in order 560 #for key in dataDict[root][exfile][test]: 561 for key in "isrun abstracted nsize args requires script".split(): 562 if not dataDict[root][exfile][test].has_key(key): continue 563 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 564 fh.write(line+"\n") 565 fh.write("\n") 566 fh.write("\n") 567 fh.write("\n") 568 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 569 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 570 fh.close() 571 return 572 573 def genPetscTests(self,root,dirs,files,dataDict): 574 """ 575 Go through and parse the source files in the directory to generate 576 the examples based on the metadata contained in the source files 577 """ 578 debug=False 579 # Use examplesAnalyze to get what the makefles think are sources 580 #self.examplesAnalyze(root,dirs,files,anlzDict) 581 582 dataDict[root]={} 583 584 for exfile in files: 585 #TST: Until we replace files, still leaving the orginals as is 586 #if not exfile.startswith("new_"+"ex"): continue 587 if not exfile.startswith("ex"): continue 588 589 # Convenience 590 fullex=os.path.join(root,exfile) 591 relpfile=self.relpath(self.petsc_dir,fullex) 592 if debug: print relpfile 593 dataDict[root].update(testparse.parseTestFile(fullex)) 594 # Need to check and make sure tests are in the file 595 # if verbosity>=1: print relpfile 596 if dataDict[root].has_key(exfile): 597 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 598 599 return 600 601 def walktree(self,top,action="printFiles"): 602 """ 603 Walk a directory tree, starting from 'top' 604 """ 605 #print "action", action 606 # Goal of action is to fill this dictionary 607 dataDict={} 608 for root, dirs, files in os.walk(top, topdown=False): 609 if not "examples" in root: continue 610 if not os.path.isfile(os.path.join(root,"makefile")): continue 611 bname=os.path.basename(root.rstrip("/")) 612 if bname=="tests" or bname=="tutorials": 613 eval("self."+action+"(root,dirs,files,dataDict)") 614 if type(top) != types.StringType: 615 raise TypeError("top must be a string") 616 # Now summarize this dictionary 617 eval("self."+action+"_summarize(dataDict)") 618 return dataDict 619 620 def gen_gnumake(self, fd): 621 """ 622 Overwrite of the method in the base PETSc class 623 """ 624 def write(stem, srcs): 625 for lang in LANGS: 626 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 627 for pkg in PKGS: 628 srcs = self.gen_pkg(pkg) 629 write('testsrcs-' + pkg, srcs) 630 return self.gendeps 631 632 def gen_pkg(self, pkg): 633 """ 634 Overwrite of the method in the base PETSc class 635 """ 636 return self.sources[pkg] 637 638 def write_gnumake(self,dataDict): 639 """ 640 Write out something similar to files from gmakegen.py 641 642 There is not a lot of has_key type checking because 643 should just work and need to know if there are bugs 644 645 Test depends on script which also depends on source 646 file, but since I don't have a good way generating 647 acting on a single file (oops) just depend on 648 executable which in turn will depend on src file 649 """ 650 # Different options for how to set up the targets 651 compileExecsFirst=False 652 653 # Open file 654 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 655 fd = open(arch_files, 'w') 656 657 # Write out the sources 658 gendeps = self.gen_gnumake(fd) 659 660 # Write out the tests and execname targets 661 fd.write("\n#Tests and executables\n") # Delimiter 662 663 for pkg in PKGS: 664 # These grab the ones that are built 665 for lang in LANGS: 666 testdeps=[] 667 for ftest in self.tests[pkg][lang]: 668 test=os.path.basename(ftest) 669 basedir=os.path.dirname(ftest) 670 testdeps.append(self.nameSpace(test,basedir)) 671 fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n") 672 fd.write('test-%s.%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang)) 673 674 # test targets 675 for ftest in self.tests[pkg][lang]: 676 test=os.path.basename(ftest) 677 basedir=os.path.dirname(ftest) 678 testdir="${TESTDIR}/"+basedir+"/" 679 nmtest=self.nameSpace(test,basedir) 680 rundir=os.path.join(testdir,test) 681 #print test, nmtest 682 script=test+".sh" 683 684 # Deps 685 exfile=self.tests[pkg][lang][ftest]['exfile'] 686 fullex=os.path.join(self.petsc_dir,exfile) 687 localexec=self.tests[pkg][lang][ftest]['exec'] 688 execname=os.path.join(testdir,localexec) 689 fullscript=os.path.join(testdir,script) 690 tmpfile=os.path.join(testdir,test,test+".tmp") 691 692 # *.counts depends on the script and either executable (will 693 # be run) or the example source file (SKIP or TODO) 694 fd.write('%s.counts : %s %s\n' 695 % (os.path.join('$(TESTDIR)/counts', nmtest), 696 fullscript, 697 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)) 698 # Now write the args: 699 fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 700 701 fd.close() 702 return 703 704 def writeHarness(self,output,dataDict): 705 """ 706 This is set up to write out multiple harness even if only gnumake 707 is supported now 708 """ 709 eval("self.write_"+output+"(dataDict)") 710 return 711 712def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 713 if output is None: 714 output = 'gnumake' 715 716 717 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 718 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 719 pEx.writeHarness(output,dataDict) 720 721if __name__ == '__main__': 722 import optparse 723 parser = optparse.OptionParser() 724 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 725 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 726 parser.add_option('--output', help='Location to write output file', default=None) 727 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') 728 opts, extra_args = parser.parse_args() 729 if extra_args: 730 import sys 731 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 732 exit(1) 733 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 734