xref: /petsc/config/PETSc/petsc.py (revision a207d08edab748df642306d213e6e891ba48ee92)
1df3bd252SSatish Balay#!/usr/bin/env python3
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.
11*d5b43468SJose E. RomanThe phases will necessarily interact, as an installation must be located before
12*d5b43468SJose E. Romantesting, however another 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
18*d5b43468SJose E. Roman  There is a weird 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 config.base
26f8833479SBarry Smith
27f8833479SBarry Smithimport re
28f8833479SBarry Smithimport os
29f8833479SBarry Smith
30f8833479SBarry Smithclass InvalidPETScError(RuntimeError):
31f8833479SBarry Smith  pass
32f8833479SBarry Smith
33f8833479SBarry Smithclass Configure(config.base.Configure):
34f8833479SBarry Smith  def __init__(self, framework):
35f8833479SBarry Smith    config.base.Configure.__init__(self, framework)
36f8833479SBarry Smith    self.headerPrefix = ''
37f8833479SBarry Smith    self.substPrefix  = ''
38f8833479SBarry Smith    self.location     = None
39f8833479SBarry Smith    self.trial        = {}
40f8833479SBarry Smith    self.working      = {}
41f8833479SBarry Smith    return
42f8833479SBarry Smith
43f8833479SBarry Smith  def __str__(self):
44f8833479SBarry Smith    if self.found:
45f8833479SBarry Smith      desc = ['PETSc:']
46f8833479SBarry Smith      desc.append('  Type: '+self.name)
47f8833479SBarry Smith      desc.append('  Version: '+self.version)
48f8833479SBarry Smith      desc.append('  Includes: '+str(self.include))
49f8833479SBarry Smith      desc.append('  Library: '+str(self.lib))
50f8833479SBarry Smith      return '\n'.join(desc)+'\n'
51f8833479SBarry Smith    else:
52f8833479SBarry Smith      return ''
53f8833479SBarry Smith
54f8833479SBarry Smith  def setupHelp(self, help):
55f8833479SBarry Smith    import nargs
56f8833479SBarry Smith    help.addArgument('PETSc', '-with-petsc=<bool>',                nargs.ArgBool(None, 1, 'Activate PETSc'))
57f8833479SBarry Smith    # Location options
58f8833479SBarry Smith    help.addArgument('PETSc', '-with-petsc-dir=<root dir>',        nargs.ArgDir(None, None, 'Specify the root directory of the PETSc installation'))
59f8833479SBarry Smith    help.addArgument('PETSc', '-with-petsc-arch=<arch>',           nargs.Arg(None, None, 'Specify PETSC_ARCH'))
60f8833479SBarry Smith    # Construction options
61ce0b2093SBarry Smith    help.addArgument('PETSc', '-download-petsc=<bool>',          nargs.ArgBool(None, 0, 'Install PETSc'))
62f8833479SBarry Smith    # Testing options
63f8833479SBarry Smith    help.addArgument('PETSc', '-with-petsc-shared=<bool>',         nargs.ArgBool(None, 1, 'Require that the PETSc library be shared'))
64f8833479SBarry Smith    return
65f8833479SBarry Smith
66f8833479SBarry Smith  def setupPackageDependencies(self, framework):
67f8833479SBarry Smith    import sys
68f8833479SBarry Smith
69f8833479SBarry Smith    petscConf = None
70f8833479SBarry Smith    for (name, (petscDir, petscArch)) in self.getLocations():
719275508cSBarry Smith      petscPythonDir = os.path.join(petscDir, 'config')
72f8833479SBarry Smith      sys.path.append(petscPythonDir)
73af0996ceSBarry Smith      confPath = os.path.join(petscDir, petscArch,'lib','petsc','conf')
74f8833479SBarry Smith      petscConf = framework.loadFramework(confPath)
75f8833479SBarry Smith      if petscConf:
76f8833479SBarry Smith        self.logPrint('Loaded PETSc-AS configuration ('+name+') from '+confPath)
77f8833479SBarry Smith        self.location = (petscDir, petscArch)
78f8833479SBarry Smith        self.trial[self.location] = name
79f8833479SBarry Smith        break
80f8833479SBarry Smith      else:
81f8833479SBarry Smith        self.logPrint('PETSc-AS has no cached configuration in '+confPath)
82f8833479SBarry Smith        sys.path.reverse()
83f8833479SBarry Smith        sys.path.remove(petscPythonDir)
84f8833479SBarry Smith        sys.path.reverse()
85f8833479SBarry Smith    if not petscConf:
86f8833479SBarry Smith      self.downloadPETSc()
87f8833479SBarry Smith    framework.addPackageDependency(petscConf, confPath)
88f8833479SBarry Smith    return
89f8833479SBarry Smith
90f8833479SBarry Smith  def setupDependencies(self, framework):
91f8833479SBarry Smith    config.base.Configure.setupDependencies(self, framework)
929d310bb7SBarry Smith    self.languages  = framework.require('PETSc.options.languages', self)
93f8833479SBarry Smith    self.compilers  = framework.require('config.compilers', self)
94f8833479SBarry Smith    self.headers    = framework.require('config.headers', self)
95f8833479SBarry Smith    self.libraries  = framework.require('config.libraries', self)
9606e08bc7SBarry Smith    self.blaslapack = framework.require('config.packages.BlasLapack', self)
9706e08bc7SBarry Smith    self.mpi        = framework.require('config.packages.MPI', self)
98f8833479SBarry Smith    return
99f8833479SBarry Smith
100f8833479SBarry Smith  def getPETScArch(self, petscDir):
101f8833479SBarry Smith    '''Return the allowable PETSc architectures for a given root'''
102f8833479SBarry Smith    if 'with-petsc-arch' in self.framework.argDB:
103f8833479SBarry Smith      yield self.framework.argDB['with-petsc-arch']
104f8833479SBarry Smith    elif 'PETSC_ARCH' in os.environ:
105f8833479SBarry Smith      yield os.environ['PETSC_ARCH']
106f8833479SBarry Smith    else:
107f8833479SBarry Smith      raise InvalidPETScError('Must set PETSC_ARCH or use --with-petsc-arch')
108f8833479SBarry Smith    return
109f8833479SBarry Smith
110f8833479SBarry Smith  def getLocations(self):
111f8833479SBarry Smith    '''Return all allowable locations for PETSc'''
112f8833479SBarry Smith    if hasattr(self, '_configured'):
113f8833479SBarry Smith      key =(self.dir, self.arch)
114f8833479SBarry Smith      yield (self.working[key], key)
115f8833479SBarry Smith      raise InvalidPETScError('Configured PETSc is not usable')
116f8833479SBarry Smith    if self.framework.argDB['download-petsc'] == 1:
117f8833479SBarry Smith      yield self.downloadPETSc()
118f8833479SBarry Smith      raise InvalidPETScError('Downloaded PETSc is not usable')
119f8833479SBarry Smith    if 'with-petsc-dir' in self.framework.argDB:
120f8833479SBarry Smith      petscDir = self.framework.argDB['with-petsc-dir']
121f8833479SBarry Smith      for petscArch in self.getPETScArch(petscDir):
122f8833479SBarry Smith        yield ('User specified installation root', (petscDir, petscArch))
123f8833479SBarry Smith      raise InvalidPETScError('No working architecitures in '+str(petscDir))
124f8833479SBarry Smith    elif 'PETSC_DIR' in os.environ:
125f8833479SBarry Smith      petscDir = os.environ['PETSC_DIR']
126f8833479SBarry Smith      for petscArch in self.getPETScArch(petscDir):
127f8833479SBarry Smith        yield ('User specified installation root', (petscDir, petscArch))
128f8833479SBarry Smith      raise InvalidPETScError('No working architecitures in '+str(petscDir))
129f8833479SBarry Smith    else:
130f8833479SBarry Smith      for petscArch in self.getPETScArch(petscDir):
131f8833479SBarry Smith        yield ('Default compiler locations', ('', petscArch))
132f8833479SBarry Smith      petscDirRE = re.compile(r'(PETSC|pets)c(-.*)?')
133f8833479SBarry Smith      trialDirs = []
1340aa1f76dSSatish Balay      for packageDir in self.framework.argDB['with-packages-search-path']:
135f8833479SBarry Smith        if os.path.isdir(packageDir):
136f8833479SBarry Smith          for d in os.listdir(packageDir):
137f8833479SBarry Smith            if petscDirRE.match(d):
138f8833479SBarry Smith              trialDirs.append(('Package directory installation root', os.path.join(packageDir, d)))
139f8833479SBarry Smith      usrLocal = os.path.join('/usr', 'local')
140f8833479SBarry Smith      if os.path.isdir(os.path.join('/usr', 'local')):
141f8833479SBarry Smith        trialDirs.append(('Frequent user install location (/usr/local)', usrLocal))
142f8833479SBarry Smith        for d in os.listdir(usrLocal):
143f8833479SBarry Smith          if petscDirRE.match(d):
144f8833479SBarry Smith            trialDirs.append(('Frequent user install location (/usr/local/'+d+')', os.path.join(usrLocal, d)))
145f8833479SBarry Smith      if 'HOME' in os.environ and os.path.isdir(os.environ['HOME']):
146f8833479SBarry Smith        for d in os.listdir(os.environ['HOME']):
147f8833479SBarry Smith          if petscDirRE.match(d):
148f8833479SBarry Smith            trialDirs.append(('Frequent user install location (~/'+d+')', os.path.join(os.environ['HOME'], d)))
149f8833479SBarry Smith    return
150f8833479SBarry Smith
151f8833479SBarry Smith  def downloadPETSc(self):
152f8833479SBarry Smith    if self.framework.argDB['download-petsc'] == 0:
153f8833479SBarry Smith      raise RuntimeError('No functioning PETSc located')
154f8833479SBarry Smith    # Download and build PETSc
155f8833479SBarry Smith    #   Use only the already configured objects from this run
156f8833479SBarry Smith    raise RuntimeError('Not implemented')
157f8833479SBarry Smith
158f8833479SBarry Smith  def getDir(self):
159f8833479SBarry Smith    if self.location:
160f8833479SBarry Smith      return self.location[0]
161f8833479SBarry Smith    return None
162f8833479SBarry Smith  dir = property(getDir, doc = 'The PETSc root directory')
163f8833479SBarry Smith
164f8833479SBarry Smith  def getArch(self):
165f8833479SBarry Smith    if self.location:
166f8833479SBarry Smith      return self.location[1]
167f8833479SBarry Smith    return None
168f8833479SBarry Smith  arch = property(getArch, doc = 'The PETSc architecture')
169f8833479SBarry Smith
170f8833479SBarry Smith  def getFound(self):
171f8833479SBarry Smith    return self.location and self.location in self.working
172f8833479SBarry Smith  found = property(getFound, doc = 'Did we find a valid PETSc installation')
173f8833479SBarry Smith
174f8833479SBarry Smith  def getName(self):
175f8833479SBarry Smith    if self.location and self.location in self.working:
176f8833479SBarry Smith      return self.working[self.location][0]
177f8833479SBarry Smith    return None
178f8833479SBarry Smith  name = property(getName, doc = 'The PETSc installation type')
179f8833479SBarry Smith
180f8833479SBarry Smith  def getInclude(self, useTrial = 0):
181f8833479SBarry Smith    if self.location and self.location in self.working:
182f8833479SBarry Smith      return self.working[self.location][1]
183f8833479SBarry Smith    elif useTrial and self.location and self.location in self.trial:
184f8833479SBarry Smith      return self.trial[self.location][1]
185f8833479SBarry Smith    return None
186f8833479SBarry Smith  include = property(getInclude, doc = 'The PETSc include directories')
187f8833479SBarry Smith
188f8833479SBarry Smith  def getLib(self, useTrial = 0):
189f8833479SBarry Smith    if self.location and self.location in self.working:
190f8833479SBarry Smith      return self.working[self.location][2]
191f8833479SBarry Smith    elif useTrial and self.location and self.location in self.trial:
192f8833479SBarry Smith      return self.trial[self.location][2]
193f8833479SBarry Smith    return None
194f8833479SBarry Smith  lib = property(getLib, doc = 'The PETSc libraries')
195f8833479SBarry Smith
196f8833479SBarry Smith  def getVersion(self):
197f8833479SBarry Smith    if self.location and self.location in self.working:
198f8833479SBarry Smith      return self.working[self.location][3]
199f8833479SBarry Smith    return None
200f8833479SBarry Smith  version = property(getVersion, doc = 'The PETSc version')
201f8833479SBarry Smith
202f8833479SBarry Smith  def getOtherIncludes(self):
203f8833479SBarry Smith    if not hasattr(self, '_otherIncludes'):
204f8833479SBarry Smith      includes = []
205f8833479SBarry Smith      includes.extend([self.headers.getIncludeArgument(inc) for inc in self.mpi.include])
206f8833479SBarry Smith      return ' '.join(includes)
207f8833479SBarry Smith    return self._otherIncludes
208f8833479SBarry Smith  def setOtherIncludes(self, otherIncludes):
209f8833479SBarry Smith    self._otherIncludes = otherIncludes
210f8833479SBarry Smith  otherIncludes = property(getOtherIncludes, setOtherIncludes, doc = 'Includes needed to compile PETSc')
211f8833479SBarry Smith
212f8833479SBarry Smith  def getOtherLibs(self):
213f8833479SBarry Smith    if not hasattr(self, '_otherLibs'):
214f8833479SBarry Smith      libs = self.compilers.flibs[:]
215f8833479SBarry Smith      libs.extend(self.mpi.lib)
216f8833479SBarry Smith      libs.extend(self.blaslapack.lib)
217f8833479SBarry Smith      return libs
218f8833479SBarry Smith    return self._otherLibs
219f8833479SBarry Smith  def setOtherLibs(self, otherLibs):
220f8833479SBarry Smith    self._otherLibs = otherLibs
221f8833479SBarry Smith  otherLibs = property(getOtherLibs, setOtherLibs, doc = 'Libraries needed to link PETSc')
222f8833479SBarry Smith
223f8833479SBarry Smith  def checkLib(self, libraries):
224f8833479SBarry Smith    '''Check for PETSc creation functions in libraries, which can be a list of libraries or a single library
225f8833479SBarry Smith       - PetscInitialize from libpetsc
226f8833479SBarry Smith       - VecCreate from libpetscvec
227f8833479SBarry Smith       - MatCreate from libpetscmat
2289a42bb27SBarry Smith       - DMDestroy from libpetscdm
229f8833479SBarry Smith       - KSPCreate from libpetscksp
230f8833479SBarry Smith       - SNESCreate from libpetscsnes
231f8833479SBarry Smith       - TSCreate from libpetscts
232f8833479SBarry Smith       '''
233f8833479SBarry Smith    if not isinstance(libraries, list): libraries = [libraries]
234f8833479SBarry Smith    oldLibs = self.compilers.LIBS
235f8833479SBarry Smith    self.libraries.pushLanguage(self.languages.clanguage)
2362c280183SJed Brown    found   = (self.libraries.check(libraries, 'PetscInitializeNoArguments', otherLibs = self.otherLibs, prototype = 'int PetscInitializeNoArguments(void);') and
2372c280183SJed Brown               self.libraries.check(libraries, 'VecDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Vec *Vec;int VecDestroy(Vec*);', call = 'VecDestroy((Vec*) 0)') and
2382c280183SJed Brown               self.libraries.check(libraries, 'MatDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Mat *Mat;int MatDestroy(Mat*);', call = 'MatDestroy((Mat*) 0)') and
2392c280183SJed Brown               self.libraries.check(libraries, 'DMDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_DM *DA;int DMDestroy(DA*);', call = 'DMDestroy((DA*) 0)') and
2402c280183SJed Brown               self.libraries.check(libraries, 'KSPDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_KSP *KSP;int KSPDestroy(KSP*);', call = 'KSPDestroy((KSP*) 0)') and
2412c280183SJed Brown               self.libraries.check(libraries, 'SNESDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_SNES *SNES;int SNESDestroy(SNES*);', call = 'SNESDestroy((SNES*) 0)') and
2422c280183SJed Brown               self.libraries.check(libraries, 'TSDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_TS *TS;int TSDestroy(TS*);', call = 'TSDestroy((TS*) 0)'))
243f8833479SBarry Smith    self.libraries.popLanguage()
244f8833479SBarry Smith    self.compilers.LIBS = oldLibs
245f8833479SBarry Smith    return found
246f8833479SBarry Smith
247f8833479SBarry Smith  def checkInclude(self, includeDir):
248d382aafbSBarry Smith    '''Check that petscsys.h is present'''
249f8833479SBarry Smith    oldFlags = self.compilers.CPPFLAGS
250f8833479SBarry Smith    self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in includeDir])
251f8833479SBarry Smith    if self.otherIncludes:
252f8833479SBarry Smith      self.compilers.CPPFLAGS += ' '+self.otherIncludes
253f8833479SBarry Smith    self.pushLanguage(self.languages.clanguage)
254d382aafbSBarry Smith    found = self.checkPreprocess('#include <petscsys.h>\n')
255f8833479SBarry Smith    self.popLanguage()
256f8833479SBarry Smith    self.compilers.CPPFLAGS = oldFlags
257f8833479SBarry Smith    return found
258f8833479SBarry Smith
259f8833479SBarry Smith  def checkPETScLink(self, includes, body, cleanup = 1, codeBegin = None, codeEnd = None, shared = None):
260f8833479SBarry Smith    '''Analogous to checkLink(), but the PETSc includes and libraries are automatically provided'''
261f8833479SBarry Smith    success  = 0
262f8833479SBarry Smith    oldFlags = self.compilers.CPPFLAGS
263f8833479SBarry Smith    self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in self.getInclude(useTrial = 1)])
264f8833479SBarry Smith    if self.otherIncludes:
265f8833479SBarry Smith      self.compilers.CPPFLAGS += ' '+self.otherIncludes
266f8833479SBarry Smith    oldLibs  = self.compilers.LIBS
267f8833479SBarry Smith    self.compilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.getLib(useTrial = 1)+self.otherLibs])+' '+self.compilers.LIBS
268f8833479SBarry Smith    if self.checkLink(includes, body, cleanup, codeBegin, codeEnd, shared):
269f8833479SBarry Smith      success = 1
270f8833479SBarry Smith    self.compilers.CPPFLAGS = oldFlags
271f8833479SBarry Smith    self.compilers.LIBS     = oldLibs
272f8833479SBarry Smith    return success
273f8833479SBarry Smith
274f8833479SBarry Smith  def checkWorkingLink(self):
275f8833479SBarry Smith    '''Checking that we can link a PETSc executable'''
276f8833479SBarry Smith    self.pushLanguage(self.languages.clanguage)
2779566063dSJacob Faibussowitsch    if not self.checkPETScLink('#include <petsctime.h>\n', 'PetscLogDouble time;\n\nPetscCall(PetscTime(&time));\n'):
278f8833479SBarry Smith      self.logPrint('PETSc cannot link, which indicates a problem with the PETSc installation')
279f8833479SBarry Smith      return 0
280f8833479SBarry Smith    self.logPrint('PETSc can link with '+self.languages.clanguage)
281f8833479SBarry Smith    self.popLanguage()
282f8833479SBarry Smith
283f8833479SBarry Smith    if hasattr(self.compilers, 'CXX') and self.languages.clanguage == 'C':
284f8833479SBarry Smith      self.pushLanguage('C++')
285f8833479SBarry Smith      self.sourceExtension = '.C'
2869566063dSJacob Faibussowitsch      if not self.checkPETScLink('#include <petsctime.h>\n', 'PetscLogDouble time;\n\nPetscCall(PetscTime(&time));\n'):
287f8833479SBarry Smith        self.logPrint('PETSc cannot link C++ but can link C, which indicates a problem with the PETSc installation')
288f8833479SBarry Smith        self.popLanguage()
289f8833479SBarry Smith        return 0
290f8833479SBarry Smith      self.popLanguage()
291f8833479SBarry Smith      self.logPrint('PETSc can link with C++')
292f8833479SBarry Smith
293f8833479SBarry Smith    if hasattr(self.compilers, 'FC'):
294f8833479SBarry Smith      self.pushLanguage('FC')
295f8833479SBarry Smith      self.sourceExtension = '.F'
2968563dfccSBarry Smith      if not self.checkPETScLink('', '          integer ierr\n          real time\n          call PetscTime(time, ierr)\n'):
297f8833479SBarry 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')
298f8833479SBarry Smith        self.popLanguage()
299f8833479SBarry Smith        return 0
300f8833479SBarry Smith      self.popLanguage()
301f8833479SBarry Smith      self.logPrint('PETSc can link with Fortran')
302f8833479SBarry Smith    return 1
303f8833479SBarry Smith
304f8833479SBarry Smith  def checkSharedLibrary(self, libraries):
305f8833479SBarry Smith    '''Check that the libraries for PETSc are shared libraries'''
3067fca349cSMatthew G. Knepley    if config.setCompilers.Configure.isDarwin(self.log):
307f8833479SBarry Smith      # on Apple if you list the MPI libraries again you will generate multiply defined errors
308f8833479SBarry Smith      # since they are already copied into the PETSc dynamic library.
309f8833479SBarry Smith      self.setOtherLibs([])
310f8833479SBarry Smith    self.pushLanguage(self.languages.clanguage)
311ace3abfcSBarry 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)
312f8833479SBarry Smith    self.popLanguage()
313f8833479SBarry Smith    return isShared
314f8833479SBarry Smith
315f8833479SBarry Smith  def configureVersion(self):
316f8833479SBarry Smith    '''Determine the PETSc version'''
317f8833479SBarry Smith    majorRE    = re.compile(r'^#define PETSC_VERSION_MAJOR([\s]+)(?P<versionNum>\d+)[\s]*$');
318f8833479SBarry Smith    minorRE    = re.compile(r'^#define PETSC_VERSION_MINOR([\s]+)(?P<versionNum>\d+)[\s]*$');
319f8833479SBarry Smith    subminorRE = re.compile(r'^#define PETSC_VERSION_SUBMINOR([\s]+)(?P<versionNum>\d+)[\s]*$');
320f8833479SBarry 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]*$');
321c6ef1b5bSJed Brown    input   = open(os.path.join(self.dir, 'include', 'petscversion.h'))
322f8833479SBarry Smith    lines   = []
323f8833479SBarry Smith    majorNum = 'Unknown'
324f8833479SBarry Smith    minorNum = 'Unknown'
325f8833479SBarry Smith    subminorNum = 'Unknown'
326f8833479SBarry Smith    self.date = 'Unknown'
327f8833479SBarry Smith    for line in input.readlines():
328f8833479SBarry Smith      m1 = majorRE.match(line)
329f8833479SBarry Smith      m2 = minorRE.match(line)
330f8833479SBarry Smith      m3 = subminorRE.match(line)
331f8833479SBarry Smith      m5 = dateRE.match(line)
332f8833479SBarry Smith      if m1:
333f8833479SBarry Smith        majorNum = int(m1.group('versionNum'))
334f8833479SBarry Smith      elif m2:
335f8833479SBarry Smith        minorNum = int(m2.group('versionNum'))
336f8833479SBarry Smith      elif m3:
337f8833479SBarry Smith        subminorNum = int(m3.group('versionNum'))
338f8833479SBarry Smith
33966d79e26SBarry Smith      if m5:
340f8833479SBarry Smith        self.date = time.strftime('%b %d, %Y', time.localtime(time.time()))
341f8833479SBarry Smith        lines.append('#define PETSC_VERSION_DATE'+m5.group(1)+'"'+self.date+'"\n')
342f8833479SBarry Smith      else:
343f8833479SBarry Smith        lines.append(line)
344f8833479SBarry Smith    input.close()
34566d79e26SBarry Smith    self.logPrint('Found PETSc version (%s,%s,%s) on %s' % (majorNum, minorNum, subminorNum, self.date))
346f8833479SBarry Smith    return '%d.%d.%d' % (majorNum, minorNum, subminorNum)
347f8833479SBarry Smith
348f8833479SBarry Smith  def includeGuesses(self, path = None):
349f8833479SBarry Smith    '''Return all include directories present in path or its ancestors'''
350f8833479SBarry Smith    if not path:
351f8833479SBarry Smith      yield []
352f8833479SBarry Smith    while path:
353f8833479SBarry Smith      dir = os.path.join(path, 'include')
354f8833479SBarry Smith      if os.path.isdir(dir):
355f8833479SBarry Smith        yield [dir, os.path.join(path, self.arch,'include')]
356f8833479SBarry Smith      if path == '/':
357f8833479SBarry Smith        return
358f8833479SBarry Smith      path = os.path.dirname(path)
359f8833479SBarry Smith    return
360f8833479SBarry Smith
361f8833479SBarry Smith  def libraryGuesses(self, root = None):
362f8833479SBarry Smith    '''Return standard library name guesses for a given installation root'''
363f8833479SBarry Smith    libs = ['ts', 'snes', 'ksp', 'dm', 'mat', 'vec', '']
364f8833479SBarry Smith    if root:
365f8833479SBarry Smith      d = os.path.join(root, 'lib', self.arch)
366f8833479SBarry Smith      if not os.path.isdir(d):
367f8833479SBarry Smith        self.logPrint('', 3, 'petsc')
368f8833479SBarry Smith        return
369f8833479SBarry Smith      yield [os.path.join(d, 'libpetsc'+lib+'.a') for lib in libs]
370f8833479SBarry Smith    else:
371f8833479SBarry Smith      yield ['libpetsc'+lib+'.a' for lib in libs]
372f8833479SBarry Smith    return
373f8833479SBarry Smith
374f8833479SBarry Smith  def configureLibrary(self):
3752c280183SJed Brown    '''Find a working PETSc'''
376f8833479SBarry Smith    for location, name in self.trial.items():
377f8833479SBarry Smith      self.framework.logPrintDivider()
378f8833479SBarry Smith      self.framework.logPrint('Checking for a functional PETSc in '+name+', location/origin '+str(location))
379f8833479SBarry Smith      lib     = None
380f8833479SBarry Smith      include = None
381f8833479SBarry Smith      found   = 0
382f8833479SBarry Smith      for libraries in self.libraryGuesses(location[0]):
383f8833479SBarry Smith        if self.checkLib(libraries):
384f8833479SBarry Smith          lib = libraries
385f8833479SBarry Smith          for includeDir in self.includeGuesses(location[0]):
386f8833479SBarry Smith            if self.checkInclude(includeDir):
387f8833479SBarry Smith              include = includeDir
388f8833479SBarry Smith              self.trial[location] = (name, include, lib, 'Unknown')
389f8833479SBarry Smith              if self.executeTest(self.checkWorkingLink):
390f8833479SBarry Smith                found = 1
391f8833479SBarry Smith                break
392f8833479SBarry Smith              else:
393f8833479SBarry Smith                self.framework.logPrintDivider(single = 1)
394f8833479SBarry Smith                self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkWorkingLink test')
395f8833479SBarry Smith            else:
396f8833479SBarry Smith              self.framework.logPrintDivider(single = 1)
397f8833479SBarry Smith              self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkInclude test with includeDir: '+str(includeDir))
398f8833479SBarry Smith          if not found:
399f8833479SBarry Smith            self.framework.logPrintDivider(single = 1)
400f8833479SBarry Smith            self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkIncludes test')
401f8833479SBarry Smith            continue
402f8833479SBarry Smith        else:
403f8833479SBarry Smith          self.framework.logPrintDivider(single = 1)
404f8833479SBarry Smith          self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkLib test with libraries: '+str(libraries))
405f8833479SBarry Smith          continue
406f8833479SBarry Smith        if self.framework.argDB['with-petsc-shared']:
407f8833479SBarry Smith          if not self.executeTest(self.checkSharedLibrary, [libraries]):
408f8833479SBarry Smith            self.framework.logPrintDivider(single = 1)
409f8833479SBarry Smith            self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkSharedLibrary test with libraries: '+str(libraries))
410f8833479SBarry Smith            found = 0
411f8833479SBarry Smith        if found:
412f8833479SBarry Smith          break
413f8833479SBarry Smith      if found:
414f8833479SBarry Smith        version = self.executeTest(self.configureVersion)
415f8833479SBarry Smith        self.working[location] = (name, include, lib, version)
416f8833479SBarry Smith        break
417f8833479SBarry Smith    if found:
418f8833479SBarry Smith      self.logPrint('Choose PETSc '+self.version+' in '+self.name)
419f8833479SBarry Smith    else:
420f8833479SBarry Smith      raise RuntimeError('Could not locate any functional PETSc')
421f8833479SBarry Smith    return
422f8833479SBarry Smith
423f8833479SBarry Smith  def setOutput(self):
424f8833479SBarry Smith    '''Add defines and substitutions
425f8833479SBarry Smith       - HAVE_PETSC is defined if a working PETSc is found
426f8833479SBarry Smith       - PETSC_INCLUDE and PETSC_LIB are command line arguments for the compile and link'''
427f8833479SBarry Smith    if self.found:
428f8833479SBarry Smith      self.addDefine('HAVE_PETSC', 1)
429f8833479SBarry Smith      self.addSubstitution('PETSC_INCLUDE', ' '.join([self.headers.getIncludeArgument(inc) for inc in self.include]))
430f8833479SBarry Smith      self.addSubstitution('PETSC_LIB', ' '.join(map(self.libraries.getLibArgument, self.lib)))
431f8833479SBarry Smith    return
432f8833479SBarry Smith
433f8833479SBarry Smith  def configure(self):
434f8833479SBarry Smith    self.executeTest(self.configureLibrary)
435f8833479SBarry Smith    self.setOutput()
436f8833479SBarry Smith    return
437f8833479SBarry Smith
438f8833479SBarry Smithif __name__ == '__main__':
439f8833479SBarry Smith  import config.framework
440f8833479SBarry Smith  import sys
441f8833479SBarry Smith  framework = config.framework.Framework(sys.argv[1:])
442f8833479SBarry Smith  framework.setup()
443f8833479SBarry Smith  framework.addChild(Configure(framework))
444f8833479SBarry Smith  framework.configure()
445f8833479SBarry Smith  framework.dumpSubstitutions()
446