xref: /petsc/config/PETSc/options/arch.py (revision 9fa15c4dcfb14eef1e694c8c4e3db8b9dee7e944)
19d310bb7SBarry Smithimport config.base
29d310bb7SBarry Smithimport os
39d310bb7SBarry Smithimport re
49d310bb7SBarry Smith
59d310bb7SBarry Smithclass Configure(config.base.Configure):
69d310bb7SBarry Smith  def __init__(self, framework):
79d310bb7SBarry Smith    config.base.Configure.__init__(self, framework)
89d310bb7SBarry Smith    self.headerPrefix = 'PETSC'
99d310bb7SBarry Smith    self.substPrefix  = 'PETSC'
109d310bb7SBarry Smith    return
119d310bb7SBarry Smith
129d310bb7SBarry Smith  def __str1__(self):
139d310bb7SBarry Smith    if not hasattr(self, 'arch'):
149d310bb7SBarry Smith      return ''
1561897808SPierre Jolivet    return '  PETSC_ARCH: '+str(self.arch)+'\n'
169d310bb7SBarry Smith
179d310bb7SBarry Smith  def setupHelp(self, help):
189d310bb7SBarry Smith    import nargs
199d310bb7SBarry Smith    help.addArgument('PETSc', '-PETSC_ARCH=<string>',     nargs.Arg(None, None, 'The configuration name'))
209d310bb7SBarry Smith    help.addArgument('PETSc', '-with-petsc-arch=<string>',nargs.Arg(None, None, 'The configuration name'))
21dd328ec0SBarry Smith    help.addArgument('PETSc', '-force=<bool>',            nargs.ArgBool(None, 0, 'Bypass configure hash caching, and run to completion'))
22dd328ec0SBarry Smith    return
23dd328ec0SBarry Smith
24dd328ec0SBarry Smith  def setupDependencies(self, framework):
25dd328ec0SBarry Smith    self.sourceControl = framework.require('config.sourceControl',self)
26dd328ec0SBarry Smith    self.petscdir = framework.require('PETSc.options.petscdir', self)
279d310bb7SBarry Smith    return
289d310bb7SBarry Smith
291a8e9eaeSSatish Balay  def setNativeArchitecture(self):
307b65ca21SBarry Smith    '''Forms the arch as GNU's configure would form it'''
3170211a5bSSatish Balay    import sys
3270211a5bSSatish Balay    arch = 'arch-' + sys.platform.replace('cygwin','mswin')
3370211a5bSSatish Balay    # use opt/debug, c/c++ tags.s
3470211a5bSSatish Balay    arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x')
3570211a5bSSatish Balay    if self.framework.argDB['with-debugging']:
3670211a5bSSatish Balay      arch += '-debug'
3770211a5bSSatish Balay    else:
3870211a5bSSatish Balay      arch += '-opt'
391a8e9eaeSSatish Balay    self.nativeArch = arch
401a8e9eaeSSatish Balay    return
4170211a5bSSatish Balay
429d310bb7SBarry Smith  def configureArchitecture(self):
437b65ca21SBarry Smith    '''Checks if PETSC_ARCH is set and sets it if not set'''
44bf3e94a3SBarry Smith    # Warn if PETSC_ARCH doesn't match env variable
459d310bb7SBarry Smith    if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']:
46d1b3ee28SJacob Faibussowitsch      self.logPrintWarning('''\
47d1b3ee28SJacob FaibussowitschPETSC_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'])))
4857ea55fdSJed Brown      os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH']
499d310bb7SBarry Smith    if 'with-petsc-arch' in self.framework.argDB:
509d310bb7SBarry Smith      self.arch = self.framework.argDB['with-petsc-arch']
5170211a5bSSatish Balay      msg = 'option -with-petsc-arch='+str(self.arch)
529d310bb7SBarry Smith    elif 'PETSC_ARCH' in self.framework.argDB:
539d310bb7SBarry Smith      self.arch = self.framework.argDB['PETSC_ARCH']
5470211a5bSSatish Balay      msg = 'option PETSC_ARCH='+str(self.arch)
5570211a5bSSatish Balay    elif 'PETSC_ARCH' in os.environ:
569d310bb7SBarry Smith      self.arch = os.environ['PETSC_ARCH']
5770211a5bSSatish Balay      msg = 'environment variable PETSC_ARCH='+str(self.arch)
589d310bb7SBarry Smith    else:
591a8e9eaeSSatish Balay      self.arch = self.nativeArch
609d310bb7SBarry Smith    if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0:
6170211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg)
62002ae2c9SLisandro Dalcin    if self.arch.startswith('-'):
6370211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg)
6470211a5bSSatish Balay    if self.arch.startswith('.'):
6570211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg)
6670211a5bSSatish Balay    if not len(self.arch):
6770211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg)
689d310bb7SBarry Smith    self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch)
699d310bb7SBarry Smith    return
709d310bb7SBarry Smith
71bf3e94a3SBarry Smith  def makeDependency(self,hash,hashfile,hashfilepackages):
72bf3e94a3SBarry Smith    '''Deletes the current hashfile and saves the hashfile names and its value in framework so that'''
73f8357408SBarry Smith    '''framework.Configure can create the file upon success of configure'''
74dd328ec0SBarry Smith    import os
75f8357408SBarry Smith    if hash:
76f8357408SBarry Smith      self.framework.hash = hash
77f8357408SBarry Smith      self.framework.hashfile = hashfile
78bf3e94a3SBarry Smith      self.logPrint('Setting hashfile: '+hashfile)
79bf3e94a3SBarry Smith      if hashfilepackages: self.framework.hashfilepackages = hashfilepackages
80dd328ec0SBarry Smith    try:
81bf3e94a3SBarry Smith      self.logPrint('Deleting configure hash file: '+hashfile)
82f8357408SBarry Smith      os.remove(hashfile)
83bf3e94a3SBarry Smith      self.logPrint('Deleted configure hash file: '+hashfile)
84dd328ec0SBarry Smith    except:
85f8357408SBarry Smith      self.logPrint('Unable to delete configure hash file: '+hashfile)
86bf3e94a3SBarry Smith
87dd328ec0SBarry Smith  def checkDependency(self):
88dd328ec0SBarry Smith    '''Checks if files in config have changed, the command line options have changed or the PATH has changed'''
89bf3e94a3SBarry Smith    '''  By default - checks if configure needs to be run'''
90bf3e94a3SBarry Smith    '''  If --arch-hash it manages the same information but it:'''
91bf3e94a3SBarry Smith    '''     * computes a short hash for the configuration <hashvalue>'''
92bf3e94a3SBarry Smith    '''     * sets self.arch and PETSC_ARCH to arch-<hashvalue>'''
93bf3e94a3SBarry Smith    '''       This results in the downloaded packages being installed once to the arch-<hasvalue> directory'''
94bf3e94a3SBarry Smith    '''       and a new directory with a different hash is created if the configuration changes.'''
95bf3e94a3SBarry Smith    '''     This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)'''
96bf3e94a3SBarry Smith    '''  If --package-prefix-hash=directory is provided'''
97bf3e94a3SBarry Smith    '''     * computes a short hash for the configuration <hashvalue>'''
98bf3e94a3SBarry Smith    '''     * puts the downloaded external packages into location directory/hash'''
99bf3e94a3SBarry Smith    '''       This results in the downloaded packages being installed once'''
100bf3e94a3SBarry Smith    '''       and a new directory with a different hash is created if the configuration changes.'''
101bf3e94a3SBarry Smith    '''     This mode is intended mostly for testing to reduce time of reinstalling external packages'''
102dd328ec0SBarry Smith    import os
103dd328ec0SBarry Smith    import sys
104dd328ec0SBarry Smith    import hashlib
1054dd8803aSSatish Balay    import platform
106e2555bbcSSatish Balay    import nargs
1074dd8803aSSatish Balay    hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n'
108b60faad8SJed Brown    hash += 'PATH=' + os.environ.get('PATH', '') + '\n'
109e2555bbcSSatish Balay    args = dict([(nargs.Arg.parseArgument(arg)[0], arg) for arg in self.framework.clArgs])
110e2555bbcSSatish Balay    hash += 'args:\n' + '\n'.join('    '+a for a in sorted(args.values())) + '\n'
111a952ef13SBarry Smith    chash=''
112dd328ec0SBarry Smith    try:
113dd328ec0SBarry Smith      for root, dirs, files in os.walk('config'):
114b60faad8SJed Brown        if root == 'config':
115b60faad8SJed Brown          dirs.remove('examples')
116dd328ec0SBarry Smith        for f in files:
117b60faad8SJed Brown          if not f.endswith('.py') or f.startswith('.') or f.startswith('#'):
118b60faad8SJed Brown            continue
119dd328ec0SBarry Smith          fname = os.path.join(root, f)
120b60faad8SJed Brown          with open(fname,'rb') as f:
121a952ef13SBarry Smith            chash += hashlib.sha256(f.read()).hexdigest() + '  ' + fname + '\n'
122dd328ec0SBarry Smith    except:
123b60faad8SJed Brown      self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration')
124dd328ec0SBarry Smith      return
125a952ef13SBarry Smith    hash += '\n'.join(sorted(chash.splitlines()))
126bf3e94a3SBarry Smith    hashfilepackages = None
127bf3e94a3SBarry Smith    # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change
128bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB:
129bf3e94a3SBarry Smith      if self.argDB['prefix']:
130bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --prefix and --arch-hash')
131bf3e94a3SBarry Smith      if hasattr(self.argDB,'PETSC_ARCH'):
132bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash')
133bf3e94a3SBarry Smith      if 'package-prefix-hash' in self.argDB:
134bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash')
135bf3e94a3SBarry Smith      if os.getenv('PETSC_ARCH'):
136bf3e94a3SBarry Smith        raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash')
137bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB:
138bf3e94a3SBarry Smith      import hashlib
139*fe324abeSRonald Gould      m = hashlib.sha256()
140a952ef13SBarry Smith      m.update(hash.encode('utf-8'))
141bf3e94a3SBarry Smith      hprefix = m.hexdigest()
1427f69da20SBarry Smith      self.logPrint('Computed hash to be used with --package-prefix-hash option: '+hprefix)
143bf3e94a3SBarry Smith      if 'arch-hash' in self.argDB:
144bf3e94a3SBarry Smith        self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6]
145bf3e94a3SBarry Smith        self.arch = 'arch-'+hprefix[0:6]
146bf3e94a3SBarry Smith      else:
147bf3e94a3SBarry Smith        if not os.path.isdir(self.argDB['package-prefix-hash']):
148d5b43468SJose E. Roman          self.logPrint('Specified package-prefix-hash location %s not found! Attempting to create this dir!' % self.argDB['package-prefix-hash'])
149be5c6b33SBarry Smith          try:
15020a7ad26SSatish Balay            os.makedirs(self.argDB['package-prefix-hash'])
151be5c6b33SBarry Smith          except Exception as e:
15220a7ad26SSatish Balay            self.logPrint('Error creating package-prefix-hash directory '+self.argDB['package-prefix-hash']+': '+str(e))
153d3c8a501SBarry Smith            raise RuntimeError('You must have write permission to create prefix directory '+self.argDB['package-prefix-hash'])
15420a7ad26SSatish Balay        status = False
15520a7ad26SSatish Balay        for idx in range(6,len(hprefix)):
15620a7ad26SSatish Balay          hashdirpackages = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:idx])
15720a7ad26SSatish Balay          hashfilepackages = os.path.join(hashdirpackages,'configure-hash')
15820a7ad26SSatish Balay          if os.path.isdir(hashdirpackages):
15920a7ad26SSatish Balay            if os.path.exists(hashfilepackages):
16020a7ad26SSatish Balay              self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild
1617f69da20SBarry Smith              self.logPrint('Found existing '+hashfilepackages+' reusing packages built in '+hashdirpackages)
16220a7ad26SSatish Balay              status = True
16320a7ad26SSatish Balay              break
164bf3e94a3SBarry Smith            else:
1657f69da20SBarry Smith              self.logPrint('Found existing '+hashdirpackages+' but it is incomplete so trying a longer directory name based on the hash')
1667f69da20SBarry Smith              continue # perhaps an incomplete build? use a longer hash
1677f69da20SBarry Smith          else:
1687f69da20SBarry Smith            if self.argDB['force']:
1697f69da20SBarry Smith              # since the previous hash associated with --package-prefix-hash
1707f69da20SBarry Smith              # (and hence its directory of built packages) is not available
1717f69da20SBarry Smith              # all the packages associated with that hash cannot be reused
1727f69da20SBarry Smith              raise RuntimeError('You cannot use --force with --package-prefix-hash=directory; you need to delete the $PETSC_ARCH directory and run configure again')
1737f69da20SBarry Smith            self.logPrint('Creating package-prefix-hash subdirectory '+hashdirpackages)
174bf3e94a3SBarry Smith            try:
17520a7ad26SSatish Balay              os.mkdir(hashdirpackages)
17620a7ad26SSatish Balay            except Exception as e:
17720a7ad26SSatish Balay              raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory')
17820a7ad26SSatish Balay            status = True
17920a7ad26SSatish Balay            break
18020a7ad26SSatish Balay        if not status:
18120a7ad26SSatish Balay          raise RuntimeError('Unable to create package-prefix-hash dir! Suggest cleaning up %s* !' % os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6]) )
18220a7ad26SSatish Balay        self.argDB['prefix'] = hashdirpackages
183bf3e94a3SBarry Smith
184bf3e94a3SBarry Smith    hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash')
185bf3e94a3SBarry Smith
186dd328ec0SBarry Smith    if self.argDB['force']:
187bf3e94a3SBarry Smith      self.logPrint('Forcing a new configuration requested by use')
188a952ef13SBarry Smith      self.makeDependency(hash,hashfile,hashfilepackages)
189dd328ec0SBarry Smith      return
190dd328ec0SBarry Smith    a = ''
191dd328ec0SBarry Smith    try:
192f8357408SBarry Smith      with open(hashfile, 'r') as f:
193dd328ec0SBarry Smith        a = f.read()
194dd328ec0SBarry Smith    except:
195bf3e94a3SBarry Smith      self.logPrint('No previous hashfile found')
196bf3e94a3SBarry Smith      self.makeDependency(hash,hashfile,hashfilepackages)
197dd328ec0SBarry Smith      return
198dd328ec0SBarry Smith    if a == hash:
199bf3e94a3SBarry Smith      try:
200bf3e94a3SBarry Smith        self.logPrint('Attempting to save lib/petsc/conf/petscvariables file')
201bf3e94a3SBarry Smith        with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g:
202bf3e94a3SBarry Smith          g.write('PETSC_ARCH='+self.arch+'\n')
203bf3e94a3SBarry Smith          g.write('PETSC_DIR='+self.petscdir.dir+'\n')
204bf3e94a3SBarry Smith          g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n')
205bf3e94a3SBarry Smith          self.logPrint('Saved lib/petsc/conf/petscvariables file')
206bf3e94a3SBarry Smith      except:
207bf3e94a3SBarry Smith        self.logPrint('Unable to save lib/petsc/conf/petscvariables file')
208f8357408SBarry Smith      self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.')
2098f47816eSPierre Jolivet      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')
2105b4fc442SVaclav Hapla
211e4d7ee71SJacob Faibussowitsch      import logger
2125b4fc442SVaclav Hapla      from config.packages.make import getMakeUserPath
213e4d7ee71SJacob Faibussowitsch      banner_ends   = 'xxx'
214e4d7ee71SJacob Faibussowitsch      banner_middle = '=' * (logger.get_global_divider_length() - 2 * len(banner_ends))
215e4d7ee71SJacob Faibussowitsch      banner_line   = banner_middle.join((banner_ends, banner_ends))
216e4d7ee71SJacob Faibussowitsch      print(banner_line)
2175b4fc442SVaclav Hapla      print(' Build PETSc libraries with:')
2185b4fc442SVaclav Hapla      print('   %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch))
219e4d7ee71SJacob Faibussowitsch      print(banner_line)
220dd328ec0SBarry Smith      sys.exit()
221ae46fe3bSBarry Smith    self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure')
222bf3e94a3SBarry Smith    self.makeDependency(hash,hashfile,hashfilepackages)
223dd328ec0SBarry Smith
2249d310bb7SBarry Smith  def configure(self):
2251a8e9eaeSSatish Balay    self.executeTest(self.setNativeArchitecture)
2269d310bb7SBarry Smith    self.executeTest(self.configureArchitecture)
2279d310bb7SBarry Smith    # required by top-level configure.py
2289d310bb7SBarry Smith    self.framework.arch = self.arch
229dd328ec0SBarry Smith    self.checkDependency()
2309d310bb7SBarry Smith    return
231