xref: /petsc/config/configure.py (revision 2c294110b7329cf2b41d0e5a915526cf08ac0efd)
1#!/usr/bin/env python
2import os, sys
3import commands
4# to load ~/.pythonrc.py before inserting correct BuildSystem to path
5import user
6extraLogs = []
7petsc_arch = ''
8
9# Use en_US as language so that BuildSystem parses compiler messages in english
10if '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'
11if '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'
12
13if not hasattr(sys, 'version_info') or not sys.version_info[0] == 2 or not sys.version_info[1] >= 4:
14  print '*** You must have Python2 version 2.4 or higher to run ./configure        *****'
15  print '*          Python is easy to install for end users or sys-admin.              *'
16  print '*                  http://www.python.org/download/                            *'
17  print '*                                                                             *'
18  print '*           You CANNOT configure PETSc without Python                         *'
19  print '*   http://www.mcs.anl.gov/petsc/documentation/installation.html     *'
20  print '*******************************************************************************'
21  sys.exit(4)
22
23def check_for_option_mistakes(opts):
24  for opt in opts[1:]:
25    name = opt.split('=')[0]
26    if name.find('_') >= 0:
27      exception = False
28      for exc in ['mkl_cpardiso', 'mkl_pardiso', 'superlu_dist', 'superlu_mt', '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','int64_t']:
29        if name.find(exc) >= 0:
30          exception = True
31      if not exception:
32        raise ValueError('The option '+name+' should probably be '+name.replace('_', '-'));
33    if opt.find('=') >=0:
34      optval = opt.split('=')[1]
35      if optval == 'ifneeded':
36        raise ValueError('The option '+opt+' should probably be '+opt.replace('ifneeded', '1'));
37  return
38
39def check_for_unsupported_combinations(opts):
40  if '--with-precision=single' in opts and '--with-clanguage=cxx' in opts and '--with-scalar-type=complex' in opts:
41    sys.exit(ValueError('PETSc does not support single precision complex with C++ clanguage, run with --with-clanguage=c'))
42
43def check_for_option_changed(opts):
44# Document changes in command line options here.
45  optMap = [('with-64bit-indices','with-64-bit-indices'),('c-blas-lapack','f2cblaslapack'),('cholmod','suitesparse'),('umfpack','suitesparse'),('f-blas-lapack','fblaslapack')]
46  for opt in opts[1:]:
47    optname = opt.split('=')[0].strip('-')
48    for oldname,newname in optMap:
49      if optname.find(oldname) >=0:
50        raise ValueError('The option '+opt+' should probably be '+opt.replace(oldname,newname))
51  return
52
53def check_petsc_arch(opts):
54  # If PETSC_ARCH not specified - use script name (if not configure.py)
55  global petsc_arch
56  found = 0
57  for name in opts:
58    if name.find('PETSC_ARCH=') >= 0:
59      petsc_arch=name.split('=')[1]
60      found = 1
61      break
62  # If not yet specified - use the filename of script
63  if not found:
64      filename = os.path.basename(sys.argv[0])
65      if not filename.startswith('configure') and not filename.startswith('reconfigure') and not filename.startswith('setup'):
66        petsc_arch=os.path.splitext(os.path.basename(sys.argv[0]))[0]
67        useName = 'PETSC_ARCH='+petsc_arch
68        opts.append(useName)
69  return 0
70
71def chkenable():
72  #Replace all 'enable-'/'disable-' with 'with-'=0/1/tail
73  #enable-fortran is a special case, the resulting --with-fortran is ambiguous.
74  #Would it mean --with-fc= or --with-fortran-interfaces=?
75  for l in range(0,len(sys.argv)):
76    name = sys.argv[l]
77    if name.find('enable-fortran') >= 0:
78      if name.find('=') == -1:
79        sys.argv[l] = name.replace('enable-fortran','with-fortran-interfaces')+'=1'
80      else:
81        head, tail = name.split('=', 1)
82        sys.argv[l] = head.replace('enable-fortran','with-fortran-interfaces')+'='+tail
83      continue
84    if name.find('disable-fortran') >= 0:
85      if name.find('=') == -1:
86        sys.argv[l] = name.replace('disable-fortran','with-fortran-interfaces')+'=0'
87      else:
88        head, tail = name.split('=', 1)
89        if tail == '1': tail = '0'
90        sys.argv[l] = head.replace('disable-fortran','with-fortran-interfaces')+'='+tail
91      continue
92
93    if name.find('enable-cxx') >= 0:
94      if name.find('=') == -1:
95        sys.argv[l] = name.replace('enable-cxx','with-clanguage=C++')
96      else:
97        head, tail = name.split('=', 1)
98        if tail=='0':
99          sys.argv[l] = head.replace('enable-cxx','with-clanguage=C')
100        else:
101          sys.argv[l] = head.replace('enable-cxx','with-clanguage=C++')
102      continue
103    if name.find('disable-cxx') >= 0:
104      if name.find('=') == -1:
105        sys.argv[l] = name.replace('disable-cxx','with-clanguage=C')
106      else:
107        head, tail = name.split('=', 1)
108        if tail == '0':
109          sys.argv[l] = head.replace('disable-cxx','with-clanguage=C++')
110        else:
111          sys.argv[l] = head.replace('disable-cxx','with-clanguage=C')
112      continue
113
114
115    if name.find('enable-') >= 0:
116      if name.find('=') == -1:
117        sys.argv[l] = name.replace('enable-','with-')+'=1'
118      else:
119        head, tail = name.split('=', 1)
120        sys.argv[l] = head.replace('enable-','with-')+'='+tail
121    if name.find('disable-') >= 0:
122      if name.find('=') == -1:
123        sys.argv[l] = name.replace('disable-','with-')+'=0'
124      else:
125        head, tail = name.split('=', 1)
126        if tail == '1': tail = '0'
127        sys.argv[l] = head.replace('disable-','with-')+'='+tail
128    if name.find('without-') >= 0:
129      if name.find('=') == -1:
130        sys.argv[l] = name.replace('without-','with-')+'=0'
131      else:
132        head, tail = name.split('=', 1)
133        if tail == '1': tail = '0'
134        sys.argv[l] = head.replace('without-','with-')+'='+tail
135
136
137def chksynonyms():
138  #replace common configure options with ones that PETSc BuildSystem recognizes
139  for l in range(0,len(sys.argv)):
140    name = sys.argv[l]
141
142
143    if name.find('with-debug=') >= 0 or name.endswith('with-debug'):
144      if name.find('=') == -1:
145        sys.argv[l] = name.replace('with-debug','with-debugging')+'=1'
146      else:
147        head, tail = name.split('=', 1)
148        sys.argv[l] = head.replace('with-debug','with-debugging')+'='+tail
149
150    if name.find('with-shared=') >= 0 or name.endswith('with-shared'):
151      if name.find('=') == -1:
152        sys.argv[l] = name.replace('with-shared','with-shared-libraries')+'=1'
153      else:
154        head, tail = name.split('=', 1)
155        sys.argv[l] = head.replace('with-shared','with-shared-libraries')+'='+tail
156
157    if name.find('with-index-size=') >=0:
158      head,tail = name.split('=',1)
159      if int(tail)==32:
160        sys.argv[l] = '--with-64-bit-indices=0'
161      elif int(tail)==64:
162        sys.argv[l] = '--with-64-bit-indices=1'
163      else:
164        raise RuntimeError('--with-index-size= must be 32 or 64')
165
166    if name.find('with-precision=') >=0:
167      head,tail = name.split('=',1)
168      if tail.find('quad')>=0:
169        sys.argv[l]='--with-precision=__float128'
170
171
172def chkwinf90():
173  for arg in sys.argv:
174    if (arg.find('win32fe') >= 0 and (arg.find('f90') >=0 or arg.find('ifort') >=0)):
175      return 1
176  return 0
177
178def chkdosfiles():
179  # cygwin - but not a hg clone - so check one of files in bin dir
180  if "\r\n" in open(os.path.join('bin','petscmpiexec'),"rb").read():
181    print '==============================================================================='
182    print ' *** Scripts are in DOS mode. Was winzip used to extract petsc sources?    ****'
183    print ' *** Please restart with a fresh tarball and use "tar -xzf petsc.tar.gz"   ****'
184    print '==============================================================================='
185    sys.exit(3)
186  return
187
188def chkcygwinlink():
189  if os.path.exists('/usr/bin/cygcheck.exe') and os.path.exists('/usr/bin/link.exe') and chkwinf90():
190      if '--ignore-cygwin-link' in sys.argv: return 0
191      print '==============================================================================='
192      print ' *** Cygwin /usr/bin/link detected! Compiles with CVF/Intel f90 can break!  **'
193      print ' *** To workarround do: "mv /usr/bin/link.exe /usr/bin/link-cygwin.exe"     **'
194      print ' *** Or to ignore this check, use configure option: --ignore-cygwin-link    **'
195      print '==============================================================================='
196      sys.exit(3)
197  return 0
198
199def chkbrokencygwin():
200  if os.path.exists('/usr/bin/cygcheck.exe'):
201    buf = os.popen('/usr/bin/cygcheck.exe -c cygwin').read()
202    if buf.find('1.5.11-1') > -1:
203      print '==============================================================================='
204      print ' *** cygwin-1.5.11-1 detected. ./configure fails with this version ***'
205      print ' *** Please upgrade to cygwin-1.5.12-1 or newer version. This can  ***'
206      print ' *** be done by running cygwin-setup, selecting "next" all the way.***'
207      print '==============================================================================='
208      sys.exit(3)
209  return 0
210
211def chkusingwindowspython():
212  if sys.platform == 'win32':
213    print '==============================================================================='
214    print ' *** Windows python detected. Please rerun ./configure with cygwin-python. ***'
215    print '==============================================================================='
216    sys.exit(3)
217  return 0
218
219def chkcygwinpython():
220  if sys.platform == 'cygwin' :
221    import platform
222    import re
223    r=re.compile("([0-9]+).([0-9]+).([0-9]+)")
224    m=r.match(platform.release())
225    major=int(m.group(1))
226    minor=int(m.group(2))
227    subminor=int(m.group(3))
228    if ((major < 1) or (major == 1 and minor < 7) or (major == 1 and minor == 7 and subminor < 34)):
229      sys.argv.append('--useThreads=0')
230      extraLogs.append('''\
231===============================================================================
232** Cygwin version is older than 1.7.34. Python threads do not work correctly. ***
233** Disabling thread usage for this run of ./configure *******
234===============================================================================''')
235  return 0
236
237def chkrhl9():
238  if os.path.exists('/etc/redhat-release'):
239    try:
240      file = open('/etc/redhat-release','r')
241      buf = file.read()
242      file.close()
243    except:
244      # can't read file - assume dangerous RHL9
245      buf = 'Shrike'
246    if buf.find('Shrike') > -1:
247      sys.argv.append('--useThreads=0')
248      extraLogs.append('''\
249==============================================================================
250   *** RHL9 detected. Threads do not work correctly with this distribution ***
251   ****** Disabling thread usage for this run of ./configure *********
252===============================================================================''')
253  return 0
254
255def check_broken_configure_log_links():
256  '''Sometime symlinks can get broken if the original files are deleted. Delete such broken links'''
257  import os
258  for logfile in ['configure.log','configure.log.bkp']:
259    if os.path.islink(logfile) and not os.path.isfile(logfile): os.remove(logfile)
260  return
261
262def move_configure_log(framework):
263  '''Move configure.log to PETSC_ARCH/lib/petsc/conf - and update configure.log.bkp in both locations appropriately'''
264  global petsc_arch
265
266  if hasattr(framework,'arch'): petsc_arch = framework.arch
267  if hasattr(framework,'logName'): curr_file = framework.logName
268  else: curr_file = 'configure.log'
269
270  if petsc_arch:
271    import shutil
272    import os
273
274    # Just in case - confdir is not created
275    lib_dir = os.path.join(petsc_arch,'lib')
276    conf_dir = os.path.join(petsc_arch,'lib','petsc','conf')
277    if not os.path.isdir(petsc_arch): os.mkdir(petsc_arch)
278    if not os.path.isdir(lib_dir): os.mkdir(lib_dir)
279    if not os.path.isdir(conf_dir): os.mkdir(conf_dir)
280
281    curr_bkp  = curr_file + '.bkp'
282    new_file  = os.path.join(conf_dir,curr_file)
283    new_bkp   = new_file + '.bkp'
284
285    # Keep backup in $PETSC_ARCH/lib/petsc/conf location
286    if os.path.isfile(new_bkp): os.remove(new_bkp)
287    if os.path.isfile(new_file): os.rename(new_file,new_bkp)
288    if os.path.isfile(curr_file):
289      shutil.copyfile(curr_file,new_file)
290      os.remove(curr_file)
291    if os.path.isfile(new_file): os.symlink(new_file,curr_file)
292    # If the old bkp is using the same PETSC_ARCH/lib/petsc/conf - then update bkp link
293    if os.path.realpath(curr_bkp) == os.path.realpath(new_file):
294      if os.path.isfile(curr_bkp): os.remove(curr_bkp)
295      if os.path.isfile(new_bkp): os.symlink(new_bkp,curr_bkp)
296  return
297
298def print_final_timestamp(framework):
299  import time
300  framework.log.write(('='*80)+'\n')
301  framework.log.write('Finishing Configure Run at '+time.ctime(time.time())+'\n')
302  framework.log.write(('='*80)+'\n')
303  return
304
305def petsc_configure(configure_options):
306  try:
307    petscdir = os.environ['PETSC_DIR']
308    sys.path.append(os.path.join(petscdir,'bin'))
309    import petscnagupgrade
310    file     = os.path.join(petscdir,'.nagged')
311    if not petscnagupgrade.naggedtoday(file):
312      petscnagupgrade.currentversion(petscdir)
313  except:
314    pass
315  print '==============================================================================='
316  print '             Configuring PETSc to compile on your system                       '
317  print '==============================================================================='
318
319  try:
320    # Command line arguments take precedence (but don't destroy argv[0])
321    sys.argv = sys.argv[:1] + configure_options + sys.argv[1:]
322    check_for_option_mistakes(sys.argv)
323    check_for_option_changed(sys.argv)
324  except (TypeError, ValueError), e:
325    emsg = str(e)
326    if not emsg.endswith('\n'): emsg = emsg+'\n'
327    msg ='*******************************************************************************\n'\
328    +'                ERROR in COMMAND LINE ARGUMENT to ./configure \n' \
329    +'-------------------------------------------------------------------------------\n'  \
330    +emsg+'*******************************************************************************\n'
331    sys.exit(msg)
332  # check PETSC_ARCH
333  check_for_unsupported_combinations(sys.argv)
334  check_petsc_arch(sys.argv)
335  check_broken_configure_log_links()
336
337  #rename '--enable-' to '--with-'
338  chkenable()
339  # support a few standard configure option types
340  chksynonyms()
341  # Check for broken cygwin
342  chkbrokencygwin()
343  # Disable threads on RHL9
344  chkrhl9()
345  # Make sure cygwin-python is used on windows
346  chkusingwindowspython()
347  # Threads don't work for cygwin & python...
348  chkcygwinpython()
349  chkcygwinlink()
350  chkdosfiles()
351
352  # Should be run from the toplevel
353  configDir = os.path.abspath('config')
354  bsDir     = os.path.join(configDir, 'BuildSystem')
355  if not os.path.isdir(configDir):
356    raise RuntimeError('Run configure from $PETSC_DIR, not '+os.path.abspath('.'))
357  sys.path.insert(0, bsDir)
358  sys.path.insert(0, configDir)
359  import config.base
360  import config.framework
361  import cPickle
362
363  framework = None
364  try:
365    framework = config.framework.Framework(['--configModules=PETSc.Configure','--optionsModule=config.compilerOptions']+sys.argv[1:], loadArgDB = 0)
366    framework.setup()
367    framework.logPrint('\n'.join(extraLogs))
368    framework.configure(out = sys.stdout)
369    framework.storeSubstitutions(framework.argDB)
370    framework.argDB['configureCache'] = cPickle.dumps(framework)
371    framework.printSummary()
372    framework.argDB.save(force = True)
373    framework.logClear()
374    print_final_timestamp(framework)
375    framework.closeLog()
376    try:
377      move_configure_log(framework)
378    except:
379      # perhaps print an error about unable to shuffle logs?
380      pass
381    return 0
382  except (RuntimeError, config.base.ConfigureSetupError), e:
383    emsg = str(e)
384    if not emsg.endswith('\n'): emsg = emsg+'\n'
385    msg ='*******************************************************************************\n'\
386    +'         UNABLE to CONFIGURE with GIVEN OPTIONS    (see configure.log for details):\n' \
387    +'-------------------------------------------------------------------------------\n'  \
388    +emsg+'*******************************************************************************\n'
389    se = ''
390  except (TypeError, ValueError), e:
391    emsg = str(e)
392    if not emsg.endswith('\n'): emsg = emsg+'\n'
393    msg ='*******************************************************************************\n'\
394    +'                ERROR in COMMAND LINE ARGUMENT to ./configure \n' \
395    +'-------------------------------------------------------------------------------\n'  \
396    +emsg+'*******************************************************************************\n'
397    se = ''
398  except ImportError, e :
399    emsg = str(e)
400    if not emsg.endswith('\n'): emsg = emsg+'\n'
401    msg ='*******************************************************************************\n'\
402    +'                     UNABLE to FIND MODULE for ./configure \n' \
403    +'-------------------------------------------------------------------------------\n'  \
404    +emsg+'*******************************************************************************\n'
405    se = ''
406  except OSError, e :
407    emsg = str(e)
408    if not emsg.endswith('\n'): emsg = emsg+'\n'
409    msg ='*******************************************************************************\n'\
410    +'                    UNABLE to EXECUTE BINARIES for ./configure \n' \
411    +'-------------------------------------------------------------------------------\n'  \
412    +emsg+'*******************************************************************************\n'
413    se = ''
414  except SystemExit, e:
415    if e.code is None or e.code == 0:
416      return
417    msg ='*******************************************************************************\n'\
418    +'         CONFIGURATION FAILURE  (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \
419    +'*******************************************************************************\n'
420    se  = str(e)
421  except Exception, e:
422    msg ='*******************************************************************************\n'\
423    +'        CONFIGURATION CRASH  (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \
424    +'*******************************************************************************\n'
425    se  = str(e)
426
427  print msg
428  if not framework is None:
429    framework.logClear()
430    if hasattr(framework, 'log'):
431      try:
432        if hasattr(framework,'compilerDefines'):
433          framework.log.write('**** Configure header '+framework.compilerDefines+' ****\n')
434          framework.outputHeader(framework.log)
435        if hasattr(framework,'compilerFixes'):
436          framework.log.write('**** C specific Configure header '+framework.compilerFixes+' ****\n')
437          framework.outputCHeader(framework.log)
438      except Exception, e:
439        framework.log.write('Problem writing headers to log: '+str(e))
440      import traceback
441      try:
442        framework.log.write(msg+se)
443        traceback.print_tb(sys.exc_info()[2], file = framework.log)
444        print_final_timestamp(framework)
445        if hasattr(framework,'log'): framework.log.close()
446        move_configure_log(framework)
447      except:
448        pass
449      sys.exit(1)
450  else:
451    print se
452    import traceback
453    traceback.print_tb(sys.exc_info()[2])
454  if hasattr(framework,'log'): framework.log.close()
455
456if __name__ == '__main__':
457  petsc_configure([])
458
459