1import config.base 2import os 3import re 4 5class Configure(config.base.Configure): 6 def __init__(self, framework): 7 config.base.Configure.__init__(self, framework) 8 self.headerPrefix = 'PETSC' 9 self.substPrefix = 'PETSC' 10 return 11 12 def __str1__(self): 13 if not hasattr(self, 'arch'): 14 return '' 15 desc = ['PETSc:'] 16 desc.append(' PETSC_ARCH: '+str(self.arch)) 17 return '\n'.join(desc)+'\n' 18 19 def setupHelp(self, help): 20 import nargs 21 help.addArgument('PETSc', '-PETSC_ARCH=<string>', nargs.Arg(None, None, 'The configuration name')) 22 help.addArgument('PETSc', '-with-petsc-arch=<string>',nargs.Arg(None, None, 'The configuration name')) 23 help.addArgument('PETSc', '-force=<bool>', nargs.ArgBool(None, 0, 'Bypass configure hash caching, and run to completion')) 24 return 25 26 def setupDependencies(self, framework): 27 self.sourceControl = framework.require('config.sourceControl',self) 28 self.petscdir = framework.require('PETSc.options.petscdir', self) 29 return 30 31 def setNativeArchitecture(self): 32 import sys 33 arch = 'arch-' + sys.platform.replace('cygwin','mswin') 34 # use opt/debug, c/c++ tags.s 35 arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x') 36 if self.framework.argDB['with-debugging']: 37 arch += '-debug' 38 else: 39 arch += '-opt' 40 self.nativeArch = arch 41 return 42 43 def configureArchitecture(self): 44 '''Checks PETSC_ARCH and sets if not set''' 45 # Warn if PETSC_ARCH doesn't match env variable 46 if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']: 47 self.logPrintBox('''\ 48Warning: PETSC_ARCH from environment does not match command-line or name of script. 49Warning: Using from command-line or name of script: %s, ignoring environment: %s''' % (str(self.framework.argDB['PETSC_ARCH']), str(os.environ['PETSC_ARCH']))) 50 os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH'] 51 if 'with-petsc-arch' in self.framework.argDB: 52 self.arch = self.framework.argDB['with-petsc-arch'] 53 msg = 'option -with-petsc-arch='+str(self.arch) 54 elif 'PETSC_ARCH' in self.framework.argDB: 55 self.arch = self.framework.argDB['PETSC_ARCH'] 56 msg = 'option PETSC_ARCH='+str(self.arch) 57 elif 'PETSC_ARCH' in os.environ: 58 self.arch = os.environ['PETSC_ARCH'] 59 msg = 'environment variable PETSC_ARCH='+str(self.arch) 60 else: 61 self.arch = self.nativeArch 62 if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0: 63 raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg) 64 if self.arch.startswith('-'): 65 raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg) 66 if self.arch.startswith('.'): 67 raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg) 68 if not len(self.arch): 69 raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg) 70 self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch) 71 return 72 73 def makeDependency(self,hash,hashfile,hashfilepackages): 74 '''Deletes the current hashfile and saves the hashfile names and its value in framework so that''' 75 '''framework.Configure can create the file upon success of configure''' 76 import os 77 if hash: 78 self.framework.hash = hash 79 self.framework.hashfile = hashfile 80 self.logPrint('Setting hashfile: '+hashfile) 81 if hashfilepackages: self.framework.hashfilepackages = hashfilepackages 82 try: 83 self.logPrint('Deleting configure hash file: '+hashfile) 84 os.remove(hashfile) 85 self.logPrint('Deleted configure hash file: '+hashfile) 86 except: 87 self.logPrint('Unable to delete configure hash file: '+hashfile) 88 89 90 def checkDependency(self): 91 '''Checks if files in config have changed, the command line options have changed or the PATH has changed''' 92 ''' By default - checks if configure needs to be run''' 93 ''' If --arch-hash it manages the same information but it:''' 94 ''' * computes a short hash for the configuration <hashvalue>''' 95 ''' * sets self.arch and PETSC_ARCH to arch-<hashvalue>''' 96 ''' This results in the downloaded packages being installed once to the arch-<hasvalue> directory''' 97 ''' and a new directory with a different hash is created if the configuration changes.''' 98 ''' This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)''' 99 ''' If --package-prefix-hash=directory is provided''' 100 ''' * computes a short hash for the configuration <hashvalue>''' 101 ''' * puts the downloaded external packages into location directory/hash''' 102 ''' This results in the downloaded packages being installed once''' 103 ''' and a new directory with a different hash is created if the configuration changes.''' 104 ''' This mode is intended mostly for testing to reduce time of reinstalling external packages''' 105 import os 106 import sys 107 import hashlib 108 args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:]))) 109 hash = 'args:\n' + '\n'.join(' '+a for a in args) + '\n' 110 hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 111 chash='' 112 try: 113 for root, dirs, files in os.walk('config'): 114 if root == 'config': 115 dirs.remove('examples') 116 for f in files: 117 if not f.endswith('.py') or f.startswith('.') or f.startswith('#'): 118 continue 119 fname = os.path.join(root, f) 120 with open(fname,'rb') as f: 121 chash += hashlib.sha256(f.read()).hexdigest() + ' ' + fname + '\n' 122 except: 123 self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration') 124 return 125 hash += '\n'.join(sorted(chash.splitlines())) 126 hashfilepackages = None 127 # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change 128 if 'arch-hash' in self.argDB: 129 if self.argDB['prefix']: 130 raise RuntimeError('Cannot provide --prefix and --arch-hash') 131 if hasattr(self.argDB,'PETSC_ARCH'): 132 raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash') 133 if 'package-prefix-hash' in self.argDB: 134 raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash') 135 if os.getenv('PETSC_ARCH'): 136 raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash') 137 if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB: 138 import hashlib 139 m = hashlib.md5() 140 m.update(hash.encode('utf-8')) 141 hprefix = m.hexdigest() 142 if 'arch-hash' in self.argDB: 143 self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6] 144 self.arch = 'arch-'+hprefix[0:6] 145 else: 146 if not os.path.isdir(self.argDB['package-prefix-hash']): 147 raise RuntimeError('--package-prefix-hash '+self.argDB['package-prefix-hash']+' directory does not exist\n') 148 self.argDB['prefix'] = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) 149 if not os.path.isdir(self.argDB['prefix']): 150 os.mkdir(self.argDB['prefix']) 151 hashfilepackages = os.path.join(self.argDB['prefix'],'configure-hash') 152 else: 153 try: 154 with open(os.path.join(self.argDB['prefix'],'configure-hash'), 'r') as f: 155 a = f.read() 156 except: 157 self.logPrint('No previous hashfilepackages found') 158 a = '' 159 if a == hash: 160 self.logPrint('Reusing download packages in '+self.argDB['prefix']) 161 self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild 162 163 hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 164 165 if self.argDB['force']: 166 self.logPrint('Forcing a new configuration requested by use') 167 self.makeDependency(hash,hashfile,hashfilepackages) 168 return 169 a = '' 170 try: 171 with open(hashfile, 'r') as f: 172 a = f.read() 173 except: 174 self.logPrint('No previous hashfile found') 175 self.makeDependency(hash,hashfile,hashfilepackages) 176 return 177 if a == hash: 178 try: 179 self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 180 with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 181 g.write('PETSC_ARCH='+self.arch+'\n') 182 g.write('PETSC_DIR='+self.petscdir.dir+'\n') 183 g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 184 self.logPrint('Saved lib/petsc/conf/petscvariables file') 185 except: 186 self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 187 self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 188 print('Your configure options and state has not changed; no need to run configure') 189 print('However you can force a configure run using the option: --force') 190 sys.exit() 191 self.logPrint('configure hash file: '+hashfile+' does not match\n'+a+'\n---\n'+hash+'\n need to run configure') 192 self.makeDependency(hash,hashfile,hashfilepackages) 193 194 def configure(self): 195 self.executeTest(self.setNativeArchitecture) 196 self.executeTest(self.configureArchitecture) 197 # required by top-level configure.py 198 self.framework.arch = self.arch 199 self.checkDependency() 200 return 201