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 '' 159d310bb7SBarry Smith desc = ['PETSc:'] 169d310bb7SBarry Smith desc.append(' PETSC_ARCH: '+str(self.arch)) 179d310bb7SBarry Smith return '\n'.join(desc)+'\n' 189d310bb7SBarry Smith 199d310bb7SBarry Smith def setupHelp(self, help): 209d310bb7SBarry Smith import nargs 219d310bb7SBarry Smith help.addArgument('PETSc', '-PETSC_ARCH=<string>', nargs.Arg(None, None, 'The configuration name')) 229d310bb7SBarry Smith help.addArgument('PETSc', '-with-petsc-arch=<string>',nargs.Arg(None, None, 'The configuration name')) 23dd328ec0SBarry Smith help.addArgument('PETSc', '-force=<bool>', nargs.ArgBool(None, 0, 'Bypass configure hash caching, and run to completion')) 24dd328ec0SBarry Smith return 25dd328ec0SBarry Smith 26dd328ec0SBarry Smith def setupDependencies(self, framework): 27dd328ec0SBarry Smith self.sourceControl = framework.require('config.sourceControl',self) 28dd328ec0SBarry Smith self.petscdir = framework.require('PETSc.options.petscdir', self) 299d310bb7SBarry Smith return 309d310bb7SBarry Smith 311a8e9eaeSSatish Balay def setNativeArchitecture(self): 3270211a5bSSatish Balay import sys 3370211a5bSSatish Balay arch = 'arch-' + sys.platform.replace('cygwin','mswin') 3470211a5bSSatish Balay # use opt/debug, c/c++ tags.s 3570211a5bSSatish Balay arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x') 3670211a5bSSatish Balay if self.framework.argDB['with-debugging']: 3770211a5bSSatish Balay arch += '-debug' 3870211a5bSSatish Balay else: 3970211a5bSSatish Balay arch += '-opt' 401a8e9eaeSSatish Balay self.nativeArch = arch 411a8e9eaeSSatish Balay return 4270211a5bSSatish Balay 439d310bb7SBarry Smith def configureArchitecture(self): 449d310bb7SBarry Smith '''Checks PETSC_ARCH and sets if not set''' 45bf3e94a3SBarry Smith # Warn if PETSC_ARCH doesn't match env variable 469d310bb7SBarry Smith if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']: 479d310bb7SBarry Smith self.logPrintBox('''\ 489d310bb7SBarry SmithWarning: PETSC_ARCH from environment does not match command-line or name of script. 499d310bb7SBarry SmithWarning: Using from command-line or name of script: %s, ignoring environment: %s''' % (str(self.framework.argDB['PETSC_ARCH']), str(os.environ['PETSC_ARCH']))) 5057ea55fdSJed Brown os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH'] 519d310bb7SBarry Smith if 'with-petsc-arch' in self.framework.argDB: 529d310bb7SBarry Smith self.arch = self.framework.argDB['with-petsc-arch'] 5370211a5bSSatish Balay msg = 'option -with-petsc-arch='+str(self.arch) 549d310bb7SBarry Smith elif 'PETSC_ARCH' in self.framework.argDB: 559d310bb7SBarry Smith self.arch = self.framework.argDB['PETSC_ARCH'] 5670211a5bSSatish Balay msg = 'option PETSC_ARCH='+str(self.arch) 5770211a5bSSatish Balay elif 'PETSC_ARCH' in os.environ: 589d310bb7SBarry Smith self.arch = os.environ['PETSC_ARCH'] 5970211a5bSSatish Balay msg = 'environment variable PETSC_ARCH='+str(self.arch) 609d310bb7SBarry Smith else: 611a8e9eaeSSatish Balay self.arch = self.nativeArch 629d310bb7SBarry Smith if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0: 6370211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg) 64002ae2c9SLisandro Dalcin if self.arch.startswith('-'): 6570211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg) 6670211a5bSSatish Balay if self.arch.startswith('.'): 6770211a5bSSatish Balay raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg) 6870211a5bSSatish Balay if not len(self.arch): 6970211a5bSSatish Balay raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg) 709d310bb7SBarry Smith self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch) 719d310bb7SBarry Smith return 729d310bb7SBarry Smith 73bf3e94a3SBarry Smith def makeDependency(self,hash,hashfile,hashfilepackages): 74bf3e94a3SBarry Smith '''Deletes the current hashfile and saves the hashfile names and its value in framework so that''' 75f8357408SBarry Smith '''framework.Configure can create the file upon success of configure''' 76dd328ec0SBarry Smith import os 77f8357408SBarry Smith if hash: 78f8357408SBarry Smith self.framework.hash = hash 79f8357408SBarry Smith self.framework.hashfile = hashfile 80bf3e94a3SBarry Smith self.logPrint('Setting hashfile: '+hashfile) 81bf3e94a3SBarry Smith if hashfilepackages: self.framework.hashfilepackages = hashfilepackages 82dd328ec0SBarry Smith try: 83bf3e94a3SBarry Smith self.logPrint('Deleting configure hash file: '+hashfile) 84f8357408SBarry Smith os.remove(hashfile) 85bf3e94a3SBarry Smith self.logPrint('Deleted configure hash file: '+hashfile) 86dd328ec0SBarry Smith except: 87f8357408SBarry Smith self.logPrint('Unable to delete configure hash file: '+hashfile) 88bf3e94a3SBarry Smith 89dd328ec0SBarry Smith 90dd328ec0SBarry Smith def checkDependency(self): 91dd328ec0SBarry Smith '''Checks if files in config have changed, the command line options have changed or the PATH has changed''' 92bf3e94a3SBarry Smith ''' By default - checks if configure needs to be run''' 93bf3e94a3SBarry Smith ''' If --arch-hash it manages the same information but it:''' 94bf3e94a3SBarry Smith ''' * computes a short hash for the configuration <hashvalue>''' 95bf3e94a3SBarry Smith ''' * sets self.arch and PETSC_ARCH to arch-<hashvalue>''' 96bf3e94a3SBarry Smith ''' This results in the downloaded packages being installed once to the arch-<hasvalue> directory''' 97bf3e94a3SBarry Smith ''' and a new directory with a different hash is created if the configuration changes.''' 98bf3e94a3SBarry Smith ''' This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)''' 99bf3e94a3SBarry Smith ''' If --package-prefix-hash=directory is provided''' 100bf3e94a3SBarry Smith ''' * computes a short hash for the configuration <hashvalue>''' 101bf3e94a3SBarry Smith ''' * puts the downloaded external packages into location directory/hash''' 102bf3e94a3SBarry Smith ''' This results in the downloaded packages being installed once''' 103bf3e94a3SBarry Smith ''' and a new directory with a different hash is created if the configuration changes.''' 104bf3e94a3SBarry Smith ''' This mode is intended mostly for testing to reduce time of reinstalling external packages''' 105dd328ec0SBarry Smith import os 106dd328ec0SBarry Smith import sys 107dd328ec0SBarry Smith import hashlib 108*4dd8803aSSatish Balay import platform 109*4dd8803aSSatish Balay if sys.version_info < (3,): 110*4dd8803aSSatish Balay hash = 'Uname: '+platform.uname()[0]+' '+platform.uname()[4]+'\n' 111*4dd8803aSSatish Balay else: 112*4dd8803aSSatish Balay hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n' 113b60faad8SJed Brown hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 114*4dd8803aSSatish Balay args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:]))) 115*4dd8803aSSatish Balay hash += 'args:\n' + '\n'.join(' '+a for a in args) + '\n' 116a952ef13SBarry Smith chash='' 117dd328ec0SBarry Smith try: 118dd328ec0SBarry Smith for root, dirs, files in os.walk('config'): 119b60faad8SJed Brown if root == 'config': 120b60faad8SJed Brown dirs.remove('examples') 121dd328ec0SBarry Smith for f in files: 122b60faad8SJed Brown if not f.endswith('.py') or f.startswith('.') or f.startswith('#'): 123b60faad8SJed Brown continue 124dd328ec0SBarry Smith fname = os.path.join(root, f) 125b60faad8SJed Brown with open(fname,'rb') as f: 126a952ef13SBarry Smith chash += hashlib.sha256(f.read()).hexdigest() + ' ' + fname + '\n' 127dd328ec0SBarry Smith except: 128b60faad8SJed Brown self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration') 129dd328ec0SBarry Smith return 130a952ef13SBarry Smith hash += '\n'.join(sorted(chash.splitlines())) 131bf3e94a3SBarry Smith hashfilepackages = None 132bf3e94a3SBarry Smith # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change 133bf3e94a3SBarry Smith if 'arch-hash' in self.argDB: 134bf3e94a3SBarry Smith if self.argDB['prefix']: 135bf3e94a3SBarry Smith raise RuntimeError('Cannot provide --prefix and --arch-hash') 136bf3e94a3SBarry Smith if hasattr(self.argDB,'PETSC_ARCH'): 137bf3e94a3SBarry Smith raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash') 138bf3e94a3SBarry Smith if 'package-prefix-hash' in self.argDB: 139bf3e94a3SBarry Smith raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash') 140bf3e94a3SBarry Smith if os.getenv('PETSC_ARCH'): 141bf3e94a3SBarry Smith raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash') 142bf3e94a3SBarry Smith if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB: 143bf3e94a3SBarry Smith import hashlib 144bf3e94a3SBarry Smith m = hashlib.md5() 145a952ef13SBarry Smith m.update(hash.encode('utf-8')) 146bf3e94a3SBarry Smith hprefix = m.hexdigest() 147bf3e94a3SBarry Smith if 'arch-hash' in self.argDB: 148bf3e94a3SBarry Smith self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6] 149bf3e94a3SBarry Smith self.arch = 'arch-'+hprefix[0:6] 150bf3e94a3SBarry Smith else: 151bf3e94a3SBarry Smith if not os.path.isdir(self.argDB['package-prefix-hash']): 152bf3e94a3SBarry Smith raise RuntimeError('--package-prefix-hash '+self.argDB['package-prefix-hash']+' directory does not exist\n') 153bf3e94a3SBarry Smith self.argDB['prefix'] = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) 154bf3e94a3SBarry Smith if not os.path.isdir(self.argDB['prefix']): 155bf3e94a3SBarry Smith os.mkdir(self.argDB['prefix']) 156bf3e94a3SBarry Smith hashfilepackages = os.path.join(self.argDB['prefix'],'configure-hash') 157bf3e94a3SBarry Smith else: 158bf3e94a3SBarry Smith try: 159bf3e94a3SBarry Smith with open(os.path.join(self.argDB['prefix'],'configure-hash'), 'r') as f: 160bf3e94a3SBarry Smith a = f.read() 161bf3e94a3SBarry Smith except: 162bf3e94a3SBarry Smith self.logPrint('No previous hashfilepackages found') 163bf3e94a3SBarry Smith a = '' 164bf3e94a3SBarry Smith if a == hash: 165bf3e94a3SBarry Smith self.logPrint('Reusing download packages in '+self.argDB['prefix']) 166bf3e94a3SBarry Smith self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild 167bf3e94a3SBarry Smith 168bf3e94a3SBarry Smith hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 169bf3e94a3SBarry Smith 170dd328ec0SBarry Smith if self.argDB['force']: 171bf3e94a3SBarry Smith self.logPrint('Forcing a new configuration requested by use') 172a952ef13SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 173dd328ec0SBarry Smith return 174dd328ec0SBarry Smith a = '' 175dd328ec0SBarry Smith try: 176f8357408SBarry Smith with open(hashfile, 'r') as f: 177dd328ec0SBarry Smith a = f.read() 178dd328ec0SBarry Smith except: 179bf3e94a3SBarry Smith self.logPrint('No previous hashfile found') 180bf3e94a3SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 181dd328ec0SBarry Smith return 182dd328ec0SBarry Smith if a == hash: 183bf3e94a3SBarry Smith try: 184bf3e94a3SBarry Smith self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 185bf3e94a3SBarry Smith with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 186bf3e94a3SBarry Smith g.write('PETSC_ARCH='+self.arch+'\n') 187bf3e94a3SBarry Smith g.write('PETSC_DIR='+self.petscdir.dir+'\n') 188bf3e94a3SBarry Smith g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 189bf3e94a3SBarry Smith self.logPrint('Saved lib/petsc/conf/petscvariables file') 190bf3e94a3SBarry Smith except: 191bf3e94a3SBarry Smith self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 192f8357408SBarry Smith self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 193dd328ec0SBarry Smith print('Your configure options and state has not changed; no need to run configure') 194dd328ec0SBarry Smith print('However you can force a configure run using the option: --force') 195dd328ec0SBarry Smith sys.exit() 196f8357408SBarry Smith self.logPrint('configure hash file: '+hashfile+' does not match\n'+a+'\n---\n'+hash+'\n need to run configure') 197bf3e94a3SBarry Smith self.makeDependency(hash,hashfile,hashfilepackages) 198dd328ec0SBarry Smith 1999d310bb7SBarry Smith def configure(self): 2001a8e9eaeSSatish Balay self.executeTest(self.setNativeArchitecture) 2019d310bb7SBarry Smith self.executeTest(self.configureArchitecture) 2029d310bb7SBarry Smith # required by top-level configure.py 2039d310bb7SBarry Smith self.framework.arch = self.arch 204dd328ec0SBarry Smith self.checkDependency() 2059d310bb7SBarry Smith return 206