1*f8833479SBarry Smith#!/usr/bin/env python 2*f8833479SBarry Smith''' 3*f8833479SBarry Smith This is the first try for a hierarchically configured module. The idea is to 4*f8833479SBarry Smithadd the configure objects from a previously executed framework into the current 5*f8833479SBarry Smithframework. However, this necessitates a reorganization of the activities in the 6*f8833479SBarry Smithmodule. 7*f8833479SBarry Smith 8*f8833479SBarry Smith We must now have three distinct phases: location, construction, and testing. 9*f8833479SBarry SmithThis is very similar to the current compiler checks. The construction phase is 10*f8833479SBarry Smithoptional, and only necessary when the package has not been previously configured. 11*f8833479SBarry SmithThe phases will necessarily interact, as an installtion must be located before 12*f8833479SBarry Smithtesting, however anothe should be located if the testing fails. 13*f8833479SBarry Smith 14*f8833479SBarry Smith We will give each installation a unique key, which is returned by the location 15*f8833479SBarry Smithmethod. This will allow us to identify working installations, as well as those 16*f8833479SBarry Smiththat failed testing. 17*f8833479SBarry Smith 18*f8833479SBarry Smith There is a wierd role reversal that can happen. If we look for PETSc, but 19*f8833479SBarry Smithcannot find it, it is reasonable to ask to have it automatically downloaded. 20*f8833479SBarry SmithHowever, in this case, rather than using the configure objects from the existing 21*f8833479SBarry SmithPETSc, we contribute objects to the PETSc which will be built. 22*f8833479SBarry Smith 23*f8833479SBarry Smith''' 24*f8833479SBarry Smithfrom __future__ import generators 25*f8833479SBarry Smithimport user 26*f8833479SBarry Smithimport config.base 27*f8833479SBarry Smith 28*f8833479SBarry Smithimport re 29*f8833479SBarry Smithimport os 30*f8833479SBarry Smith 31*f8833479SBarry Smithclass InvalidPETScError(RuntimeError): 32*f8833479SBarry Smith pass 33*f8833479SBarry Smith 34*f8833479SBarry Smithclass Configure(config.base.Configure): 35*f8833479SBarry Smith def __init__(self, framework): 36*f8833479SBarry Smith config.base.Configure.__init__(self, framework) 37*f8833479SBarry Smith self.headerPrefix = '' 38*f8833479SBarry Smith self.substPrefix = '' 39*f8833479SBarry Smith self.location = None 40*f8833479SBarry Smith self.trial = {} 41*f8833479SBarry Smith self.working = {} 42*f8833479SBarry Smith return 43*f8833479SBarry Smith 44*f8833479SBarry Smith def __str__(self): 45*f8833479SBarry Smith if self.found: 46*f8833479SBarry Smith desc = ['PETSc:'] 47*f8833479SBarry Smith desc.append(' Type: '+self.name) 48*f8833479SBarry Smith desc.append(' Version: '+self.version) 49*f8833479SBarry Smith desc.append(' Includes: '+str(self.include)) 50*f8833479SBarry Smith desc.append(' Library: '+str(self.lib)) 51*f8833479SBarry Smith return '\n'.join(desc)+'\n' 52*f8833479SBarry Smith else: 53*f8833479SBarry Smith return '' 54*f8833479SBarry Smith 55*f8833479SBarry Smith def setupHelp(self, help): 56*f8833479SBarry Smith import nargs 57*f8833479SBarry Smith help.addArgument('PETSc', '-with-petsc=<bool>', nargs.ArgBool(None, 1, 'Activate PETSc')) 58*f8833479SBarry Smith # Location options 59*f8833479SBarry Smith help.addArgument('PETSc', '-with-petsc-dir=<root dir>', nargs.ArgDir(None, None, 'Specify the root directory of the PETSc installation')) 60*f8833479SBarry Smith help.addArgument('PETSc', '-with-petsc-arch=<arch>', nargs.Arg(None, None, 'Specify PETSC_ARCH')) 61*f8833479SBarry Smith # Construction options 62*f8833479SBarry Smith help.addArgument('PETSc', '-download-petsc=<no,yes,ifneeded>', nargs.ArgFuzzyBool(None, 0, 'Install PETSc')) 63*f8833479SBarry Smith # Testing options 64*f8833479SBarry Smith help.addArgument('PETSc', '-with-petsc-shared=<bool>', nargs.ArgBool(None, 1, 'Require that the PETSc library be shared')) 65*f8833479SBarry Smith return 66*f8833479SBarry Smith 67*f8833479SBarry Smith def setupPackageDependencies(self, framework): 68*f8833479SBarry Smith import sys 69*f8833479SBarry Smith 70*f8833479SBarry Smith petscConf = None 71*f8833479SBarry Smith for (name, (petscDir, petscArch)) in self.getLocations(): 72*f8833479SBarry Smith petscPythonDir = os.path.join(petscDir, 'python') 73*f8833479SBarry Smith sys.path.append(petscPythonDir) 74*f8833479SBarry Smith confPath = os.path.join(petscDir, petscArch,'conf') 75*f8833479SBarry Smith petscConf = framework.loadFramework(confPath) 76*f8833479SBarry Smith if petscConf: 77*f8833479SBarry Smith self.logPrint('Loaded PETSc-AS configuration ('+name+') from '+confPath) 78*f8833479SBarry Smith self.location = (petscDir, petscArch) 79*f8833479SBarry Smith self.trial[self.location] = name 80*f8833479SBarry Smith break 81*f8833479SBarry Smith else: 82*f8833479SBarry Smith self.logPrint('PETSc-AS has no cached configuration in '+confPath) 83*f8833479SBarry Smith sys.path.reverse() 84*f8833479SBarry Smith sys.path.remove(petscPythonDir) 85*f8833479SBarry Smith sys.path.reverse() 86*f8833479SBarry Smith if not petscConf: 87*f8833479SBarry Smith self.downloadPETSc() 88*f8833479SBarry Smith framework.addPackageDependency(petscConf, confPath) 89*f8833479SBarry Smith return 90*f8833479SBarry Smith 91*f8833479SBarry Smith def setupDependencies(self, framework): 92*f8833479SBarry Smith config.base.Configure.setupDependencies(self, framework) 93*f8833479SBarry Smith self.languages = framework.require('PETSc.utilities.languages', self) 94*f8833479SBarry Smith self.compilers = framework.require('config.compilers', self) 95*f8833479SBarry Smith self.headers = framework.require('config.headers', self) 96*f8833479SBarry Smith self.libraries = framework.require('config.libraries', self) 97*f8833479SBarry Smith self.blaslapack = framework.require('PETSc.packages.BlasLapack', self) 98*f8833479SBarry Smith self.mpi = framework.require('PETSc.packages.MPI', self) 99*f8833479SBarry Smith return 100*f8833479SBarry Smith 101*f8833479SBarry Smith def getPETScArch(self, petscDir): 102*f8833479SBarry Smith '''Return the allowable PETSc architectures for a given root''' 103*f8833479SBarry Smith if 'with-petsc-arch' in self.framework.argDB: 104*f8833479SBarry Smith yield self.framework.argDB['with-petsc-arch'] 105*f8833479SBarry Smith elif 'PETSC_ARCH' in os.environ: 106*f8833479SBarry Smith yield os.environ['PETSC_ARCH'] 107*f8833479SBarry Smith else: 108*f8833479SBarry Smith raise InvalidPETScError('Must set PETSC_ARCH or use --with-petsc-arch') 109*f8833479SBarry Smith return 110*f8833479SBarry Smith 111*f8833479SBarry Smith def getLocations(self): 112*f8833479SBarry Smith '''Return all allowable locations for PETSc''' 113*f8833479SBarry Smith if hasattr(self, '_configured'): 114*f8833479SBarry Smith key =(self.dir, self.arch) 115*f8833479SBarry Smith yield (self.working[key], key) 116*f8833479SBarry Smith raise InvalidPETScError('Configured PETSc is not usable') 117*f8833479SBarry Smith if self.framework.argDB['download-petsc'] == 1: 118*f8833479SBarry Smith yield self.downloadPETSc() 119*f8833479SBarry Smith raise InvalidPETScError('Downloaded PETSc is not usable') 120*f8833479SBarry Smith if 'with-petsc-dir' in self.framework.argDB: 121*f8833479SBarry Smith petscDir = self.framework.argDB['with-petsc-dir'] 122*f8833479SBarry Smith for petscArch in self.getPETScArch(petscDir): 123*f8833479SBarry Smith yield ('User specified installation root', (petscDir, petscArch)) 124*f8833479SBarry Smith raise InvalidPETScError('No working architecitures in '+str(petscDir)) 125*f8833479SBarry Smith elif 'PETSC_DIR' in os.environ: 126*f8833479SBarry Smith petscDir = os.environ['PETSC_DIR'] 127*f8833479SBarry Smith for petscArch in self.getPETScArch(petscDir): 128*f8833479SBarry Smith yield ('User specified installation root', (petscDir, petscArch)) 129*f8833479SBarry Smith raise InvalidPETScError('No working architecitures in '+str(petscDir)) 130*f8833479SBarry Smith else: 131*f8833479SBarry Smith for petscArch in self.getPETScArch(petscDir): 132*f8833479SBarry Smith yield ('Default compiler locations', ('', petscArch)) 133*f8833479SBarry Smith petscDirRE = re.compile(r'(PETSC|pets)c(-.*)?') 134*f8833479SBarry Smith trialDirs = [] 135*f8833479SBarry Smith for packageDir in self.framework.argDB['package-dirs']: 136*f8833479SBarry Smith if os.path.isdir(packageDir): 137*f8833479SBarry Smith for d in os.listdir(packageDir): 138*f8833479SBarry Smith if petscDirRE.match(d): 139*f8833479SBarry Smith trialDirs.append(('Package directory installation root', os.path.join(packageDir, d))) 140*f8833479SBarry Smith usrLocal = os.path.join('/usr', 'local') 141*f8833479SBarry Smith if os.path.isdir(os.path.join('/usr', 'local')): 142*f8833479SBarry Smith trialDirs.append(('Frequent user install location (/usr/local)', usrLocal)) 143*f8833479SBarry Smith for d in os.listdir(usrLocal): 144*f8833479SBarry Smith if petscDirRE.match(d): 145*f8833479SBarry Smith trialDirs.append(('Frequent user install location (/usr/local/'+d+')', os.path.join(usrLocal, d))) 146*f8833479SBarry Smith if 'HOME' in os.environ and os.path.isdir(os.environ['HOME']): 147*f8833479SBarry Smith for d in os.listdir(os.environ['HOME']): 148*f8833479SBarry Smith if petscDirRE.match(d): 149*f8833479SBarry Smith trialDirs.append(('Frequent user install location (~/'+d+')', os.path.join(os.environ['HOME'], d))) 150*f8833479SBarry Smith return 151*f8833479SBarry Smith 152*f8833479SBarry Smith def downloadPETSc(self): 153*f8833479SBarry Smith if self.framework.argDB['download-petsc'] == 0: 154*f8833479SBarry Smith raise RuntimeError('No functioning PETSc located') 155*f8833479SBarry Smith # Download and build PETSc 156*f8833479SBarry Smith # Use only the already configured objects from this run 157*f8833479SBarry Smith raise RuntimeError('Not implemented') 158*f8833479SBarry Smith 159*f8833479SBarry Smith def getDir(self): 160*f8833479SBarry Smith if self.location: 161*f8833479SBarry Smith return self.location[0] 162*f8833479SBarry Smith return None 163*f8833479SBarry Smith dir = property(getDir, doc = 'The PETSc root directory') 164*f8833479SBarry Smith 165*f8833479SBarry Smith def getArch(self): 166*f8833479SBarry Smith if self.location: 167*f8833479SBarry Smith return self.location[1] 168*f8833479SBarry Smith return None 169*f8833479SBarry Smith arch = property(getArch, doc = 'The PETSc architecture') 170*f8833479SBarry Smith 171*f8833479SBarry Smith def getFound(self): 172*f8833479SBarry Smith return self.location and self.location in self.working 173*f8833479SBarry Smith found = property(getFound, doc = 'Did we find a valid PETSc installation') 174*f8833479SBarry Smith 175*f8833479SBarry Smith def getName(self): 176*f8833479SBarry Smith if self.location and self.location in self.working: 177*f8833479SBarry Smith return self.working[self.location][0] 178*f8833479SBarry Smith return None 179*f8833479SBarry Smith name = property(getName, doc = 'The PETSc installation type') 180*f8833479SBarry Smith 181*f8833479SBarry Smith def getInclude(self, useTrial = 0): 182*f8833479SBarry Smith if self.location and self.location in self.working: 183*f8833479SBarry Smith return self.working[self.location][1] 184*f8833479SBarry Smith elif useTrial and self.location and self.location in self.trial: 185*f8833479SBarry Smith return self.trial[self.location][1] 186*f8833479SBarry Smith return None 187*f8833479SBarry Smith include = property(getInclude, doc = 'The PETSc include directories') 188*f8833479SBarry Smith 189*f8833479SBarry Smith def getLib(self, useTrial = 0): 190*f8833479SBarry Smith if self.location and self.location in self.working: 191*f8833479SBarry Smith return self.working[self.location][2] 192*f8833479SBarry Smith elif useTrial and self.location and self.location in self.trial: 193*f8833479SBarry Smith return self.trial[self.location][2] 194*f8833479SBarry Smith return None 195*f8833479SBarry Smith lib = property(getLib, doc = 'The PETSc libraries') 196*f8833479SBarry Smith 197*f8833479SBarry Smith def getVersion(self): 198*f8833479SBarry Smith if self.location and self.location in self.working: 199*f8833479SBarry Smith return self.working[self.location][3] 200*f8833479SBarry Smith return None 201*f8833479SBarry Smith version = property(getVersion, doc = 'The PETSc version') 202*f8833479SBarry Smith 203*f8833479SBarry Smith def getOtherIncludes(self): 204*f8833479SBarry Smith if not hasattr(self, '_otherIncludes'): 205*f8833479SBarry Smith includes = [] 206*f8833479SBarry Smith includes.extend([self.headers.getIncludeArgument(inc) for inc in self.mpi.include]) 207*f8833479SBarry Smith return ' '.join(includes) 208*f8833479SBarry Smith return self._otherIncludes 209*f8833479SBarry Smith def setOtherIncludes(self, otherIncludes): 210*f8833479SBarry Smith self._otherIncludes = otherIncludes 211*f8833479SBarry Smith otherIncludes = property(getOtherIncludes, setOtherIncludes, doc = 'Includes needed to compile PETSc') 212*f8833479SBarry Smith 213*f8833479SBarry Smith def getOtherLibs(self): 214*f8833479SBarry Smith if not hasattr(self, '_otherLibs'): 215*f8833479SBarry Smith libs = self.compilers.flibs[:] 216*f8833479SBarry Smith libs.extend(self.mpi.lib) 217*f8833479SBarry Smith libs.extend(self.blaslapack.lib) 218*f8833479SBarry Smith return libs 219*f8833479SBarry Smith return self._otherLibs 220*f8833479SBarry Smith def setOtherLibs(self, otherLibs): 221*f8833479SBarry Smith self._otherLibs = otherLibs 222*f8833479SBarry Smith otherLibs = property(getOtherLibs, setOtherLibs, doc = 'Libraries needed to link PETSc') 223*f8833479SBarry Smith 224*f8833479SBarry Smith def checkLib(self, libraries): 225*f8833479SBarry Smith '''Check for PETSc creation functions in libraries, which can be a list of libraries or a single library 226*f8833479SBarry Smith - PetscInitialize from libpetsc 227*f8833479SBarry Smith - VecCreate from libpetscvec 228*f8833479SBarry Smith - MatCreate from libpetscmat 229*f8833479SBarry Smith - DADestroy from libpetscdm 230*f8833479SBarry Smith - KSPCreate from libpetscksp 231*f8833479SBarry Smith - SNESCreate from libpetscsnes 232*f8833479SBarry Smith - TSCreate from libpetscts 233*f8833479SBarry Smith ''' 234*f8833479SBarry Smith if not isinstance(libraries, list): libraries = [libraries] 235*f8833479SBarry Smith oldLibs = self.compilers.LIBS 236*f8833479SBarry Smith self.libraries.pushLanguage(self.languages.clanguage) 237*f8833479SBarry Smith found = (self.libraries.check(libraries, 'PetscInitializeNoArguments', otherLibs = self.otherLibs, prototype = 'int PetscInitializeNoArguments(void);', cxxMangle = not self.languages.cSupport) and 238*f8833479SBarry Smith self.libraries.check(libraries, 'VecDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Vec *Vec;int VecDestroy(Vec);', call = 'VecDestroy((Vec) 0)', cxxMangle = not self.languages.cSupport) and 239*f8833479SBarry Smith self.libraries.check(libraries, 'MatDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Mat *Mat;int MatDestroy(Mat);', call = 'MatDestroy((Mat) 0)', cxxMangle = not self.languages.cSupport) and 240*f8833479SBarry Smith self.libraries.check(libraries, 'DADestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_DA *DA;int DADestroy(DA);', call = 'DADestroy((DA) 0)', cxxMangle = not self.languages.cSupport) and 241*f8833479SBarry Smith self.libraries.check(libraries, 'KSPDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_KSP *KSP;int KSPDestroy(KSP);', call = 'KSPDestroy((KSP) 0)', cxxMangle = not self.languages.cSupport) and 242*f8833479SBarry Smith self.libraries.check(libraries, 'SNESDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_SNES *SNES;int SNESDestroy(SNES);', call = 'SNESDestroy((SNES) 0)', cxxMangle = not self.languages.cSupport) and 243*f8833479SBarry Smith self.libraries.check(libraries, 'TSDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_TS *TS;int TSDestroy(TS);', call = 'TSDestroy((TS) 0)', cxxMangle = not self.languages.cSupport)) 244*f8833479SBarry Smith self.libraries.popLanguage() 245*f8833479SBarry Smith self.compilers.LIBS = oldLibs 246*f8833479SBarry Smith return found 247*f8833479SBarry Smith 248*f8833479SBarry Smith def checkInclude(self, includeDir): 249*f8833479SBarry Smith '''Check that petsc.h is present''' 250*f8833479SBarry Smith oldFlags = self.compilers.CPPFLAGS 251*f8833479SBarry Smith self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in includeDir]) 252*f8833479SBarry Smith if self.otherIncludes: 253*f8833479SBarry Smith self.compilers.CPPFLAGS += ' '+self.otherIncludes 254*f8833479SBarry Smith self.pushLanguage(self.languages.clanguage) 255*f8833479SBarry Smith found = self.checkPreprocess('#include <petsc.h>\n') 256*f8833479SBarry Smith self.popLanguage() 257*f8833479SBarry Smith self.compilers.CPPFLAGS = oldFlags 258*f8833479SBarry Smith return found 259*f8833479SBarry Smith 260*f8833479SBarry Smith def checkPETScLink(self, includes, body, cleanup = 1, codeBegin = None, codeEnd = None, shared = None): 261*f8833479SBarry Smith '''Analogous to checkLink(), but the PETSc includes and libraries are automatically provided''' 262*f8833479SBarry Smith success = 0 263*f8833479SBarry Smith oldFlags = self.compilers.CPPFLAGS 264*f8833479SBarry Smith self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in self.getInclude(useTrial = 1)]) 265*f8833479SBarry Smith if self.otherIncludes: 266*f8833479SBarry Smith self.compilers.CPPFLAGS += ' '+self.otherIncludes 267*f8833479SBarry Smith oldLibs = self.compilers.LIBS 268*f8833479SBarry Smith self.compilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.getLib(useTrial = 1)+self.otherLibs])+' '+self.compilers.LIBS 269*f8833479SBarry Smith if self.checkLink(includes, body, cleanup, codeBegin, codeEnd, shared): 270*f8833479SBarry Smith success = 1 271*f8833479SBarry Smith self.compilers.CPPFLAGS = oldFlags 272*f8833479SBarry Smith self.compilers.LIBS = oldLibs 273*f8833479SBarry Smith return success 274*f8833479SBarry Smith 275*f8833479SBarry Smith def checkWorkingLink(self): 276*f8833479SBarry Smith '''Checking that we can link a PETSc executable''' 277*f8833479SBarry Smith self.pushLanguage(self.languages.clanguage) 278*f8833479SBarry Smith if not self.checkPETScLink('#include <petsclog.h>\n', 'PetscLogDouble time;\nPetscErrorCode ierr;\n\nierr = PetscGetTime(&time); CHKERRQ(ierr);\n'): 279*f8833479SBarry Smith self.logPrint('PETSc cannot link, which indicates a problem with the PETSc installation') 280*f8833479SBarry Smith return 0 281*f8833479SBarry Smith self.logPrint('PETSc can link with '+self.languages.clanguage) 282*f8833479SBarry Smith self.popLanguage() 283*f8833479SBarry Smith 284*f8833479SBarry Smith if hasattr(self.compilers, 'CXX') and self.languages.clanguage == 'C': 285*f8833479SBarry Smith self.pushLanguage('C++') 286*f8833479SBarry Smith self.sourceExtension = '.C' 287*f8833479SBarry Smith if not self.checkPETScLink('#define PETSC_USE_EXTERN_CXX\n#include <petsc.h>\n', 'PetscLogDouble time;\nPetscErrorCode ierr;\n\nierr = PetscGetTime(&time); CHKERRQ(ierr);\n'): 288*f8833479SBarry Smith self.logPrint('PETSc cannot link C++ but can link C, which indicates a problem with the PETSc installation') 289*f8833479SBarry Smith self.popLanguage() 290*f8833479SBarry Smith return 0 291*f8833479SBarry Smith self.popLanguage() 292*f8833479SBarry Smith self.logPrint('PETSc can link with C++') 293*f8833479SBarry Smith 294*f8833479SBarry Smith if hasattr(self.compilers, 'FC'): 295*f8833479SBarry Smith self.pushLanguage('FC') 296*f8833479SBarry Smith self.sourceExtension = '.F' 297*f8833479SBarry Smith if not self.checkPETScLink('', ' integer ierr\n real time\n call PetscGetTime(time, ierr)\n'): 298*f8833479SBarry Smith self.logPrint('PETSc cannot link Fortran, but can link C, which indicates a problem with the PETSc installation\nRun with -with-fc=0 if you do not wish to use Fortran') 299*f8833479SBarry Smith self.popLanguage() 300*f8833479SBarry Smith return 0 301*f8833479SBarry Smith self.popLanguage() 302*f8833479SBarry Smith self.logPrint('PETSc can link with Fortran') 303*f8833479SBarry Smith return 1 304*f8833479SBarry Smith 305*f8833479SBarry Smith def checkSharedLibrary(self, libraries): 306*f8833479SBarry Smith '''Check that the libraries for PETSc are shared libraries''' 307*f8833479SBarry Smith if config.setCompilers.Configure.isDarwin(): 308*f8833479SBarry Smith # on Apple if you list the MPI libraries again you will generate multiply defined errors 309*f8833479SBarry Smith # since they are already copied into the PETSc dynamic library. 310*f8833479SBarry Smith self.setOtherLibs([]) 311*f8833479SBarry Smith self.pushLanguage(self.languages.clanguage) 312*f8833479SBarry Smith isShared = self.libraries.checkShared('#include <petsc.h>\n', 'PetscInitialize', 'PetscInitialized', 'PetscFinalize', checkLink = self.checkPETScLink, libraries = libraries, initArgs = '&argc, &argv, 0, 0', boolType = 'PetscTruth', executor = self.mpi.mpiexec) 313*f8833479SBarry Smith self.popLanguage() 314*f8833479SBarry Smith return isShared 315*f8833479SBarry Smith 316*f8833479SBarry Smith def configureVersion(self): 317*f8833479SBarry Smith '''Determine the PETSc version''' 318*f8833479SBarry Smith majorRE = re.compile(r'^#define PETSC_VERSION_MAJOR([\s]+)(?P<versionNum>\d+)[\s]*$'); 319*f8833479SBarry Smith minorRE = re.compile(r'^#define PETSC_VERSION_MINOR([\s]+)(?P<versionNum>\d+)[\s]*$'); 320*f8833479SBarry Smith subminorRE = re.compile(r'^#define PETSC_VERSION_SUBMINOR([\s]+)(?P<versionNum>\d+)[\s]*$'); 321*f8833479SBarry Smith patchRE = re.compile(r'^#define PETSC_VERSION_PATCH([\s]+)(?P<patchNum>\d+)[\s]*$'); 322*f8833479SBarry Smith dateRE = re.compile(r'^#define PETSC_VERSION_DATE([\s]+)"(?P<date>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d)"[\s]*$'); 323*f8833479SBarry Smith input = file(os.path.join(self.dir, 'include', 'petscversion.h')) 324*f8833479SBarry Smith lines = [] 325*f8833479SBarry Smith majorNum = 'Unknown' 326*f8833479SBarry Smith minorNum = 'Unknown' 327*f8833479SBarry Smith subminorNum = 'Unknown' 328*f8833479SBarry Smith patchNum = 'Unknown' 329*f8833479SBarry Smith self.date = 'Unknown' 330*f8833479SBarry Smith for line in input.readlines(): 331*f8833479SBarry Smith m1 = majorRE.match(line) 332*f8833479SBarry Smith m2 = minorRE.match(line) 333*f8833479SBarry Smith m3 = subminorRE.match(line) 334*f8833479SBarry Smith m4 = patchRE.match(line) 335*f8833479SBarry Smith m5 = dateRE.match(line) 336*f8833479SBarry Smith if m1: 337*f8833479SBarry Smith majorNum = int(m1.group('versionNum')) 338*f8833479SBarry Smith elif m2: 339*f8833479SBarry Smith minorNum = int(m2.group('versionNum')) 340*f8833479SBarry Smith elif m3: 341*f8833479SBarry Smith subminorNum = int(m3.group('versionNum')) 342*f8833479SBarry Smith 343*f8833479SBarry Smith if m4: 344*f8833479SBarry Smith patchNum = int(m4.group('patchNum'))+1 345*f8833479SBarry Smith lines.append('#define PETSC_VERSION_PATCH'+m4.group(1)+str(patchNum)+'\n') 346*f8833479SBarry Smith elif m5: 347*f8833479SBarry Smith self.date = time.strftime('%b %d, %Y', time.localtime(time.time())) 348*f8833479SBarry Smith lines.append('#define PETSC_VERSION_DATE'+m5.group(1)+'"'+self.date+'"\n') 349*f8833479SBarry Smith else: 350*f8833479SBarry Smith lines.append(line) 351*f8833479SBarry Smith input.close() 352*f8833479SBarry Smith self.logPrint('Found PETSc version (%s,%s,%s) patch %s on %s' % (majorNum, minorNum, subminorNum, patchNum, self.date)) 353*f8833479SBarry Smith return '%d.%d.%d' % (majorNum, minorNum, subminorNum) 354*f8833479SBarry Smith 355*f8833479SBarry Smith def includeGuesses(self, path = None): 356*f8833479SBarry Smith '''Return all include directories present in path or its ancestors''' 357*f8833479SBarry Smith if not path: 358*f8833479SBarry Smith yield [] 359*f8833479SBarry Smith while path: 360*f8833479SBarry Smith dir = os.path.join(path, 'include') 361*f8833479SBarry Smith if os.path.isdir(dir): 362*f8833479SBarry Smith yield [dir, os.path.join(path, self.arch,'include')] 363*f8833479SBarry Smith if path == '/': 364*f8833479SBarry Smith return 365*f8833479SBarry Smith path = os.path.dirname(path) 366*f8833479SBarry Smith return 367*f8833479SBarry Smith 368*f8833479SBarry Smith def libraryGuesses(self, root = None): 369*f8833479SBarry Smith '''Return standard library name guesses for a given installation root''' 370*f8833479SBarry Smith libs = ['ts', 'snes', 'ksp', 'dm', 'mat', 'vec', ''] 371*f8833479SBarry Smith if root: 372*f8833479SBarry Smith d = os.path.join(root, 'lib', self.arch) 373*f8833479SBarry Smith if not os.path.isdir(d): 374*f8833479SBarry Smith self.logPrint('', 3, 'petsc') 375*f8833479SBarry Smith return 376*f8833479SBarry Smith yield [os.path.join(d, 'libpetsc'+lib+'.a') for lib in libs] 377*f8833479SBarry Smith else: 378*f8833479SBarry Smith yield ['libpetsc'+lib+'.a' for lib in libs] 379*f8833479SBarry Smith return 380*f8833479SBarry Smith 381*f8833479SBarry Smith def configureLibrary(self): 382*f8833479SBarry Smith '''Find a working PETSc 383*f8833479SBarry Smith - Right now, C++ builds are required to use PETSC_USE_EXTERN_CXX''' 384*f8833479SBarry Smith for location, name in self.trial.items(): 385*f8833479SBarry Smith self.framework.logPrintDivider() 386*f8833479SBarry Smith self.framework.logPrint('Checking for a functional PETSc in '+name+', location/origin '+str(location)) 387*f8833479SBarry Smith lib = None 388*f8833479SBarry Smith include = None 389*f8833479SBarry Smith found = 0 390*f8833479SBarry Smith for libraries in self.libraryGuesses(location[0]): 391*f8833479SBarry Smith if self.checkLib(libraries): 392*f8833479SBarry Smith lib = libraries 393*f8833479SBarry Smith for includeDir in self.includeGuesses(location[0]): 394*f8833479SBarry Smith if self.checkInclude(includeDir): 395*f8833479SBarry Smith include = includeDir 396*f8833479SBarry Smith self.trial[location] = (name, include, lib, 'Unknown') 397*f8833479SBarry Smith if self.executeTest(self.checkWorkingLink): 398*f8833479SBarry Smith found = 1 399*f8833479SBarry Smith break 400*f8833479SBarry Smith else: 401*f8833479SBarry Smith self.framework.logPrintDivider(single = 1) 402*f8833479SBarry Smith self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkWorkingLink test') 403*f8833479SBarry Smith else: 404*f8833479SBarry Smith self.framework.logPrintDivider(single = 1) 405*f8833479SBarry Smith self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkInclude test with includeDir: '+str(includeDir)) 406*f8833479SBarry Smith if not found: 407*f8833479SBarry Smith self.framework.logPrintDivider(single = 1) 408*f8833479SBarry Smith self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkIncludes test') 409*f8833479SBarry Smith continue 410*f8833479SBarry Smith else: 411*f8833479SBarry Smith self.framework.logPrintDivider(single = 1) 412*f8833479SBarry Smith self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkLib test with libraries: '+str(libraries)) 413*f8833479SBarry Smith continue 414*f8833479SBarry Smith if self.framework.argDB['with-petsc-shared']: 415*f8833479SBarry Smith if not self.executeTest(self.checkSharedLibrary, [libraries]): 416*f8833479SBarry Smith self.framework.logPrintDivider(single = 1) 417*f8833479SBarry Smith self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkSharedLibrary test with libraries: '+str(libraries)) 418*f8833479SBarry Smith found = 0 419*f8833479SBarry Smith if found: 420*f8833479SBarry Smith break 421*f8833479SBarry Smith if found: 422*f8833479SBarry Smith version = self.executeTest(self.configureVersion) 423*f8833479SBarry Smith self.working[location] = (name, include, lib, version) 424*f8833479SBarry Smith break 425*f8833479SBarry Smith if found: 426*f8833479SBarry Smith self.logPrint('Choose PETSc '+self.version+' in '+self.name) 427*f8833479SBarry Smith else: 428*f8833479SBarry Smith raise RuntimeError('Could not locate any functional PETSc') 429*f8833479SBarry Smith return 430*f8833479SBarry Smith 431*f8833479SBarry Smith def setOutput(self): 432*f8833479SBarry Smith '''Add defines and substitutions 433*f8833479SBarry Smith - HAVE_PETSC is defined if a working PETSc is found 434*f8833479SBarry Smith - PETSC_INCLUDE and PETSC_LIB are command line arguments for the compile and link''' 435*f8833479SBarry Smith if self.found: 436*f8833479SBarry Smith self.addDefine('HAVE_PETSC', 1) 437*f8833479SBarry Smith self.addSubstitution('PETSC_INCLUDE', ' '.join([self.headers.getIncludeArgument(inc) for inc in self.include])) 438*f8833479SBarry Smith self.addSubstitution('PETSC_LIB', ' '.join(map(self.libraries.getLibArgument, self.lib))) 439*f8833479SBarry Smith return 440*f8833479SBarry Smith 441*f8833479SBarry Smith def configure(self): 442*f8833479SBarry Smith self.executeTest(self.configureLibrary) 443*f8833479SBarry Smith self.setOutput() 444*f8833479SBarry Smith return 445*f8833479SBarry Smith 446*f8833479SBarry Smithif __name__ == '__main__': 447*f8833479SBarry Smith import config.framework 448*f8833479SBarry Smith import sys 449*f8833479SBarry Smith framework = config.framework.Framework(sys.argv[1:]) 450*f8833479SBarry Smith framework.setup() 451*f8833479SBarry Smith framework.addChild(Configure(framework)) 452*f8833479SBarry Smith framework.configure() 453*f8833479SBarry Smith framework.dumpSubstitutions() 454