xref: /petsc/config/PETSc/options/arch.py (revision d3c8a50109fab35391a942b0e8763aca8c5b3c06)
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):
3070211a5bSSatish Balay    import sys
3170211a5bSSatish Balay    arch = 'arch-' + sys.platform.replace('cygwin','mswin')
3270211a5bSSatish Balay    # use opt/debug, c/c++ tags.s
3370211a5bSSatish Balay    arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x')
3470211a5bSSatish Balay    if self.framework.argDB['with-debugging']:
3570211a5bSSatish Balay      arch += '-debug'
3670211a5bSSatish Balay    else:
3770211a5bSSatish Balay      arch += '-opt'
381a8e9eaeSSatish Balay    self.nativeArch = arch
391a8e9eaeSSatish Balay    return
4070211a5bSSatish Balay
419d310bb7SBarry Smith  def configureArchitecture(self):
429d310bb7SBarry Smith    '''Checks PETSC_ARCH and sets if not set'''
43bf3e94a3SBarry Smith    # Warn if PETSC_ARCH doesn't match env variable
449d310bb7SBarry Smith    if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']:
45d1b3ee28SJacob Faibussowitsch      self.logPrintWarning('''\
46d1b3ee28SJacob 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'])))
4757ea55fdSJed Brown      os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH']
489d310bb7SBarry Smith    if 'with-petsc-arch' in self.framework.argDB:
499d310bb7SBarry Smith      self.arch = self.framework.argDB['with-petsc-arch']
5070211a5bSSatish Balay      msg = 'option -with-petsc-arch='+str(self.arch)
519d310bb7SBarry Smith    elif 'PETSC_ARCH' in self.framework.argDB:
529d310bb7SBarry Smith      self.arch = self.framework.argDB['PETSC_ARCH']
5370211a5bSSatish Balay      msg = 'option PETSC_ARCH='+str(self.arch)
5470211a5bSSatish Balay    elif 'PETSC_ARCH' in os.environ:
559d310bb7SBarry Smith      self.arch = os.environ['PETSC_ARCH']
5670211a5bSSatish Balay      msg = 'environment variable PETSC_ARCH='+str(self.arch)
579d310bb7SBarry Smith    else:
581a8e9eaeSSatish Balay      self.arch = self.nativeArch
599d310bb7SBarry Smith    if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0:
6070211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg)
61002ae2c9SLisandro Dalcin    if self.arch.startswith('-'):
6270211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg)
6370211a5bSSatish Balay    if self.arch.startswith('.'):
6470211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg)
6570211a5bSSatish Balay    if not len(self.arch):
6670211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg)
679d310bb7SBarry Smith    self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch)
689d310bb7SBarry Smith    return
699d310bb7SBarry Smith
70bf3e94a3SBarry Smith  def makeDependency(self,hash,hashfile,hashfilepackages):
71bf3e94a3SBarry Smith    '''Deletes the current hashfile and saves the hashfile names and its value in framework so that'''
72f8357408SBarry Smith    '''framework.Configure can create the file upon success of configure'''
73dd328ec0SBarry Smith    import os
74f8357408SBarry Smith    if hash:
75f8357408SBarry Smith      self.framework.hash = hash
76f8357408SBarry Smith      self.framework.hashfile = hashfile
77bf3e94a3SBarry Smith      self.logPrint('Setting hashfile: '+hashfile)
78bf3e94a3SBarry Smith      if hashfilepackages: self.framework.hashfilepackages = hashfilepackages
79dd328ec0SBarry Smith    try:
80bf3e94a3SBarry Smith      self.logPrint('Deleting configure hash file: '+hashfile)
81f8357408SBarry Smith      os.remove(hashfile)
82bf3e94a3SBarry Smith      self.logPrint('Deleted configure hash file: '+hashfile)
83dd328ec0SBarry Smith    except:
84f8357408SBarry Smith      self.logPrint('Unable to delete configure hash file: '+hashfile)
85bf3e94a3SBarry Smith
86dd328ec0SBarry 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
1064dd8803aSSatish Balay    hash = 'Uname: '+platform.uname().system+' '+platform.uname().processor+'\n'
107b60faad8SJed Brown    hash += 'PATH=' + os.environ.get('PATH', '') + '\n'
1084dd8803aSSatish Balay    args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:])))
1094dd8803aSSatish Balay    hash += 'args:\n' + '\n'.join('    '+a for a in args) + '\n'
110a952ef13SBarry Smith    chash=''
111dd328ec0SBarry Smith    try:
112dd328ec0SBarry Smith      for root, dirs, files in os.walk('config'):
113b60faad8SJed Brown        if root == 'config':
114b60faad8SJed Brown          dirs.remove('examples')
115dd328ec0SBarry Smith        for f in files:
116b60faad8SJed Brown          if not f.endswith('.py') or f.startswith('.') or f.startswith('#'):
117b60faad8SJed Brown            continue
118dd328ec0SBarry Smith          fname = os.path.join(root, f)
119b60faad8SJed Brown          with open(fname,'rb') as f:
120a952ef13SBarry Smith            chash += hashlib.sha256(f.read()).hexdigest() + '  ' + fname + '\n'
121dd328ec0SBarry Smith    except:
122b60faad8SJed Brown      self.logPrint('Error generating file list/hash from config directory for configure hash, forcing new configuration')
123dd328ec0SBarry Smith      return
124a952ef13SBarry Smith    hash += '\n'.join(sorted(chash.splitlines()))
125bf3e94a3SBarry Smith    hashfilepackages = None
126bf3e94a3SBarry Smith    # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change
127bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB:
128bf3e94a3SBarry Smith      if self.argDB['prefix']:
129bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --prefix and --arch-hash')
130bf3e94a3SBarry Smith      if hasattr(self.argDB,'PETSC_ARCH'):
131bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash')
132bf3e94a3SBarry Smith      if 'package-prefix-hash' in self.argDB:
133bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash')
134bf3e94a3SBarry Smith      if os.getenv('PETSC_ARCH'):
135bf3e94a3SBarry Smith        raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash')
136bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB:
137bf3e94a3SBarry Smith      import hashlib
138bf3e94a3SBarry Smith      m = hashlib.md5()
139a952ef13SBarry Smith      m.update(hash.encode('utf-8'))
140bf3e94a3SBarry Smith      hprefix = m.hexdigest()
141bf3e94a3SBarry Smith      if 'arch-hash' in self.argDB:
142bf3e94a3SBarry Smith        self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6]
143bf3e94a3SBarry Smith        self.arch = 'arch-'+hprefix[0:6]
144bf3e94a3SBarry Smith      else:
145bf3e94a3SBarry Smith        if not os.path.isdir(self.argDB['package-prefix-hash']):
146*d3c8a501SBarry Smith          self.logPrint('Specified package-prefix-hash location %s not found! Attemping to create this dir!' % self.argDB['package-prefix-hash'])
147be5c6b33SBarry Smith          try:
14820a7ad26SSatish Balay            os.makedirs(self.argDB['package-prefix-hash'])
149be5c6b33SBarry Smith          except Exception as e:
15020a7ad26SSatish Balay            self.logPrint('Error creating package-prefix-hash directory '+self.argDB['package-prefix-hash']+': '+str(e))
151*d3c8a501SBarry Smith            raise RuntimeError('You must have write permission to create prefix directory '+self.argDB['package-prefix-hash'])
15220a7ad26SSatish Balay        status = False
15320a7ad26SSatish Balay        for idx in range(6,len(hprefix)):
15420a7ad26SSatish Balay          hashdirpackages = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:idx])
15520a7ad26SSatish Balay          hashfilepackages = os.path.join(hashdirpackages,'configure-hash')
15620a7ad26SSatish Balay          if os.path.isdir(hashdirpackages):
15720a7ad26SSatish Balay            if os.path.exists(hashfilepackages):
15820a7ad26SSatish Balay              self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild
15920a7ad26SSatish Balay              status = True
16020a7ad26SSatish Balay              break
16120a7ad26SSatish Balay            else: continue # perhaps an incomplete build? use a longer hash
162bf3e94a3SBarry Smith          else:
163bf3e94a3SBarry Smith            try:
16420a7ad26SSatish Balay              os.mkdir(hashdirpackages)
16520a7ad26SSatish Balay            except Exception as e:
16620a7ad26SSatish Balay              self.logPrint('Error creating package-prefix-hash directory '+hashdirpackages+': '+str(e))
16720a7ad26SSatish Balay              raise RuntimeError('You must have write permission on --package-prefix-hash='+self.argDB['package-prefix-hash']+' directory')
16820a7ad26SSatish Balay            status = True
16920a7ad26SSatish Balay            break
17020a7ad26SSatish Balay        if not status:
17120a7ad26SSatish 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]) )
17220a7ad26SSatish Balay        self.argDB['prefix'] = hashdirpackages
173bf3e94a3SBarry Smith
174bf3e94a3SBarry Smith    hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash')
175bf3e94a3SBarry Smith
176dd328ec0SBarry Smith    if self.argDB['force']:
177bf3e94a3SBarry Smith      self.logPrint('Forcing a new configuration requested by use')
178a952ef13SBarry Smith      self.makeDependency(hash,hashfile,hashfilepackages)
179dd328ec0SBarry Smith      return
180dd328ec0SBarry Smith    a = ''
181dd328ec0SBarry Smith    try:
182f8357408SBarry Smith      with open(hashfile, 'r') as f:
183dd328ec0SBarry Smith        a = f.read()
184dd328ec0SBarry Smith    except:
185bf3e94a3SBarry Smith      self.logPrint('No previous hashfile found')
186bf3e94a3SBarry Smith      self.makeDependency(hash,hashfile,hashfilepackages)
187dd328ec0SBarry Smith      return
188dd328ec0SBarry Smith    if a == hash:
189bf3e94a3SBarry Smith      try:
190bf3e94a3SBarry Smith        self.logPrint('Attempting to save lib/petsc/conf/petscvariables file')
191bf3e94a3SBarry Smith        with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g:
192bf3e94a3SBarry Smith          g.write('PETSC_ARCH='+self.arch+'\n')
193bf3e94a3SBarry Smith          g.write('PETSC_DIR='+self.petscdir.dir+'\n')
194bf3e94a3SBarry Smith          g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n')
195bf3e94a3SBarry Smith          self.logPrint('Saved lib/petsc/conf/petscvariables file')
196bf3e94a3SBarry Smith      except:
197bf3e94a3SBarry Smith        self.logPrint('Unable to save lib/petsc/conf/petscvariables file')
198f8357408SBarry Smith      self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.')
199dd328ec0SBarry Smith      print('Your configure options and state has not changed; no need to run configure')
200dd328ec0SBarry Smith      print('However you can force a configure run using the option: --force')
2015b4fc442SVaclav Hapla
2025b4fc442SVaclav Hapla      from config.packages.make import getMakeUserPath
2035b4fc442SVaclav Hapla      print('xxx=========================================================================xxx')
2045b4fc442SVaclav Hapla      print(' Build PETSc libraries with:')
2055b4fc442SVaclav Hapla      print('   %s PETSC_DIR=%s PETSC_ARCH=%s all' % (getMakeUserPath(self.arch), self.petscdir.dir, self.arch))
2065b4fc442SVaclav Hapla      print('xxx=========================================================================xxx')
207dd328ec0SBarry Smith      sys.exit()
208ae46fe3bSBarry Smith    self.logPrint('configure hash file: '+hashfile+' does not match, need to run configure')
209bf3e94a3SBarry Smith    self.makeDependency(hash,hashfile,hashfilepackages)
210dd328ec0SBarry Smith
2119d310bb7SBarry Smith  def configure(self):
2121a8e9eaeSSatish Balay    self.executeTest(self.setNativeArchitecture)
2139d310bb7SBarry Smith    self.executeTest(self.configureArchitecture)
2149d310bb7SBarry Smith    # required by top-level configure.py
2159d310bb7SBarry Smith    self.framework.arch = self.arch
216dd328ec0SBarry Smith    self.checkDependency()
2179d310bb7SBarry Smith    return
218