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.logPrintWarning('''\ 48PETSC_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']))) 49 os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH'] 50 if 'with-petsc-arch' in self.framework.argDB: 51 self.arch = self.framework.argDB['with-petsc-arch'] 52 msg = 'option -with-petsc-arch='+str(self.arch) 53 elif 'PETSC_ARCH' in self.framework.argDB: 54 self.arch = self.framework.argDB['PETSC_ARCH'] 55 msg = 'option PETSC_ARCH='+str(self.arch) 56 elif 'PETSC_ARCH' in os.environ: 57 self.arch = os.environ['PETSC_ARCH'] 58 msg = 'environment variable PETSC_ARCH='+str(self.arch) 59 else: 60 self.arch = self.nativeArch 61 if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0: 62 raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg) 63 if self.arch.startswith('-'): 64 raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg) 65 if self.arch.startswith('.'): 66 raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg) 67 if not len(self.arch): 68 raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg) 69 self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch) 70 return 71 72 def makeDependency(self,hash,hashfile,hashfilepackages): 73 '''Deletes the current hashfile and saves the hashfile names and its value in framework so that''' 74 '''framework.Configure can create the file upon success of configure''' 75 import os 76 if hash: 77 self.framework.hash = hash 78 self.framework.hashfile = hashfile 79 self.logPrint('Setting hashfile: '+hashfile) 80 if hashfilepackages: self.framework.hashfilepackages = hashfilepackages 81 try: 82 self.logPrint('Deleting configure hash file: '+hashfile) 83 os.remove(hashfile) 84 self.logPrint('Deleted configure hash file: '+hashfile) 85 except: 86 self.logPrint('Unable to delete configure hash file: '+hashfile) 87 88 89 def checkDependency(self): 90 '''Checks if files in config have changed, the command line options have changed or the PATH has changed''' 91 ''' By default - checks if configure needs to be run''' 92 ''' If --arch-hash it manages the same information but it:''' 93 ''' * computes a short hash for the configuration <hashvalue>''' 94 ''' * sets self.arch and PETSC_ARCH to arch-<hashvalue>''' 95 ''' This results in the downloaded packages being installed once to the arch-<hasvalue> directory''' 96 ''' and a new directory with a different hash is created if the configuration changes.''' 97 ''' This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)''' 98 ''' If --package-prefix-hash=directory is provided''' 99 ''' * computes a short hash for the configuration <hashvalue>''' 100 ''' * puts the downloaded external packages into location directory/hash''' 101 ''' This results in the downloaded packages being installed once''' 102 ''' and a new directory with a different hash is created if the configuration changes.''' 103 ''' This mode is intended mostly for testing to reduce time of reinstalling external packages''' 104 import os 105 import sys 106 import hashlib 107 import platform 108 hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n' 109 hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 110 args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:]))) 111 hash += 'args:\n' + '\n'.join(' '+a for a in args) + '\n' 112 chash='' 113 try: 114 for root, dirs, files in os.walk('config'): 115 if root == 'config': 116 dirs.remove('examples') 117 for f in files: 118 if not f.endswith('.py') or f.startswith('.') or f.startswith('#'): 119 continue 120 fname = os.path.join(root, f) 121 with open(fname,'rb') as f: 122 chash += hashlib.sha256(f.read()).hexdigest() + ' ' + fname + '\n' 123 except: 124 self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration') 125 return 126 hash += '\n'.join(sorted(chash.splitlines())) 127 hashfilepackages = None 128 # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change 129 if 'arch-hash' in self.argDB: 130 if self.argDB['prefix']: 131 raise RuntimeError('Cannot provide --prefix and --arch-hash') 132 if hasattr(self.argDB,'PETSC_ARCH'): 133 raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash') 134 if 'package-prefix-hash' in self.argDB: 135 raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash') 136 if os.getenv('PETSC_ARCH'): 137 raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash') 138 if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB: 139 import hashlib 140 m = hashlib.md5() 141 m.update(hash.encode('utf-8')) 142 hprefix = m.hexdigest() 143 if 'arch-hash' in self.argDB: 144 self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6] 145 self.arch = 'arch-'+hprefix[0:6] 146 else: 147 if not os.path.isdir(self.argDB['package-prefix-hash']): 148 self.logPrintBox('Specified package-prefix-hash location %s not found! Attemping to create this dir!' % self.argDB['package-prefix-hash']) 149 try: 150 os.makedirs(self.argDB['package-prefix-hash']) 151 except Exception as e: 152 self.logPrint('Error creating package-prefix-hash directory '+self.argDB['package-prefix-hash']+': '+str(e)) 153 raise RuntimeError('You must have write permission to create this directory!') 154 status = False 155 for idx in range(6,len(hprefix)): 156 hashdirpackages = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:idx]) 157 hashfilepackages = os.path.join(hashdirpackages,'configure-hash') 158 if os.path.isdir(hashdirpackages): 159 if os.path.exists(hashfilepackages): 160 self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild 161 status = True 162 break 163 else: continue # perhaps an incomplete build? use a longer hash 164 else: 165 try: 166 os.mkdir(hashdirpackages) 167 except Exception as e: 168 self.logPrint('Error creating package-prefix-hash directory '+hashdirpackages+': '+str(e)) 169 raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory') 170 status = True 171 break 172 if not status: 173 raise RuntimeError('Unable to create package-prefix-hash dir! Suggest cleaning up %s* !' % os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) ) 174 self.argDB['prefix'] = hashdirpackages 175 176 hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 177 178 if self.argDB['force']: 179 self.logPrint('Forcing a new configuration requested by use') 180 self.makeDependency(hash,hashfile,hashfilepackages) 181 return 182 a = '' 183 try: 184 with open(hashfile, 'r') as f: 185 a = f.read() 186 except: 187 self.logPrint('No previous hashfile found') 188 self.makeDependency(hash,hashfile,hashfilepackages) 189 return 190 if a == hash: 191 try: 192 self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 193 with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 194 g.write('PETSC_ARCH='+self.arch+'\n') 195 g.write('PETSC_DIR='+self.petscdir.dir+'\n') 196 g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 197 self.logPrint('Saved lib/petsc/conf/petscvariables file') 198 except: 199 self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 200 self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 201 print('Your configure options and state has not changed; no need to run configure') 202 print('However you can force a configure run using the option: --force') 203 204 from config.packages.make import getMakeUserPath 205 print('xxx=========================================================================xxx') 206 print(' Build PETSc libraries with:') 207 print(' %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch)) 208 print('xxx=========================================================================xxx') 209 sys.exit() 210 self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure') 211 self.makeDependency(hash,hashfile,hashfilepackages) 212 213 def configure(self): 214 self.executeTest(self.setNativeArchitecture) 215 self.executeTest(self.configureArchitecture) 216 # required by top-level configure.py 217 self.framework.arch = self.arch 218 self.checkDependency() 219 return 220