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