xref: /petsc/config/PETSc/petsc.py (revision f8833479dff2f015b8e0160ff3b6889d7190cdd9)
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