xref: /petsc/config/PETSc/options/arch.py (revision bf3e94a389f1b8e911c22b5a9785d79b6bf6a258)
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 ''
159d310bb7SBarry Smith    desc = ['PETSc:']
169d310bb7SBarry Smith    desc.append('  PETSC_ARCH: '+str(self.arch))
179d310bb7SBarry Smith    return '\n'.join(desc)+'\n'
189d310bb7SBarry Smith
199d310bb7SBarry Smith  def setupHelp(self, help):
209d310bb7SBarry Smith    import nargs
219d310bb7SBarry Smith    help.addArgument('PETSc', '-PETSC_ARCH=<string>',     nargs.Arg(None, None, 'The configuration name'))
229d310bb7SBarry Smith    help.addArgument('PETSc', '-with-petsc-arch=<string>',nargs.Arg(None, None, 'The configuration name'))
23dd328ec0SBarry Smith    help.addArgument('PETSc', '-force=<bool>',            nargs.ArgBool(None, 0, 'Bypass configure hash caching, and run to completion'))
24dd328ec0SBarry Smith    return
25dd328ec0SBarry Smith
26dd328ec0SBarry Smith  def setupDependencies(self, framework):
27dd328ec0SBarry Smith    self.sourceControl = framework.require('config.sourceControl',self)
28dd328ec0SBarry Smith    self.petscdir = framework.require('PETSc.options.petscdir', self)
299d310bb7SBarry Smith    return
309d310bb7SBarry Smith
311a8e9eaeSSatish Balay  def setNativeArchitecture(self):
3270211a5bSSatish Balay    import sys
3370211a5bSSatish Balay    arch = 'arch-' + sys.platform.replace('cygwin','mswin')
3470211a5bSSatish Balay    # use opt/debug, c/c++ tags.s
3570211a5bSSatish Balay    arch+= '-'+self.framework.argDB['with-clanguage'].lower().replace('+','x')
3670211a5bSSatish Balay    if self.framework.argDB['with-debugging']:
3770211a5bSSatish Balay      arch += '-debug'
3870211a5bSSatish Balay    else:
3970211a5bSSatish Balay      arch += '-opt'
401a8e9eaeSSatish Balay    self.nativeArch = arch
411a8e9eaeSSatish Balay    return
4270211a5bSSatish Balay
439d310bb7SBarry Smith  def configureArchitecture(self):
449d310bb7SBarry Smith    '''Checks PETSC_ARCH and sets if not set'''
45*bf3e94a3SBarry Smith    # Warn if PETSC_ARCH doesn't match env variable
469d310bb7SBarry Smith    if 'PETSC_ARCH' in self.framework.argDB and 'PETSC_ARCH' in os.environ and self.framework.argDB['PETSC_ARCH'] != os.environ['PETSC_ARCH']:
479d310bb7SBarry Smith      self.logPrintBox('''\
489d310bb7SBarry SmithWarning: PETSC_ARCH from environment does not match command-line or name of script.
499d310bb7SBarry SmithWarning: Using from command-line or name of script: %s, ignoring environment: %s''' % (str(self.framework.argDB['PETSC_ARCH']), str(os.environ['PETSC_ARCH'])))
5057ea55fdSJed Brown      os.environ['PETSC_ARCH'] = self.framework.argDB['PETSC_ARCH']
519d310bb7SBarry Smith    if 'with-petsc-arch' in self.framework.argDB:
529d310bb7SBarry Smith      self.arch = self.framework.argDB['with-petsc-arch']
5370211a5bSSatish Balay      msg = 'option -with-petsc-arch='+str(self.arch)
549d310bb7SBarry Smith    elif 'PETSC_ARCH' in self.framework.argDB:
559d310bb7SBarry Smith      self.arch = self.framework.argDB['PETSC_ARCH']
5670211a5bSSatish Balay      msg = 'option PETSC_ARCH='+str(self.arch)
5770211a5bSSatish Balay    elif 'PETSC_ARCH' in os.environ:
589d310bb7SBarry Smith      self.arch = os.environ['PETSC_ARCH']
5970211a5bSSatish Balay      msg = 'environment variable PETSC_ARCH='+str(self.arch)
609d310bb7SBarry Smith    else:
611a8e9eaeSSatish Balay      self.arch = self.nativeArch
629d310bb7SBarry Smith    if self.arch.find('/') >= 0 or self.arch.find('\\') >= 0:
6370211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not contain path characters, but you have specified with '+msg)
64002ae2c9SLisandro Dalcin    if self.arch.startswith('-'):
6570211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with "-", but you have specified with '+msg)
6670211a5bSSatish Balay    if self.arch.startswith('.'):
6770211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH should not start with ".", but you have specified with '+msg)
6870211a5bSSatish Balay    if not len(self.arch):
6970211a5bSSatish Balay      raise RuntimeError('PETSC_ARCH cannot be empty string. Use a valid string or do not set one. Currently set with '+msg)
709d310bb7SBarry Smith    self.archBase = re.sub(r'^(\w+)[-_]?.*$', r'\1', self.arch)
719d310bb7SBarry Smith    return
729d310bb7SBarry Smith
73*bf3e94a3SBarry Smith  def makeDependency(self,hash,hashfile,hashfilepackages):
74*bf3e94a3SBarry Smith    '''Deletes the current hashfile and saves the hashfile names and its value in framework so that'''
75f8357408SBarry Smith    '''framework.Configure can create the file upon success of configure'''
76dd328ec0SBarry Smith    import os
77f8357408SBarry Smith    if hash:
78f8357408SBarry Smith      self.framework.hash = hash
79f8357408SBarry Smith      self.framework.hashfile = hashfile
80*bf3e94a3SBarry Smith      self.logPrint('Setting hashfile: '+hashfile)
81*bf3e94a3SBarry Smith      if hashfilepackages: self.framework.hashfilepackages = hashfilepackages
82dd328ec0SBarry Smith    try:
83*bf3e94a3SBarry Smith      self.logPrint('Deleting configure hash file: '+hashfile)
84f8357408SBarry Smith      os.remove(hashfile)
85*bf3e94a3SBarry Smith      self.logPrint('Deleted configure hash file: '+hashfile)
86dd328ec0SBarry Smith    except:
87f8357408SBarry Smith      self.logPrint('Unable to delete configure hash file: '+hashfile)
88*bf3e94a3SBarry Smith
89dd328ec0SBarry Smith
90dd328ec0SBarry Smith  def checkDependency(self):
91dd328ec0SBarry Smith    '''Checks if files in config have changed, the command line options have changed or the PATH has changed'''
92*bf3e94a3SBarry Smith    '''  By default - checks if configure needs to be run'''
93*bf3e94a3SBarry Smith    '''  If --arch-hash it manages the same information but it:'''
94*bf3e94a3SBarry Smith    '''     * computes a short hash for the configuration <hashvalue>'''
95*bf3e94a3SBarry Smith    '''     * sets self.arch and PETSC_ARCH to arch-<hashvalue>'''
96*bf3e94a3SBarry Smith    '''       This results in the downloaded packages being installed once to the arch-<hasvalue> directory'''
97*bf3e94a3SBarry Smith    '''       and a new directory with a different hash is created if the configuration changes.'''
98*bf3e94a3SBarry Smith    '''     This mode is intended mostly for testing to reduce reconfigure and recompile times (not currently used)'''
99*bf3e94a3SBarry Smith    '''  If --package-prefix-hash=directory is provided'''
100*bf3e94a3SBarry Smith    '''     * computes a short hash for the configuration <hashvalue>'''
101*bf3e94a3SBarry Smith    '''     * puts the downloaded external packages into location directory/hash'''
102*bf3e94a3SBarry Smith    '''       This results in the downloaded packages being installed once'''
103*bf3e94a3SBarry Smith    '''       and a new directory with a different hash is created if the configuration changes.'''
104*bf3e94a3SBarry Smith    '''     This mode is intended mostly for testing to reduce time of reinstalling external packages'''
105dd328ec0SBarry Smith    import os
106dd328ec0SBarry Smith    import sys
107dd328ec0SBarry Smith    import hashlib
108b60faad8SJed Brown    args = sorted(set(filter(lambda x: not (x.startswith('PETSC_ARCH') or x == '--force'),sys.argv[1:])))
109b60faad8SJed Brown    hash = 'args:\n' + '\n'.join('    '+a for a in args) + '\n'
110b60faad8SJed Brown    hash += 'PATH=' + os.environ.get('PATH', '') + '\n'
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:
120b60faad8SJed Brown            hash += 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
124*bf3e94a3SBarry Smith
125*bf3e94a3SBarry Smith    hashfilepackages = None
126*bf3e94a3SBarry Smith    # Generate short hash to use for the arch so the same arch can be reused if the configuration files don't change
127*bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB:
128*bf3e94a3SBarry Smith      if self.argDB['prefix']:
129*bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --prefix and --arch-hash')
130*bf3e94a3SBarry Smith      if hasattr(self.argDB,'PETSC_ARCH'):
131*bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide PETSC_ARCH and --arch-hash')
132*bf3e94a3SBarry Smith      if 'package-prefix-hash' in self.argDB:
133*bf3e94a3SBarry Smith        raise RuntimeError('Cannot provide --arch-hash and --package-prefix-hash')
134*bf3e94a3SBarry Smith      if os.getenv('PETSC_ARCH'):
135*bf3e94a3SBarry Smith        raise RuntimeError('Do not set the environmental variable PETSC_ARCH and use --arch-hash')
136*bf3e94a3SBarry Smith    if 'arch-hash' in self.argDB or 'package-prefix-hash' in self.argDB:
137*bf3e94a3SBarry Smith      import hashlib
138*bf3e94a3SBarry Smith      m = hashlib.md5()
139*bf3e94a3SBarry Smith      m.update(hash)
140*bf3e94a3SBarry Smith      hprefix = m.hexdigest()
141*bf3e94a3SBarry Smith      if 'arch-hash' in self.argDB:
142*bf3e94a3SBarry Smith        self.argDB['PETSC_ARCH'] = 'arch-'+hprefix[0:6]
143*bf3e94a3SBarry Smith        self.arch = 'arch-'+hprefix[0:6]
144*bf3e94a3SBarry Smith      else:
145*bf3e94a3SBarry Smith        if not os.path.isdir(self.argDB['package-prefix-hash']):
146*bf3e94a3SBarry Smith          raise RuntimeError('--package-prefix-hash '+self.argDB['package-prefix-hash']+' directory does not exist\n')
147*bf3e94a3SBarry Smith        self.argDB['prefix'] = os.path.join(self.argDB['package-prefix-hash'],hprefix[0:6])
148*bf3e94a3SBarry Smith        if not os.path.isdir(self.argDB['prefix']):
149*bf3e94a3SBarry Smith          os.mkdir(self.argDB['prefix'])
150*bf3e94a3SBarry Smith          hashfilepackages = os.path.join(self.argDB['prefix'],'configure-hash')
151*bf3e94a3SBarry Smith        else:
152*bf3e94a3SBarry Smith          try:
153*bf3e94a3SBarry Smith            with open(os.path.join(self.argDB['prefix'],'configure-hash'), 'r') as f:
154*bf3e94a3SBarry Smith              a = f.read()
155*bf3e94a3SBarry Smith          except:
156*bf3e94a3SBarry Smith            self.logPrint('No previous hashfilepackages found')
157*bf3e94a3SBarry Smith            a = ''
158*bf3e94a3SBarry Smith          if a == hash:
159*bf3e94a3SBarry Smith            self.logPrint('Reusing download packages in '+self.argDB['prefix'])
160*bf3e94a3SBarry Smith            self.argDB['package-prefix-hash'] = 'reuse' # indicates prefix libraries already built, no need to rebuild
161*bf3e94a3SBarry Smith
162*bf3e94a3SBarry Smith    hashfile = os.path.join(self.arch,'lib','petsc','conf','configure-hash')
163*bf3e94a3SBarry Smith
164dd328ec0SBarry Smith    if self.argDB['force']:
165*bf3e94a3SBarry Smith      self.logPrint('Forcing a new configuration requested by use')
166*bf3e94a3SBarry Smith      self.makeDependency(hash,hashfile,None)
167dd328ec0SBarry Smith      return
168dd328ec0SBarry Smith    a = ''
169dd328ec0SBarry Smith    try:
170f8357408SBarry Smith      with open(hashfile, 'r') as f:
171dd328ec0SBarry Smith        a = f.read()
172dd328ec0SBarry Smith    except:
173*bf3e94a3SBarry Smith      self.logPrint('No previous hashfile found')
174*bf3e94a3SBarry Smith      self.makeDependency(hash,hashfile,hashfilepackages)
175dd328ec0SBarry Smith      return
176dd328ec0SBarry Smith    if a == hash:
177*bf3e94a3SBarry Smith      try:
178*bf3e94a3SBarry Smith        self.logPrint('Attempting to save lib/petsc/conf/petscvariables file')
179*bf3e94a3SBarry Smith        with open(os.path.join('lib','petsc','conf','petscvariables'), 'w') as g:
180*bf3e94a3SBarry Smith          g.write('PETSC_ARCH='+self.arch+'\n')
181*bf3e94a3SBarry Smith          g.write('PETSC_DIR='+self.petscdir.dir+'\n')
182*bf3e94a3SBarry Smith          g.write('include $(PETSC_DIR)/$(PETSC_ARCH)/lib/petsc/conf/petscvariables\n')
183*bf3e94a3SBarry Smith          self.logPrint('Saved lib/petsc/conf/petscvariables file')
184*bf3e94a3SBarry Smith      except:
185*bf3e94a3SBarry Smith        self.logPrint('Unable to save lib/petsc/conf/petscvariables file')
186f8357408SBarry Smith      self.logPrint('configure hash file: '+hashfile+' matches; no need to run configure.')
187dd328ec0SBarry Smith      print('Your configure options and state has not changed; no need to run configure')
188dd328ec0SBarry Smith      print('However you can force a configure run using the option: --force')
189dd328ec0SBarry Smith      sys.exit()
190f8357408SBarry Smith    self.logPrint('configure hash file: '+hashfile+' does not match\n'+a+'\n---\n'+hash+'\n need to run configure')
191*bf3e94a3SBarry Smith    self.makeDependency(hash,hashfile,hashfilepackages)
192dd328ec0SBarry Smith
1939d310bb7SBarry Smith  def configure(self):
1941a8e9eaeSSatish Balay    self.executeTest(self.setNativeArchitecture)
1959d310bb7SBarry Smith    self.executeTest(self.configureArchitecture)
1969d310bb7SBarry Smith    # required by top-level configure.py
1979d310bb7SBarry Smith    self.framework.arch = self.arch
198dd328ec0SBarry Smith    self.checkDependency()
1999d310bb7SBarry Smith    return
200