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