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['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" or lang=="F90") 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 # Different options for how to set up the targets 649 compileExecsFirst=False 650 651 # Open file 652 arch_files = self.arch_path('lib','petsc','conf', 'testfiles') 653 fd = open(arch_files, 'w') 654 655 # Write out the sources 656 gendeps = self.gen_gnumake(fd,prefix="testsrcs-") 657 658 # Write out the tests and execname targets 659 fd.write("\n#Tests and executables\n") # Delimiter 660 661 for pkg in PKGS: 662 # These grab the ones that are built 663 for lang in LANGS: 664 testdeps=[] 665 for ftest in self.tests[pkg][lang]: 666 test=os.path.basename(ftest) 667 basedir=os.path.dirname(ftest) 668 testdeps.append(self.nameSpace(test,basedir)) 669 fd.write("test-"+pkg+"."+lang+" := "+' '.join(testdeps)+"\n") 670 fd.write('test-%s-%s : $(test-%s.%s)\n' % (pkg, lang, pkg, lang)) 671 672 # test targets 673 for ftest in self.tests[pkg][lang]: 674 test=os.path.basename(ftest) 675 basedir=os.path.dirname(ftest) 676 testdir="${TESTDIR}/"+basedir+"/" 677 nmtest=self.nameSpace(test,basedir) 678 rundir=os.path.join(testdir,test) 679 #print test, nmtest 680 script=test+".sh" 681 682 # Deps 683 exfile=self.tests[pkg][lang][ftest]['exfile'] 684 fullex=os.path.join(self.petsc_dir,exfile) 685 localexec=self.tests[pkg][lang][ftest]['exec'] 686 execname=os.path.join(testdir,localexec) 687 fullscript=os.path.join(testdir,script) 688 tmpfile=os.path.join(testdir,test,test+".tmp") 689 690 # *.counts depends on the script and either executable (will 691 # be run) or the example source file (SKIP or TODO) 692 fd.write('%s.counts : %s %s\n' 693 % (os.path.join('$(TESTDIR)/counts', nmtest), 694 fullscript, 695 execname if exfile in self.sources[pkg][lang]['srcs'] else fullex)) 696 # Now write the args: 697 fd.write(nmtest+"_ARGS := '"+self.tests[pkg][lang][ftest]['argLabel']+"'\n") 698 699 # rm targets 700 fd.write("test-rm-"+pkg+"-"+lang+": test-"+pkg+"-"+lang+"\n") 701 for exfile in self.sources[pkg][lang]['srcs']: 702 root=os.path.join(self.petsc_dir,os.path.dirname(exfile)) 703 basedir=os.path.dirname(exfile) 704 testdir="${TESTDIR}/"+basedir+"/" 705 localexec=os.path.basename(os.path.splitext(exfile)[0]) 706 execname=os.path.join(testdir,localexec) 707 line="\t@$(RM) "+execname 708 fd.write(line+"\n") 709 710 fd.close() 711 return 712 713 def writeHarness(self,output,dataDict): 714 """ 715 This is set up to write out multiple harness even if only gnumake 716 is supported now 717 """ 718 eval("self.write_"+output+"(dataDict)") 719 return 720 721def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 722 if output is None: 723 output = 'gnumake' 724 725 726 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 727 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 728 pEx.writeHarness(output,dataDict) 729 730if __name__ == '__main__': 731 import optparse 732 parser = optparse.OptionParser() 733 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 734 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 735 parser.add_option('--output', help='Location to write output file', default=None) 736 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') 737 opts, extra_args = parser.parse_args() 738 if extra_args: 739 import sys 740 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 741 exit(1) 742 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 743