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