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 subst['petsc_lib_dir']=self.conf['PETSC_LIB_DIR'] 245 246 return subst 247 248 def getCmds(self,subst,i): 249 """ 250 Generate bash script using template found next to this file. 251 This file is read in at constructor time to avoid file I/O 252 """ 253 indent=" " 254 nindent=i # the start and has to be consistent with below 255 cmdLines="" 256 # MPI is the default -- but we have a few odd commands 257 if not subst.has_key('command'): 258 cmd=indent*nindent+self._substVars(subst,example_template.mpitest) 259 else: 260 cmd=indent*nindent+self._substVars(subst,example_template.commandtest) 261 cmdLines=cmdLines+cmd+"\n\n" 262 263 if not subst['filter_output']: 264 cmd=indent*nindent+self._substVars(subst,example_template.difftest) 265 else: 266 cmd=indent*nindent+self._substVars(subst,example_template.filterdifftest) 267 cmdLines=cmdLines+cmd+"\n" 268 return cmdLines 269 270 def _substVars(self,subst,origStr): 271 """ 272 Substitute varial 273 """ 274 Str=origStr 275 for subkey in subst: 276 if type(subst[subkey])!=types.StringType: continue 277 patt="@"+subkey.upper()+"@" 278 Str=re.sub(patt,subst[subkey],Str) 279 return Str 280 281 def genRunScript(self,testname,root,isRun,srcDict): 282 """ 283 Generate bash script using template found next to this file. 284 This file is read in at constructor time to avoid file I/O 285 """ 286 # runscript_dir directory has to be consistent with gmakefile 287 testDict=srcDict[testname] 288 rpath=self.relpath(self.petsc_dir,root) 289 runscript_dir=os.path.join(self.testroot_dir,rpath) 290 if not os.path.isdir(runscript_dir): os.makedirs(runscript_dir) 291 fh=open(os.path.join(runscript_dir,testname+".sh"),"w") 292 petscvarfile=os.path.join(self.arch_dir,'lib','petsc','conf','petscvariables') 293 294 subst=self.getSubstVars(testDict,rpath,testname) 295 296 #Handle runfiles 297 if subst['localrunfiles']: 298 for lfile in subst['localrunfiles'].split(): 299 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 300 shutil.copy(fullfile,runscript_dir) 301 # Check subtests for local runfiles 302 if testDict.has_key("subtests"): 303 for stest in testDict["subtests"]: 304 if testDict[stest].has_key('localrunfiles'): 305 for lfile in testDict[stest]['localrunfiles'].split(): 306 fullfile=os.path.join(self.petsc_dir,rpath,lfile) 307 shutil.copy(fullfile,self.runscript_dir) 308 309 # Now substitute the key variables into the header and footer 310 header=self._substVars(subst,example_template.header) 311 footer=re.sub('@TESTROOT@',subst['testroot'],example_template.footer) 312 313 # Start writing the file 314 fh.write(header+"\n") 315 316 # If there is a TODO or a SKIP then we do it before writing out the 317 # rest of the command (which is useful for working on the test) 318 # SKIP and TODO can be for the source file or for the runs 319 if srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 320 if srcDict.has_key("TODO"): 321 todo=re.sub("@TODOCOMMENT@",srcDict['TODO'],example_template.todoline) 322 fh.write(todo+"\ntotal=1; todo=1\n") 323 fh.write(footer+"\n") 324 fh.write("exit\n\n\n") 325 elif srcDict.has_key("SKIP") or srcDict.has_key("TODO"): 326 skip=re.sub("@SKIPCOMMENT@",srcDict['SKIP'],example_template.skipline) 327 fh.write(skip+"\ntotal=1; skip=1\n") 328 fh.write(footer+"\n") 329 fh.write("exit\n\n\n") 330 elif not isRun: 331 skip=re.sub("@SKIPCOMMENT@",testDict['SKIP'],example_template.skipline) 332 fh.write(skip+"\ntotal=1; skip=1\n") 333 fh.write(footer+"\n") 334 fh.write("exit\n\n\n") 335 elif testDict.has_key('TODO'): 336 todo=re.sub("@TODOCOMMENT@",testDict['TODO'],example_template.todoline) 337 fh.write(todo+"\ntotal=1; todo=1\n") 338 fh.write(footer+"\n") 339 fh.write("exit\n\n\n") 340 341 # Need to handle loops 342 i=8 # for loop counters 343 j=0 # for indentation 344 345 doForP=False 346 if "{{" in subst['args']+subst['nsize']: 347 doForP=True 348 flinesP,dlinesP,i,j=self.getFor(subst,i,j) 349 fh.write(flinesP+"\n") 350 351 # Subtests are special 352 if testDict.has_key("subtests"): 353 substP=subst # Subtests can inherit args but be careful 354 if not substP.has_key("arg"): substP["arg"]="" 355 jorig=j 356 for stest in testDict["subtests"]: 357 j=jorig 358 subst=substP 359 subst.update(testDict[stest]) 360 subst['nsize']=str(subst['nsize']) 361 if not testDict[stest].has_key('args'): testDict[stest]['args']="" 362 subst['args']=substP['args']+testDict[stest]['args'] 363 doFor=False 364 if "{{" in subst['args']+subst['nsize']: 365 doFor=True 366 flines,dlines,i,j=self.getFor(subst,i,j) 367 fh.write(flines+"\n") 368 fh.write(self.getCmds(subst,j)+"\n") 369 if doFor: fh.write(dlines+"\n") 370 else: 371 fh.write(self.getCmds(subst,j)+"\n") 372 if doForP: fh.write(dlinesP+"\n") 373 374 fh.write(footer+"\n") 375 os.chmod(os.path.join(runscript_dir,testname+".sh"),0755) 376 return 377 378 def genScriptsAndInfo(self,exfile,root,srcDict): 379 """ 380 Generate scripts from the source file, determine if built, etc. 381 For every test in the exfile with info in the srcDict: 382 1. Determine if it needs to be run for this arch 383 2. Generate the script 384 3. Generate the data needed to write out the makefile in a 385 convenient way 386 All tests are *always* run, but some may be SKIP'd per the TAP standard 387 """ 388 debug=False 389 fileIsTested=False 390 execname=self.getExecname(exfile,root) 391 isBuilt=self._isBuilt(exfile,srcDict) 392 for test in srcDict: 393 if test in self.buildkeys: continue 394 if debug: print self.nameSpace(exfile,root), test 395 srcDict[test]['execname']=execname # Convenience in generating scripts 396 isRun=self._isRun(srcDict[test]) 397 self.genRunScript(test,root,isRun,srcDict) 398 srcDict[test]['isrun']=isRun 399 if isRun: fileIsTested=True 400 self.addToTests(test,root,exfile,execname,srcDict[test]) 401 402 # This adds to datastructure for building deps 403 if fileIsTested and isBuilt: self.addToSources(exfile,root,srcDict) 404 #print self.nameSpace(exfile,root), fileIsTested 405 return 406 407 def _isBuilt(self,exfile,srcDict): 408 """ 409 Determine if this file should be built. 410 """ 411 # Get the language based on file extension 412 lang=self.getLanguage(exfile) 413 if (lang=="F" or lang=="F90") and not self.have_fortran: 414 srcDict["SKIP"]="Fortran required for this test" 415 return False 416 if lang=="cu" and not self.conf.has_key('PETSC_HAVE_CUDA'): 417 srcDict["SKIP"]="CUDA required for this test" 418 return False 419 if lang=="cxx" and not self.conf.has_key('PETSC_HAVE_CXX'): 420 srcDict["SKIP"]="C++ required for this test" 421 return False 422 423 # Deprecated source files 424 if srcDict.has_key("TODO"): return False 425 426 # isRun can work with srcDict to handle the requires 427 if srcDict.has_key("requires"): 428 if len(srcDict["requires"])>0: 429 return self._isRun(srcDict) 430 431 return True 432 433 434 def _isRun(self,testDict): 435 """ 436 Based on the requirements listed in the src file and the petscconf.h 437 info, determine whether this test should be run or not. 438 """ 439 indent=" " 440 debug=False 441 442 # MPI requirements 443 if testDict.has_key('nsize'): 444 if testDict['nsize']>1 and self.conf.has_key('MPI_IS_MPIUNI'): 445 if debug: print indent+"Cannot run parallel tests" 446 testDict['SKIP']="Parallel test with serial build" 447 return False 448 449 # The requirements for the test are the sum of all the run subtests 450 if testDict.has_key('subtests'): 451 if not testDict.has_key('requires'): testDict['requires']="" 452 for stest in testDict['subtests']: 453 if testDict[stest].has_key('requires'): 454 testDict['requires']=testDict['requires']+" "+testDict[stest]['requires'] 455 456 457 # Now go through all requirements 458 if testDict.has_key('requires'): 459 for requirement in testDict['requires'].split(): 460 requirement=requirement.strip() 461 if not requirement: continue 462 if debug: print indent+"Requirement: ", requirement 463 isNull=False 464 if requirement.startswith("!"): 465 requirement=requirement[1:]; isNull=True 466 # Precision requirement for reals 467 if requirement in self.precision_types: 468 if self.conf['PETSC_PRECISION']==requirement: 469 testDict['SKIP']="not "+requirement+" required" 470 if isNull: return False 471 else: 472 testDict['SKIP']=requirement+" required" 473 return False 474 # Precision requirement for ints 475 if requirement in self.integer_types: 476 if requirement=="int32": 477 if self.conf['PETSC_SIZEOF_INT']==4: 478 testDict['SKIP']="not int32 required" 479 if isNull: return False 480 else: 481 testDict['SKIP']="int32 required" 482 return False 483 if requirement=="int64": 484 if self.conf['PETSC_SIZEOF_INT']==8: 485 testDict['SKIP']="NOT int64 required" 486 if isNull: return False 487 else: 488 testDict['SKIP']="int64 required" 489 return False 490 # Datafilespath 491 if requirement=="datafilespath": 492 testDict['SKIP']="Requires DATAFILESPATH" 493 return False 494 # Defines -- not sure I have comments matching 495 if "define(" in requirement.lower(): 496 reqdef=requirement.split("(")[1].split(")")[0] 497 val=(reqdef.split()[1] if " " in reqdef else "") 498 if self.conf.has_key(reqdef): 499 if val: 500 if self.conf[reqdef]==val: 501 if isNull: 502 testDict['SKIP']="Null requirement not met: "+requirement 503 return False 504 else: 505 testDict['SKIP']="Required: "+requirement 506 return False 507 else: 508 if isNull: 509 testDict['SKIP']="Null requirement not met: "+requirement 510 return False 511 else: 512 return True 513 else: 514 testDict['SKIP']="Requirement not met: "+requirement 515 return False 516 517 # Rest should be packages that we can just get from conf 518 if requirement == "complex": petscconfvar="PETSC_USE_COMPLEX" 519 else: petscconfvar="PETSC_HAVE_"+requirement.upper() 520 if self.conf.get(petscconfvar): 521 if isNull: 522 testDict['SKIP']="Not "+petscconfvar+" requirement not met" 523 return False 524 elif not isNull: 525 if debug: print "requirement not found: ", requirement 526 testDict['SKIP']=petscconfvar+" requirement not met" 527 return False 528 529 return True 530 531 def genPetscTests_summarize(self,dataDict): 532 """ 533 Required method to state what happened 534 """ 535 if not self.summarize: return 536 indent=" " 537 fhname=os.path.join(self.testroot_dir,'GenPetscTests_summarize.txt') 538 fh=open(fhname,"w") 539 #print "See ", fhname 540 for root in dataDict: 541 relroot=self.relpath(self.petsc_dir,root) 542 pkg=relroot.split("/")[1] 543 fh.write(relroot+"\n") 544 allSrcs=[] 545 for lang in LANGS: allSrcs=allSrcs+self.sources[pkg][lang]['srcs'] 546 for exfile in dataDict[root]: 547 # Basic information 548 fullfile=os.path.join(root,exfile) 549 rfile=self.relpath(self.petsc_dir,fullfile) 550 builtStatus=(" Is built" if rfile in allSrcs else " Is NOT built") 551 fh.write(indent+exfile+indent*4+builtStatus+"\n") 552 553 for test in dataDict[root][exfile]: 554 if test in self.buildkeys: continue 555 line=indent*2+test 556 fh.write(line+"\n") 557 # Looks nice to have the keys in order 558 #for key in dataDict[root][exfile][test]: 559 for key in "isrun abstracted nsize args requires script".split(): 560 if not dataDict[root][exfile][test].has_key(key): continue 561 line=indent*3+key+": "+str(dataDict[root][exfile][test][key]) 562 fh.write(line+"\n") 563 fh.write("\n") 564 fh.write("\n") 565 fh.write("\n") 566 #fh.write("\nClass Sources\n"+str(self.sources)+"\n") 567 #fh.write("\nClass Tests\n"+str(self.tests)+"\n") 568 fh.close() 569 return 570 571 def genPetscTests(self,root,dirs,files,dataDict): 572 """ 573 Go through and parse the source files in the directory to generate 574 the examples based on the metadata contained in the source files 575 """ 576 debug=False 577 # Use examplesAnalyze to get what the makefles think are sources 578 #self.examplesAnalyze(root,dirs,files,anlzDict) 579 580 dataDict[root]={} 581 582 for exfile in files: 583 #TST: Until we replace files, still leaving the orginals as is 584 #if not exfile.startswith("new_"+"ex"): continue 585 if not exfile.startswith("ex"): continue 586 587 # Convenience 588 fullex=os.path.join(root,exfile) 589 relpfile=self.relpath(self.petsc_dir,fullex) 590 if debug: print relpfile 591 dataDict[root].update(testparse.parseTestFile(fullex)) 592 # Need to check and make sure tests are in the file 593 # if verbosity>=1: print relpfile 594 if dataDict[root].has_key(exfile): 595 self.genScriptsAndInfo(exfile,root,dataDict[root][exfile]) 596 597 return 598 599 def walktree(self,top,action="printFiles"): 600 """ 601 Walk a directory tree, starting from 'top' 602 """ 603 #print "action", action 604 # Goal of action is to fill this dictionary 605 dataDict={} 606 for root, dirs, files in os.walk(top, topdown=False): 607 if not "examples" in root: continue 608 if not os.path.isfile(os.path.join(root,"makefile")): continue 609 bname=os.path.basename(root.rstrip("/")) 610 if bname=="tests" or bname=="tutorials": 611 eval("self."+action+"(root,dirs,files,dataDict)") 612 if type(top) != types.StringType: 613 raise TypeError("top must be a string") 614 # Now summarize this dictionary 615 eval("self."+action+"_summarize(dataDict)") 616 return dataDict 617 618 def gen_gnumake(self, fd): 619 """ 620 Overwrite of the method in the base PETSc class 621 """ 622 def write(stem, srcs): 623 for lang in LANGS: 624 fd.write('%(stem)s.%(lang)s := %(srcs)s\n' % dict(stem=stem, lang=lang, srcs=' '.join(srcs[lang]['srcs']))) 625 for pkg in PKGS: 626 srcs = self.gen_pkg(pkg) 627 write('testsrcs-' + 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) 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 fd.close() 700 return 701 702 def writeHarness(self,output,dataDict): 703 """ 704 This is set up to write out multiple harness even if only gnumake 705 is supported now 706 """ 707 eval("self.write_"+output+"(dataDict)") 708 return 709 710def main(petsc_dir=None, petsc_arch=None, output=None, verbose=False, single_ex=False): 711 if output is None: 712 output = 'gnumake' 713 714 715 pEx=generateExamples(petsc_dir=petsc_dir, petsc_arch=petsc_arch, verbose=verbose, single_ex=single_ex) 716 dataDict=pEx.walktree(os.path.join(pEx.petsc_dir,'src'),action="genPetscTests") 717 pEx.writeHarness(output,dataDict) 718 719if __name__ == '__main__': 720 import optparse 721 parser = optparse.OptionParser() 722 parser.add_option('--verbose', help='Show mismatches between makefiles and the filesystem', action='store_true', default=False) 723 parser.add_option('--petsc-arch', help='Set PETSC_ARCH different from environment', default=os.environ.get('PETSC_ARCH')) 724 parser.add_option('--output', help='Location to write output file', default=None) 725 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') 726 opts, extra_args = parser.parse_args() 727 if extra_args: 728 import sys 729 sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 730 exit(1) 731 main(petsc_arch=opts.petsc_arch, output=opts.output, verbose=opts.verbose, single_ex=opts.single_executable) 732