19d310bb7SBarry Smithimport config.base 29d310bb7SBarry Smithimport os 39d310bb7SBarry Smithimport re 49d310bb7SBarry Smith 59d310bb7SBarry Smithclass Configure(config.base.Configure): 69d310bb7SBarry Smith def __init__(self, framework): 79d310bb7SBarry Smith config.base.Configure.__init__(self, framework) 89d310bb7SBarry Smith self.headerPrefix = 'PETSC' 99d310bb7SBarry Smith self.substPrefix = 'PETSC' 109d310bb7SBarry Smith return 119d310bb7SBarry Smith 129d310bb7SBarry Smith def __str1__(self): 139d310bb7SBarry Smith if not hasattr(self, 'arch'): 149d310bb7SBarry Smith return '' 1561897808SPierre Jolivet return ' PETSC_ARCH: '+str(self.arch)+'\n' 169d310bb7SBarry Smith 179d310bb7SBarry Smith def setupHelp(self, help): 189d310bb7SBarry Smith import nargs 199d310bb7SBarry Smith help.addArgument('PETSc', '-PETSC_ARCH=<string>', nargs.Arg(None, None, 'The configuration name')) 209d310bb7SBarry Smith help.addArgument('PETSc', '-with-petsc-arch=<string>',nargs.Arg(None, None, 'The configuration name')) 21dd328ec0SBarry Smith help.addArgument('PETSc', '-force=<bool>', nargs.ArgBool(None, 0, 'Bypass configure hash caching, and run to completion')) 22dd328ec0SBarry Smith return 23dd328ec0SBarry Smith 24dd328ec0SBarry Smith def setupDependencies(self, framework): 25dd328ec0SBarry Smith self.sourceControl = framework.require('config.sourceControl',self) 26dd328ec0SBarry Smith self.petscdir = framework.require('PETSc.options.petscdir', self) 279d310bb7SBarry Smith return 289d310bb7SBarry Smith 291a8e9eaeSSatish Balay def setNativeArchitecture(self): 307b65ca21SBarry Smith '''Forms the arch as GNU's configure would form it''' 3170211a5bSSatish Balay import sys 3270211a5bSSatish Balay arch = 'arch-' + sys.platform.replace('cygwin','mswin') 3370211a5bSSatish Balay # use opt/debug, c/c++ tags.s 3470211a5bSSatish Balay arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x') 3570211a5bSSatish Balay if self.framework.argDB['with-debugging']: 3670211a5bSSatish Balay arch += '-debug' 3770211a5bSSatish Balay else: 3870211a5bSSatish Balay arch += '-opt' 391a8e9eaeSSatish Balay self.nativeArch = arch 401a8e9eaeSSatish Balay return 4170211a5bSSatish Balay 429d310bb7SBarry Smith def configureArchitecture(self): 437b65ca21SBarry Smith '''Checks if PETSC_ARCH is set and sets it if not set''' 44bf3e94a3SBarry Smith # Warn if PETSC_ARCH doesn't match env variable 459d310bb7SBarry Smith if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']: 46d1b3ee28SJacob Faibussowitsch self.logPrintWarning('''\ 47d1b3ee28SJacob FaibussowitschPETSC_ARCH from environment does not match command-line or name of script. Using from command-line or name of script: %s, ignoring environment: %s''' % (str(self.framework.argDB['PETSC_ARCH']), str(os.environ['PETSC_ARCH']))) 4857ea55fdSJed Brown os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH'] 499d310bb7SBarry Smith if 'with-petsc-arch' in self.framework.argDB: 509d310bb7SBarry Smith self.arch = self.framework.argDB['with-petsc-arch'] 5170211a5bSSatish Balay msg = 'option -with-petsc-arch='+str(self.arch) 529d310bb7SBarry Smith elif 'PETSC_ARCH' in self.framework.argDB: 539d310bb7SBarry Smith self.arch = self.framework.argDB['PETSC_ARCH'] 5470211a5bSSatish Balay msg = 'option PETSC_ARCH='+str(self.arch) 5570211a5bSSatish Balay elif 'PETSC_ARCH' in os.environ: 569d310bb7SBarry Smith self.arch = os.environ['PETSC_ARCH'] 5770211a5bSSatish Balay msg = 'environment variable PETSC_ARCH='+str(self.arch) 589d310bb7SBarry Smith else: 591a8e9eaeSSatish Balay self.arch = self.nativeArch 609d310bb7SBarry Smith if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0: 6170211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg) 62002ae2c9SLisandro Dalcin if self.arch.startswith('-'): 6370211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg) 6470211a5bSSatish Balay if self.arch.startswith('.'): 6570211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg) 6670211a5bSSatish Balay if not len(self.arch): 6770211a5bSSatish Balay raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg) 689d310bb7SBarry Smith self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch) 699d310bb7SBarry Smith return 709d310bb7SBarry Smith 71bf3e94a3SBarry Smith def makeDependency(self,hash,hashfile,hashfilepackages): 72bf3e94a3SBarry Smith '''Deletes the current hashfile and saves the hashfile names and its value in framework so that''' 73f8357408SBarry Smith '''framework.Configure can create the file upon success of configure''' 74dd328ec0SBarry Smith import os 75f8357408SBarry Smith if hash: 76f8357408SBarry Smith self.framework.hash = hash 77f8357408SBarry Smith self.framework.hashfile = hashfile 78bf3e94a3SBarry Smith self.logPrint('Setting hashfile: '+hashfile) 79bf3e94a3SBarry Smith if hashfilepackages: self.framework.hashfilepackages = hashfilepackages 80dd328ec0SBarry Smith try: 81bf3e94a3SBarry Smith self.logPrint('Deleting configure hash file: '+hashfile) 82f8357408SBarry Smith os.remove(hashfile) 83bf3e94a3SBarry Smith self.logPrint('Deleted configure hash file: '+hashfile) 84dd328ec0SBarry Smith except: 85f8357408SBarry Smith self.logPrint('Unable to delete configure hash file: '+hashfile) 86bf3e94a3SBarry Smith 87dd328ec0SBarry Smith 88dd328ec0SBarry Smith def checkDependency(self): 89dd328ec0SBarry Smith '''Checks if files in config have changed, the command line options have changed or the PATH has changed''' 90bf3e94a3SBarry Smith ''' By default - checks if configure needs to be run''' 91bf3e94a3SBarry Smith ''' If --arch-hash it manages the same information but it:''' 92bf3e94a3SBarry Smith ''' * computes a short hash for the configuration <hashvalue>''' 93bf3e94a3SBarry Smith ''' * sets self.arch and PETSC_ARCH to arch-<hashvalue>''' 94bf3e94a3SBarry Smith ''' This results in the downloaded packages being installed once to the arch-<hasvalue> directory''' 95bf3e94a3SBarry Smith ''' and a new directory with a different hash is created if the configuration changes.''' 96bf3e94a3SBarry Smith ''' This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)''' 97bf3e94a3SBarry Smith ''' If --package-prefix-hash=directory is provided''' 98bf3e94a3SBarry Smith ''' * computes a short hash for the configuration <hashvalue>''' 99bf3e94a3SBarry Smith ''' * puts the downloaded external packages into location directory/hash''' 100bf3e94a3SBarry Smith ''' This results in the downloaded packages being installed once''' 101bf3e94a3SBarry Smith ''' and a new directory with a different hash is created if the configuration changes.''' 102bf3e94a3SBarry Smith ''' This mode is intended mostly for testing to reduce time of reinstalling external packages''' 103dd328ec0SBarry Smith import os 104dd328ec0SBarry Smith import sys 105dd328ec0SBarry Smith import hashlib 1064dd8803aSSatish Balay import platform 107*e2555bbcSSatish Balay import nargs 1084dd8803aSSatish Balay hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n' 109b60faad8SJed Brown hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 110*e2555bbcSSatish Balay args = dict([(nargs.Arg.parseArgument(arg)[0], arg) for arg in self.framework.clArgs]) 111*e2555bbcSSatish Balay hash += 'args:\n' + '\n'.join(' '+a for a in sorted(args.values())) + '\n' 112a952ef13SBarry Smith chash='' 113dd328ec0SBarry Smith try: 114dd328ec0SBarry Smith for root, dirs, files in os.walk('config'): 115b60faad8SJed Brown if root == 'config': 116b60faad8SJed Brown dirs.remove('examples') 117dd328ec0SBarry Smith for f in files: 118b60faad8SJed Brown if not f.endswith('.py') or f.startswith('.') or f.startswith('#'): 119b60faad8SJed Brown continue 120dd328ec0SBarry Smith fname = os.path.join(root, f) 121b60faad8SJed Brown with open(fname,'rb') as f: 122a952ef13SBarry Smith chash += hashlib.sha256(f.read()).hexdigest() + ' ' + fname + '\n' 123dd328ec0SBarry Smith except: 124b60faad8SJed Brown self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration') 125dd328ec0SBarry Smith return 126a952ef13SBarry Smith hash += '\n'.join(sorted(chash.splitlines())) 127bf3e94a3SBarry Smith hashfilepackages = None 128bf3e94a3SBarry Smith # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change 129bf3e94a3SBarry Smith if 'arch-hash' in self.argDB: 130bf3e94a3SBarry Smith if self.argDB['prefix']: 131bf3e94a3SBarry Smith raise RuntimeError('Cannot provide --prefix and --arch-hash') 132bf3e94a3SBarry Smith if hasattr(self.argDB,'PETSC_ARCH'): 133bf3e94a3SBarry Smith raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash') 134bf3e94a3SBarry Smith if 'package-prefix-hash' in self.argDB: 135bf3e94a3SBarry Smith raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash') 136bf3e94a3SBarry Smith if os.getenv('PETSC_ARCH'): 137bf3e94a3SBarry Smith raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash') 138bf3e94a3SBarry Smith if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB: 139bf3e94a3SBarry Smith import hashlib 140bf3e94a3SBarry Smith m = hashlib.md5() 141a952ef13SBarry Smith m.update(hash.encode('utf-8')) 142bf3e94a3SBarry Smith hprefix = m.hexdigest() 1437f69da20SBarry Smith self.logPrint('Computed hash to be used with --package-prefix-hash option: '+hprefix) 144bf3e94a3SBarry Smith if 'arch-hash' in self.argDB: 145bf3e94a3SBarry Smith self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6] 146bf3e94a3SBarry Smith self.arch = 'arch-'+hprefix[0:6] 147bf3e94a3SBarry Smith else: 148bf3e94a3SBarry Smith if not os.path.isdir(self.argDB['package-prefix-hash']): 149d5b43468SJose E. Roman self.logPrint('Specified package-prefix-hash location %s not found! Attempting to create this dir!' % self.argDB['package-prefix-hash']) 150be5c6b33SBarry Smith try: 15120a7ad26SSatish Balay os.makedirs(self.argDB['package-prefix-hash']) 152be5c6b33SBarry Smith except Exception as e: 15320a7ad26SSatish Balay self.logPrint('Error creating package-prefix-hash directory '+self.argDB['package-prefix-hash']+': '+str(e)) 154d3c8a501SBarry Smith raise RuntimeError('You must have write permission to create prefix directory '+self.argDB['package-prefix-hash']) 15520a7ad26SSatish Balay status = False 15620a7ad26SSatish Balay for idx in range(6,len(hprefix)): 15720a7ad26SSatish Balay hashdirpackages = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:idx]) 15820a7ad26SSatish Balay hashfilepackages = os.path.join(hashdirpackages,'configure-hash') 15920a7ad26SSatish Balay if os.path.isdir(hashdirpackages): 16020a7ad26SSatish Balay if os.path.exists(hashfilepackages): 16120a7ad26SSatish Balay self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild 1627f69da20SBarry Smith self.logPrint('Found existing '+hashfilepackages+' reusing packages built in '+hashdirpackages) 16320a7ad26SSatish Balay status = True 16420a7ad26SSatish Balay break 165bf3e94a3SBarry Smith else: 1667f69da20SBarry Smith self.logPrint('Found existing '+hashdirpackages+' but it is incomplete so trying a longer directory name based on the hash') 1677f69da20SBarry Smith continue # perhaps an incomplete build? use a longer hash 1687f69da20SBarry Smith else: 1697f69da20SBarry Smith if self.argDB['force']: 1707f69da20SBarry Smith # since the previous hash associated with --package-prefix-hash 1717f69da20SBarry Smith # (and hence its directory of built packages) is not available 1727f69da20SBarry Smith # all the packages associated with that hash cannot be reused 1737f69da20SBarry Smith raise RuntimeError('You cannot use --force with --package-prefix-hash=directory; you need to delete the $PETSC_ARCH directory and run configure again') 1747f69da20SBarry Smith self.logPrint('Creating package-prefix-hash subdirectory '+hashdirpackages) 175bf3e94a3SBarry Smith try: 17620a7ad26SSatish Balay os.mkdir(hashdirpackages) 17720a7ad26SSatish Balay except Exception as e: 17820a7ad26SSatish Balay raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory') 17920a7ad26SSatish Balay status = True 18020a7ad26SSatish Balay break 18120a7ad26SSatish Balay if not status: 18220a7ad26SSatish Balay raise RuntimeError('Unable to create package-prefix-hash dir! Suggest cleaning up %s* !' % os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) ) 18320a7ad26SSatish Balay self.argDB['prefix'] = hashdirpackages 184bf3e94a3SBarry Smith 185bf3e94a3SBarry Smith hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 186bf3e94a3SBarry Smith 187dd328ec0SBarry Smith if self.argDB['force']: 188bf3e94a3SBarry Smith self.logPrint('Forcing a new configuration requested by use') 189a952ef13SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 190dd328ec0SBarry Smith return 191dd328ec0SBarry Smith a = '' 192dd328ec0SBarry Smith try: 193f8357408SBarry Smith with open(hashfile, 'r') as f: 194dd328ec0SBarry Smith a = f.read() 195dd328ec0SBarry Smith except: 196bf3e94a3SBarry Smith self.logPrint('No previous hashfile found') 197bf3e94a3SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 198dd328ec0SBarry Smith return 199dd328ec0SBarry Smith if a == hash: 200bf3e94a3SBarry Smith try: 201bf3e94a3SBarry Smith self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 202bf3e94a3SBarry Smith with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 203bf3e94a3SBarry Smith g.write('PETSC_ARCH='+self.arch+'\n') 204bf3e94a3SBarry Smith g.write('PETSC_DIR='+self.petscdir.dir+'\n') 205bf3e94a3SBarry Smith g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 206bf3e94a3SBarry Smith self.logPrint('Saved lib/petsc/conf/petscvariables file') 207bf3e94a3SBarry Smith except: 208bf3e94a3SBarry Smith self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 209f8357408SBarry Smith self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 210dd328ec0SBarry Smith print('Your configure options and state has not changed; no need to run configure') 211dd328ec0SBarry Smith print('However you can force a configure run using the option: --force') 2125b4fc442SVaclav Hapla 213e4d7ee71SJacob Faibussowitsch import logger 2145b4fc442SVaclav Hapla from config.packages.make import getMakeUserPath 215e4d7ee71SJacob Faibussowitsch banner_ends = 'xxx' 216e4d7ee71SJacob Faibussowitsch banner_middle = '=' * (logger.get_global_divider_length() - 2 * len(banner_ends)) 217e4d7ee71SJacob Faibussowitsch banner_line = banner_middle.join((banner_ends, banner_ends)) 218e4d7ee71SJacob Faibussowitsch print(banner_line) 2195b4fc442SVaclav Hapla print(' Build PETSc libraries with:') 2205b4fc442SVaclav Hapla print(' %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch)) 221e4d7ee71SJacob Faibussowitsch print(banner_line) 222dd328ec0SBarry Smith sys.exit() 223ae46fe3bSBarry Smith self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure') 224bf3e94a3SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 225dd328ec0SBarry Smith 2269d310bb7SBarry Smith def configure(self): 2271a8e9eaeSSatish Balay self.executeTest(self.setNativeArchitecture) 2289d310bb7SBarry Smith self.executeTest(self.configureArchitecture) 2299d310bb7SBarry Smith # required by top-level configure.py 2309d310bb7SBarry Smith self.framework.arch = self.arch 231dd328ec0SBarry Smith self.checkDependency() 2329d310bb7SBarry Smith return 233