xref: /petsc/config/configure.py (revision 0700a8246d308f50502909ba325e6169d3ee27eb)
1#!/usr/bin/env python
2import os
3import sys
4import commands
5# to load ~/.pythonrc.py before inserting correct BuildSystem to path
6import user
7extraLogs = []
8petsc_arch = ''
9
10# Use en_US as language so that BuildSystem parses compiler messages in english
11if 'LC_LOCAL' in os.environ and os.environ['LC_LOCAL'] != '' and os.environ['LC_LOCAL'] != 'en_US' and os.environ['LC_LOCAL']!= 'en_US.UTF-8': os.environ['LC_LOCAL'] = 'en_US.UTF-8'
12if 'LANG' in os.environ and os.environ['LANG'] != '' and os.environ['LANG'] != 'en_US' and os.environ['LANG'] != 'en_US.UTF-8': os.environ['LANG'] = 'en_US.UTF-8'
13
14if not hasattr(sys, 'version_info') or not sys.version_info[1] >= 2 or not sys.version_info[0] >= 2:
15  print '*** You must have Python version 2.2 or higher to run config/configure.py *****'
16  print '*          Python is easy to install for end users or sys-admin.              *'
17  print '*                  http://www.python.org/download/                            *'
18  print '*                                                                             *'
19  print '*           You CANNOT configure PETSc without Python                         *'
20  print '*   http://www.mcs.anl.gov/petsc/petsc-as/documentation/installation.html     *'
21  print '*******************************************************************************'
22  sys.exit(4)
23
24def check_for_option_mistakes(opts):
25  for opt in opts[1:]:
26    name = opt.split('=')[0]
27    if name.find('_') >= 0:
28      exception = False
29      for exc in ['superlu_dist', 'PETSC_ARCH', 'PETSC_DIR', 'CXX_CXXFLAGS', 'LD_SHARED', 'CC_LINKER_FLAGS', 'CXX_LINKER_FLAGS', 'FC_LINKER_FLAGS', 'AR_FLAGS', 'C_VERSION', 'CXX_VERSION', 'FC_VERSION', 'size_t', 'MPI_Comm','MPI_Fint']:
30        if name.find(exc) >= 0:
31          exception = True
32      if not exception:
33        raise ValueError('The option '+name+' should probably be '+name.replace('_', '-'));
34  return
35
36def check_petsc_arch(opts):
37  # If PETSC_ARCH not specified - use script name (if not configure.py)
38  global petsc_arch
39  found = 0
40  for name in opts:
41    if name.find('PETSC_ARCH=') >= 0:
42      petsc_arch=name.split('=')[1]
43      found = 1
44      break
45  # If not yet specified - use the filename of script
46  if not found:
47      filename = os.path.basename(sys.argv[0])
48      if not filename.startswith('configure') and not filename.startswith('reconfigure'):
49        petsc_arch=os.path.splitext(os.path.basename(sys.argv[0]))[0]
50        useName = 'PETSC_ARCH='+petsc_arch
51        opts.append(useName)
52  return 0
53
54def chkwinf90():
55  for arg in sys.argv:
56    if (arg.find('win32fe') >= 0 and (arg.find('f90') >=0 or arg.find('ifort') >=0)):
57      return 1
58  return 0
59
60def chkcygwinlink():
61  if os.path.exists('/usr/bin/cygcheck.exe') and os.path.exists('/usr/bin/link.exe') and chkwinf90():
62      if '--ignore-cygwin-link' in sys.argv: return 0
63      print '==============================================================================='
64      print ' *** Cygwin /usr/bin/link detected! Compiles with CVF/Intel f90 can break!  **'
65      print ' *** To workarround do: "mv /usr/bin/link.exe /usr/bin/link-cygwin.exe"     **'
66      print ' *** Or to ignore this check, use configure option: --ignore-cygwin-link    **'
67      print '==============================================================================='
68      sys.exit(3)
69  return 0
70
71def chkbrokencygwin():
72  if os.path.exists('/usr/bin/cygcheck.exe'):
73    buf = os.popen('/usr/bin/cygcheck.exe -c cygwin').read()
74    if buf.find('1.5.11-1') > -1:
75      print '==============================================================================='
76      print ' *** cygwin-1.5.11-1 detected. config/configure.py fails with this version ***'
77      print ' *** Please upgrade to cygwin-1.5.12-1 or newer version. This can  ***'
78      print ' *** be done by running cygwin-setup, selecting "next" all the way.***'
79      print '==============================================================================='
80      sys.exit(3)
81  return 0
82
83def chkusingwindowspython():
84  if os.path.exists('/usr/bin/cygcheck.exe') and sys.platform != 'cygwin':
85    print '==============================================================================='
86    print ' *** Non-cygwin python detected. Please rerun config/configure.py **'
87    print ' *** with cygwin-python. ***'
88    print '==============================================================================='
89    sys.exit(3)
90  return 0
91
92def chkcygwinpythonver():
93  if os.path.exists('/usr/bin/cygcheck.exe'):
94    buf = os.popen('/usr/bin/cygcheck.exe -c python').read()
95    if (buf.find('2.4') > -1) or (buf.find('2.5') > -1) or (buf.find('2.6') > -1):
96      sys.argv.append('--useThreads=0')
97      extraLogs.append('''\
98===============================================================================
99** Cygwin-python-2.4/2.5/2.6 detected. Threads do not work correctly with this
100** version. Disabling thread usage for this run of config/configure.py *******
101===============================================================================''')
102  return 0
103
104def chkrhl9():
105  if os.path.exists('/etc/redhat-release'):
106    try:
107      file = open('/etc/redhat-release','r')
108      buf = file.read()
109      file.close()
110    except:
111      # can't read file - assume dangerous RHL9
112      buf = 'Shrike'
113    if buf.find('Shrike') > -1:
114      sys.argv.append('--useThreads=0')
115      extraLogs.append('''\
116==============================================================================
117   *** RHL9 detected. Threads do not work correctly with this distribution ***
118   ****** Disabling thread usage for this run of config/configure.py *********
119===============================================================================''')
120  return 0
121
122def check_broken_configure_log_links():
123  '''Sometime symlinks can get broken if the original files are deleted. Delete such broken links'''
124  import os
125  for logfile in ['configure.log','configure.log.bkp']:
126    if os.path.islink(logfile) and not os.path.isfile(logfile): os.remove(logfile)
127  return
128
129def move_configure_log(framework):
130  '''Move configure.log to PETSC_ARCH/conf - and update configure.log.bkp in both locations appropriately'''
131  global petsc_arch
132
133  if hasattr(framework,'arch'): petsc_arch = framework.arch
134  if hasattr(framework,'logName'): curr_file = framework.logName
135  else: curr_file = 'configure.log'
136
137  if petsc_arch:
138    import shutil
139    import os
140
141    # Just in case - confdir is not created
142    conf_dir = os.path.join(petsc_arch,'conf')
143    if not os.path.isdir(petsc_arch): os.mkdir(petsc_arch)
144    if not os.path.isdir(conf_dir): os.mkdir(conf_dir)
145
146    curr_bkp  = curr_file + '.bkp'
147    new_file  = os.path.join(conf_dir,curr_file)
148    new_bkp   = new_file + '.bkp'
149
150    # Keep backup in $PETSC_ARCH/conf location
151    if os.path.isfile(new_bkp): os.remove(new_bkp)
152    if os.path.isfile(new_file): os.rename(new_file,new_bkp)
153    if os.path.isfile(curr_file):
154      shutil.copyfile(curr_file,new_file)
155      os.remove(curr_file)
156    if os.path.isfile(new_file): os.symlink(new_file,curr_file)
157    # If the old bkp is using the same PETSC_ARCH/conf - then update bkp link
158    if os.path.realpath(curr_bkp) == os.path.realpath(new_file):
159      if os.path.isfile(curr_bkp): os.remove(curr_bkp)
160      if os.path.isfile(new_bkp): os.symlink(new_bkp,curr_bkp)
161  return
162
163def petsc_configure(configure_options):
164  print '==============================================================================='
165  print '             Configuring PETSc to compile on your system                       '
166  print '==============================================================================='
167
168  # Command line arguments take precedence (but don't destroy argv[0])
169  sys.argv = sys.argv[:1] + configure_options + sys.argv[1:]
170  check_for_option_mistakes(sys.argv)
171  # check PETSC_ARCH
172  check_petsc_arch(sys.argv)
173  check_broken_configure_log_links()
174
175  # support a few standard configure option types
176  for l in range(0,len(sys.argv)):
177    name = sys.argv[l]
178    if name.find('enable-') >= 0:
179      if name.find('=') == -1:
180        sys.argv[l] = name.replace('enable-','with-')+'=1'
181      else:
182        head, tail = name.split('=', 1)
183        sys.argv[l] = head.replace('enable-','with-')+'='+tail
184    if name.find('disable-') >= 0:
185      if name.find('=') == -1:
186        sys.argv[l] = name.replace('disable-','with-')+'=0'
187      else:
188        head, tail = name.split('=', 1)
189        if tail == '1': tail = '0'
190        sys.argv[l] = head.replace('disable-','with-')+'='+tail
191    if name.find('without-') >= 0:
192      if name.find('=') == -1:
193        sys.argv[l] = name.replace('without-','with-')+'=0'
194      else:
195        head, tail = name.split('=', 1)
196        if tail == '1': tail = '0'
197        sys.argv[l] = head.replace('without-','with-')+'='+tail
198
199  # Check for broken cygwin
200  chkbrokencygwin()
201  # Disable threads on RHL9
202  chkrhl9()
203  # Make sure cygwin-python is used on windows
204  chkusingwindowspython()
205  # Threads don't work for cygwin & python-2.4, 2.5 etc..
206  chkcygwinpythonver()
207  chkcygwinlink()
208
209  # Should be run from the toplevel
210  configDir = os.path.abspath('config')
211  bsDir     = os.path.join(configDir, 'BuildSystem')
212  if not os.path.isdir(configDir):
213    raise RuntimeError('Run configure from $PETSC_DIR, not '+os.path.abspath('.'))
214  if not os.path.isdir(bsDir):
215    print '==============================================================================='
216    print '''++ Could not locate BuildSystem in %s.''' % configDir
217    print '''++ Downloading it using "hg clone http://hg.mcs.anl.gov/petsc/BuildSystem %s"''' % bsDir
218    print '==============================================================================='
219    (status,output) = commands.getstatusoutput('hg clone http://petsc.cs.iit.edu/petsc/BuildSystem '+ bsDir)
220    if status:
221      if output.find('ommand not found') >= 0:
222        print '==============================================================================='
223        print '''** Unable to locate hg (Mercurial) to download BuildSystem; make sure hg is'''
224        print '''** in your path or manually copy BuildSystem to $PETSC_DIR/config/BuildSystem'''
225        print '''**  from a machine where you do have hg installed and can clone BuildSystem. '''
226        print '==============================================================================='
227      elif output.find('Cannot resolve host') >= 0:
228        print '==============================================================================='
229        print '''** Unable to download BuildSystem. You must be off the network.'''
230        print '''** Connect to the internet and run config/configure.py again.'''
231        print '==============================================================================='
232      else:
233        print '==============================================================================='
234        print '''** Unable to download BuildSystem. Please send this message to petsc-maint@mcs.anl.gov'''
235        print '==============================================================================='
236      print output
237      sys.exit(3)
238
239  sys.path.insert(0, bsDir)
240  sys.path.insert(0, configDir)
241  import config.base
242  import config.framework
243  import cPickle
244
245  framework = None
246  try:
247    framework = config.framework.Framework(['--configModules=PETSc.Configure','--optionsModule=PETSc.compilerOptions']+sys.argv[1:], loadArgDB = 0)
248    framework.setup()
249    framework.logPrint('\n'.join(extraLogs))
250    framework.configure(out = sys.stdout)
251    framework.storeSubstitutions(framework.argDB)
252    framework.argDB['configureCache'] = cPickle.dumps(framework)
253    import PETSc.packages
254    for i in framework.packages:
255      if hasattr(i,'postProcess'):
256        i.postProcess()
257    framework.printSummary()
258    framework.logClear()
259    framework.closeLog()
260    try:
261      move_configure_log(framework)
262    except:
263      # perhaps print an error about unable to shuffle logs?
264      pass
265    return 0
266  except (RuntimeError, config.base.ConfigureSetupError), e:
267    emsg = str(e)
268    if not emsg.endswith('\n'): emsg = emsg+'\n'
269    msg ='*******************************************************************************\n'\
270    +'         UNABLE to CONFIGURE with GIVEN OPTIONS    (see configure.log for details):\n' \
271    +'-------------------------------------------------------------------------------\n'  \
272    +emsg+'*******************************************************************************\n'
273    se = ''
274  except (TypeError, ValueError), e:
275    emsg = str(e)
276    if not emsg.endswith('\n'): emsg = emsg+'\n'
277    msg ='*******************************************************************************\n'\
278    +'                ERROR in COMMAND LINE ARGUMENT to config/configure.py \n' \
279    +'-------------------------------------------------------------------------------\n'  \
280    +emsg+'*******************************************************************************\n'
281    se = ''
282  except ImportError, e :
283    emsg = str(e)
284    if not emsg.endswith('\n'): emsg = emsg+'\n'
285    msg ='*******************************************************************************\n'\
286    +'                     UNABLE to FIND MODULE for config/configure.py \n' \
287    +'-------------------------------------------------------------------------------\n'  \
288    +emsg+'*******************************************************************************\n'
289    se = ''
290  except OSError, e :
291    emsg = str(e)
292    if not emsg.endswith('\n'): emsg = emsg+'\n'
293    msg ='*******************************************************************************\n'\
294    +'                    UNABLE to EXECUTE BINARIES for config/configure.py \n' \
295    +'-------------------------------------------------------------------------------\n'  \
296    +emsg+'*******************************************************************************\n'
297    se = ''
298  except SystemExit, e:
299    if e.code is None or e.code == 0:
300      return
301    msg ='*******************************************************************************\n'\
302    +'         CONFIGURATION FAILURE  (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \
303    +'*******************************************************************************\n'
304    se  = str(e)
305  except Exception, e:
306    msg ='*******************************************************************************\n'\
307    +'        CONFIGURATION CRASH  (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \
308    +'*******************************************************************************\n'
309    se  = str(e)
310
311  print msg
312  if not framework is None:
313    framework.logClear()
314    if hasattr(framework, 'log'):
315      import traceback
316      try:
317        framework.log.write(msg+se)
318        traceback.print_tb(sys.exc_info()[2], file = framework.log)
319        close(framework.log)
320        move_configure_log(framework)
321      except:
322        pass
323      sys.exit(1)
324  else:
325    print se
326    import traceback
327    traceback.print_tb(sys.exc_info()[2])
328  close(framework.log)
329  move_configure_log(framework)
330
331if __name__ == '__main__':
332  petsc_configure([])
333
334