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