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 import platform 109 hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n' 110 hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 111 args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:]))) 112 hash += 'args:\n' + '\n'.join(' '+a for a in args) + '\n' 113 chash='' 114 try: 115 for root, dirs, files in os.walk('config'): 116 if root == 'config': 117 dirs.remove('examples') 118 for f in files: 119 if not f.endswith('.py') or f.startswith('.') or f.startswith('#'): 120 continue 121 fname = os.path.join(root, f) 122 with open(fname,'rb') as f: 123 chash += hashlib.sha256(f.read()).hexdigest() + ' ' + fname + '\n' 124 except: 125 self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration') 126 return 127 hash += '\n'.join(sorted(chash.splitlines())) 128 hashfilepackages = None 129 # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change 130 if 'arch-hash' in self.argDB: 131 if self.argDB['prefix']: 132 raise RuntimeError('Cannot provide --prefix and --arch-hash') 133 if hasattr(self.argDB,'PETSC_ARCH'): 134 raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash') 135 if 'package-prefix-hash' in self.argDB: 136 raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash') 137 if os.getenv('PETSC_ARCH'): 138 raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash') 139 if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB: 140 import hashlib 141 m = hashlib.md5() 142 m.update(hash.encode('utf-8')) 143 hprefix = m.hexdigest() 144 if 'arch-hash' in self.argDB: 145 self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6] 146 self.arch = 'arch-'+hprefix[0:6] 147 else: 148 if not os.path.isdir(self.argDB['package-prefix-hash']): 149 self.logPrintBox('Specified package-prefix-hash location %s not found! Attemping to create this dir!' % self.argDB['package-prefix-hash']) 150 try: 151 os.makedirs(self.argDB['package-prefix-hash']) 152 except Exception as e: 153 self.logPrint('Error creating package-prefix-hash directory '+self.argDB['package-prefix-hash']+': '+str(e)) 154 raise RuntimeError('You must have write permission to create this directory!') 155 status = False 156 for idx in range(6,len(hprefix)): 157 hashdirpackages = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:idx]) 158 hashfilepackages = os.path.join(hashdirpackages,'configure-hash') 159 if os.path.isdir(hashdirpackages): 160 if os.path.exists(hashfilepackages): 161 self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild 162 status = True 163 break 164 else: continue # perhaps an incomplete build? use a longer hash 165 else: 166 try: 167 os.mkdir(hashdirpackages) 168 except Exception as e: 169 self.logPrint('Error creating package-prefix-hash directory '+hashdirpackages+': '+str(e)) 170 raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory') 171 status = True 172 break 173 if not status: 174 raise RuntimeError('Unable to create package-prefix-hash dir! Suggest cleaning up %s* !' % os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) ) 175 self.argDB['prefix'] = hashdirpackages 176 177 hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 178 179 if self.argDB['force']: 180 self.logPrint('Forcing a new configuration requested by use') 181 self.makeDependency(hash,hashfile,hashfilepackages) 182 return 183 a = '' 184 try: 185 with open(hashfile, 'r') as f: 186 a = f.read() 187 except: 188 self.logPrint('No previous hashfile found') 189 self.makeDependency(hash,hashfile,hashfilepackages) 190 return 191 if a == hash: 192 try: 193 self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 194 with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 195 g.write('PETSC_ARCH='+self.arch+'\n') 196 g.write('PETSC_DIR='+self.petscdir.dir+'\n') 197 g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 198 self.logPrint('Saved lib/petsc/conf/petscvariables file') 199 except: 200 self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 201 self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 202 print('Your configure options and state has not changed; no need to run configure') 203 print('However you can force a configure run using the option: --force') 204 205 from config.packages.make import getMakeUserPath 206 print('xxx=========================================================================xxx') 207 print(' Build PETSc libraries with:') 208 print(' %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch)) 209 print('xxx=========================================================================xxx') 210 sys.exit() 211 self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure') 212 self.makeDependency(hash,hashfile,hashfilepackages) 213 214 def configure(self): 215 self.executeTest(self.setNativeArchitecture) 216 self.executeTest(self.configureArchitecture) 217 # required by top-level configure.py 218 self.framework.arch = self.arch 219 self.checkDependency() 220 return 221