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 '''Forms the arch as GNU's configure would form it''' 31 import sys 32 arch = 'arch-' + sys.platform.replace('cygwin','mswin') 33 # use opt/debug, c/c++ tags.s 34 arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x') 35 if self.framework.argDB['with-debugging']: 36 arch += '-debug' 37 else: 38 arch += '-opt' 39 self.nativeArch = arch 40 return 41 42 def configureArchitecture(self): 43 '''Checks if PETSC_ARCH is set and sets it if not set''' 44 # Warn if PETSC_ARCH doesn't match env variable 45 if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']: 46 self.logPrintWarning('''\ 47PETSC_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']))) 48 os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH'] 49 if 'with-petsc-arch' in self.framework.argDB: 50 self.arch = self.framework.argDB['with-petsc-arch'] 51 msg = 'option -with-petsc-arch='+str(self.arch) 52 elif 'PETSC_ARCH' in self.framework.argDB: 53 self.arch = self.framework.argDB['PETSC_ARCH'] 54 msg = 'option PETSC_ARCH='+str(self.arch) 55 elif 'PETSC_ARCH' in os.environ: 56 self.arch = os.environ['PETSC_ARCH'] 57 msg = 'environment variable PETSC_ARCH='+str(self.arch) 58 else: 59 self.arch = self.nativeArch 60 if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0: 61 raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg) 62 if self.arch.startswith('-'): 63 raise RuntimeError('PETSC_ARCH should not start with "-", 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 not len(self.arch): 67 raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg) 68 self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch) 69 return 70 71 def makeDependency(self,hash,hashfile,hashfilepackages): 72 '''Deletes the current hashfile and saves the hashfile names and its value in framework so that''' 73 '''framework.Configure can create the file upon success of configure''' 74 import os 75 if hash: 76 self.framework.hash = hash 77 self.framework.hashfile = hashfile 78 self.logPrint('Setting hashfile: '+hashfile) 79 if hashfilepackages: self.framework.hashfilepackages = hashfilepackages 80 try: 81 self.logPrint('Deleting configure hash file: '+hashfile) 82 os.remove(hashfile) 83 self.logPrint('Deleted configure hash file: '+hashfile) 84 except: 85 self.logPrint('Unable to delete configure hash file: '+hashfile) 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 import nargs 107 hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n' 108 hash += 'PATH=' + os.environ.get('PATH', '') + '\n' 109 args = dict([(nargs.Arg.parseArgument(arg)[0], arg) for arg in self.framework.clArgs]) 110 hash += 'args:\n' + '\n'.join(' '+a for a in sorted(args.values())) + '\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.sha256() 140 m.update(hash.encode('utf-8')) 141 hprefix = m.hexdigest() 142 self.logPrint('Computed hash to be used with --package-prefix-hash option: '+hprefix) 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.logPrint('Specified package-prefix-hash location %s not found! Attempting 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 prefix directory '+self.argDB['package-prefix-hash']) 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 self.logPrint('Found existing '+hashfilepackages+' reusing packages built in '+hashdirpackages) 162 status = True 163 break 164 else: 165 self.logPrint('Found existing '+hashdirpackages+' but it is incomplete so trying a longer directory name based on the hash') 166 continue # perhaps an incomplete build? use a longer hash 167 else: 168 if self.argDB['force']: 169 # since the previous hash associated with --package-prefix-hash 170 # (and hence its directory of built packages) is not available 171 # all the packages associated with that hash cannot be reused 172 raise RuntimeError('You cannot use --force with --package-prefix-hash=directory; you need to delete the $PETSC_ARCH directory and run configure again') 173 self.logPrint('Creating package-prefix-hash subdirectory '+hashdirpackages) 174 try: 175 os.mkdir(hashdirpackages) 176 except Exception as e: 177 raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory') 178 status = True 179 break 180 if not status: 181 raise RuntimeError('Unable to create package-prefix-hash dir! Suggest cleaning up %s* !' % os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) ) 182 self.argDB['prefix'] = hashdirpackages 183 184 hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash') 185 186 if self.argDB['force']: 187 self.logPrint('Forcing a new configuration requested by use') 188 self.makeDependency(hash,hashfile,hashfilepackages) 189 return 190 a = '' 191 try: 192 with open(hashfile, 'r') as f: 193 a = f.read() 194 except: 195 self.logPrint('No previous hashfile found') 196 self.makeDependency(hash,hashfile,hashfilepackages) 197 return 198 if a == hash: 199 try: 200 self.logPrint('Attempting to save lib/petsc/conf/petscvariables file') 201 with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g: 202 g.write('PETSC_ARCH='+self.arch+'\n') 203 g.write('PETSC_DIR='+self.petscdir.dir+'\n') 204 g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n') 205 self.logPrint('Saved lib/petsc/conf/petscvariables file') 206 except: 207 self.logPrint('Unable to save lib/petsc/conf/petscvariables file') 208 self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.') 209 self.logPrintBox('Your configure options and state has not changed; no need to run configure\nHowever you can force a configure run using the option: --force') 210 211 import logger 212 from config.packages.make import getMakeUserPath 213 banner_ends = 'xxx' 214 banner_middle = '=' * (logger.get_global_divider_length() - 2 * len(banner_ends)) 215 banner_line = banner_middle.join((banner_ends, banner_ends)) 216 print(banner_line) 217 print(' Build PETSc libraries with:') 218 print(' %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch)) 219 print(banner_line) 220 sys.exit() 221 self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure') 222 self.makeDependency(hash,hashfile,hashfilepackages) 223 224 def configure(self): 225 self.executeTest(self.setNativeArchitecture) 226 self.executeTest(self.configureArchitecture) 227 # required by top-level configure.py 228 self.framework.arch = self.arch 229 self.checkDependency() 230 return 231