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