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