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 9import urllib 10import tarfile 11 12def untar(tar, path = '.', leading = ''): 13 if leading: 14 entries = [t.name for t in tar.getmembers()] 15 prefix = os.path.commonprefix(entries) 16 if prefix: 17 for tarinfo in tar.getmembers(): 18 tail = tarinfo.name.split(prefix, 1)[1] 19 tarinfo.name = os.path.join(leading, tail) 20 for tarinfo in tar.getmembers(): 21 tar.extract(tarinfo, path) 22 return 23 24def downloadPackage(url, filename, targetDirname): 25 '''Download the tarball for a package at url, save it as filename, and untar it into targetDirname''' 26 filename, headers = urllib.urlretrieve(url, filename) 27 tar = tarfile.open(filename, 'r:gz') 28 untar(tar, targetDirname, leading = filename.split('.')[0]) 29 return 30 31# Use en_US as language so that BuildSystem parses compiler messages in english 32if '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' 33if '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' 34 35if not hasattr(sys, 'version_info') or not sys.version_info[0] == 2 or not sys.version_info[1] >= 4: 36 print '*** You must have Python2 version 2.4 or higher to run ./configure *****' 37 print '* Python is easy to install for end users or sys-admin. *' 38 print '* http://www.python.org/download/ *' 39 print '* *' 40 print '* You CANNOT configure PETSc without Python *' 41 print '* http://www.mcs.anl.gov/petsc/documentation/installation.html *' 42 print '*******************************************************************************' 43 sys.exit(4) 44 45def check_for_option_mistakes(opts): 46 for opt in opts[1:]: 47 name = opt.split('=')[0] 48 if name.find('_') >= 0: 49 exception = False 50 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']: 51 if name.find(exc) >= 0: 52 exception = True 53 if not exception: 54 raise ValueError('The option '+name+' should probably be '+name.replace('_', '-')); 55 if opt.find('=') >=0: 56 optval = opt.split('=')[1] 57 if optval == 'ifneeded': 58 raise ValueError('The option '+opt+' should probably be '+opt.replace('ifneeded', '1')); 59 return 60 61def check_for_option_changed(opts): 62# Document changes in command line options here. 63 optMap = [('c-blas-lapack','f2cblaslapack')] 64 for opt in opts[1:]: 65 optname = opt.split('=')[0].strip('-') 66 for oldname,newname in optMap: 67 if optname.find(oldname) >=0: 68 raise ValueError('The option '+opt+' should probably be '+opt.replace(oldname,newname)) 69 return 70 71def check_petsc_arch(opts): 72 # If PETSC_ARCH not specified - use script name (if not configure.py) 73 global petsc_arch 74 found = 0 75 for name in opts: 76 if name.find('PETSC_ARCH=') >= 0: 77 petsc_arch=name.split('=')[1] 78 found = 1 79 break 80 # If not yet specified - use the filename of script 81 if not found: 82 filename = os.path.basename(sys.argv[0]) 83 if not filename.startswith('configure') and not filename.startswith('reconfigure') and not filename.startswith('setup'): 84 petsc_arch=os.path.splitext(os.path.basename(sys.argv[0]))[0] 85 useName = 'PETSC_ARCH='+petsc_arch 86 opts.append(useName) 87 return 0 88 89def chkwinf90(): 90 for arg in sys.argv: 91 if (arg.find('win32fe') >= 0 and (arg.find('f90') >=0 or arg.find('ifort') >=0)): 92 return 1 93 return 0 94 95def chkdosfiles(): 96 if not os.path.exists('/usr/bin/cygcheck.exe'): return 97 (status,output) = commands.getstatusoutput('hg showconfig paths.default') 98 if not status and output: return 99 # cygwin - but not a hg clone - so check files in bin dir 100 (status,output) = commands.getstatusoutput('file bin/*') 101 if status: 102 print '===============================================================================' 103 print ' *** Incomplete cygwin install? command "file" not found! **' 104 print '===============================================================================' 105 return 106 if output.find('with CRLF line terminators') >= 0: 107 print '===============================================================================' 108 print ' *** Scripts are in DOS mode. Was winzip used instead of tar? Converting.......' 109 print '===============================================================================' 110 (status,output) = commands.getstatusoutput('dos2unix bin/*') 111 if status: 112 print '===============================================================================' 113 print ' *** Incomplete cygwin install? command "dos2unix" not found! **' 114 print '===============================================================================' 115 return 116 117def chkcygwinlink(): 118 if os.path.exists('/usr/bin/cygcheck.exe') and os.path.exists('/usr/bin/link.exe') and chkwinf90(): 119 if '--ignore-cygwin-link' in sys.argv: return 0 120 print '===============================================================================' 121 print ' *** Cygwin /usr/bin/link detected! Compiles with CVF/Intel f90 can break! **' 122 print ' *** To workarround do: "mv /usr/bin/link.exe /usr/bin/link-cygwin.exe" **' 123 print ' *** Or to ignore this check, use configure option: --ignore-cygwin-link **' 124 print '===============================================================================' 125 sys.exit(3) 126 return 0 127 128def chkbrokencygwin(): 129 if os.path.exists('/usr/bin/cygcheck.exe'): 130 buf = os.popen('/usr/bin/cygcheck.exe -c cygwin').read() 131 if buf.find('1.5.11-1') > -1: 132 print '===============================================================================' 133 print ' *** cygwin-1.5.11-1 detected. ./configure fails with this version ***' 134 print ' *** Please upgrade to cygwin-1.5.12-1 or newer version. This can ***' 135 print ' *** be done by running cygwin-setup, selecting "next" all the way.***' 136 print '===============================================================================' 137 sys.exit(3) 138 return 0 139 140def chkcygwinpython(): 141 if os.path.exists('/usr/bin/cygcheck.exe') and sys.platform == 'cygwin' : 142 sys.argv.append('--useThreads=0') 143 extraLogs.append('''\ 144=============================================================================== 145** Cygwin-python detected. Threads do not work correctly. *** 146** Disabling thread usage for this run of ./configure ******* 147===============================================================================''') 148 return 0 149 150def chkrhl9(): 151 if os.path.exists('/etc/redhat-release'): 152 try: 153 file = open('/etc/redhat-release','r') 154 buf = file.read() 155 file.close() 156 except: 157 # can't read file - assume dangerous RHL9 158 buf = 'Shrike' 159 if buf.find('Shrike') > -1: 160 sys.argv.append('--useThreads=0') 161 extraLogs.append('''\ 162============================================================================== 163 *** RHL9 detected. Threads do not work correctly with this distribution *** 164 ****** Disabling thread usage for this run of ./configure ********* 165===============================================================================''') 166 return 0 167 168def check_broken_configure_log_links(): 169 '''Sometime symlinks can get broken if the original files are deleted. Delete such broken links''' 170 import os 171 for logfile in ['configure.log','configure.log.bkp']: 172 if os.path.islink(logfile) and not os.path.isfile(logfile): os.remove(logfile) 173 return 174 175def move_configure_log(framework): 176 '''Move configure.log to PETSC_ARCH/conf - and update configure.log.bkp in both locations appropriately''' 177 global petsc_arch 178 179 if hasattr(framework,'arch'): petsc_arch = framework.arch 180 if hasattr(framework,'logName'): curr_file = framework.logName 181 else: curr_file = 'configure.log' 182 183 if petsc_arch: 184 import shutil 185 import os 186 187 # Just in case - confdir is not created 188 conf_dir = os.path.join(petsc_arch,'conf') 189 if not os.path.isdir(petsc_arch): os.mkdir(petsc_arch) 190 if not os.path.isdir(conf_dir): os.mkdir(conf_dir) 191 192 curr_bkp = curr_file + '.bkp' 193 new_file = os.path.join(conf_dir,curr_file) 194 new_bkp = new_file + '.bkp' 195 196 # Keep backup in $PETSC_ARCH/conf location 197 if os.path.isfile(new_bkp): os.remove(new_bkp) 198 if os.path.isfile(new_file): os.rename(new_file,new_bkp) 199 if os.path.isfile(curr_file): 200 shutil.copyfile(curr_file,new_file) 201 os.remove(curr_file) 202 if os.path.isfile(new_file): os.symlink(new_file,curr_file) 203 # If the old bkp is using the same PETSC_ARCH/conf - then update bkp link 204 if os.path.realpath(curr_bkp) == os.path.realpath(new_file): 205 if os.path.isfile(curr_bkp): os.remove(curr_bkp) 206 if os.path.isfile(new_bkp): os.symlink(new_bkp,curr_bkp) 207 return 208 209def petsc_configure(configure_options): 210 try: 211 petscdir = os.environ['PETSC_DIR'] 212 sys.path.append(os.path.join(petscdir,'bin')) 213 import petscnagupgrade 214 file = os.path.join(petscdir,'.nagged') 215 if not petscnagupgrade.naggedtoday(file): 216 petscnagupgrade.currentversion(petscdir) 217 except: 218 pass 219 print '===============================================================================' 220 print ' Configuring PETSc to compile on your system ' 221 print '===============================================================================' 222 223 try: 224 # Command line arguments take precedence (but don't destroy argv[0]) 225 sys.argv = sys.argv[:1] + configure_options + sys.argv[1:] 226 check_for_option_mistakes(sys.argv) 227 check_for_option_changed(sys.argv) 228 except (TypeError, ValueError), e: 229 emsg = str(e) 230 if not emsg.endswith('\n'): emsg = emsg+'\n' 231 msg ='*******************************************************************************\n'\ 232 +' ERROR in COMMAND LINE ARGUMENT to ./configure \n' \ 233 +'-------------------------------------------------------------------------------\n' \ 234 +emsg+'*******************************************************************************\n' 235 sys.exit(msg) 236 # check PETSC_ARCH 237 check_petsc_arch(sys.argv) 238 check_broken_configure_log_links() 239 240 # support a few standard configure option types 241 for l in range(0,len(sys.argv)): 242 name = sys.argv[l] 243 if name.find('enable-') >= 0: 244 if name.find('=') == -1: 245 sys.argv[l] = name.replace('enable-','with-')+'=1' 246 else: 247 head, tail = name.split('=', 1) 248 sys.argv[l] = head.replace('enable-','with-')+'='+tail 249 if name.find('disable-') >= 0: 250 if name.find('=') == -1: 251 sys.argv[l] = name.replace('disable-','with-')+'=0' 252 else: 253 head, tail = name.split('=', 1) 254 if tail == '1': tail = '0' 255 sys.argv[l] = head.replace('disable-','with-')+'='+tail 256 if name.find('without-') >= 0: 257 if name.find('=') == -1: 258 sys.argv[l] = name.replace('without-','with-')+'=0' 259 else: 260 head, tail = name.split('=', 1) 261 if tail == '1': tail = '0' 262 sys.argv[l] = head.replace('without-','with-')+'='+tail 263 264 # Check for broken cygwin 265 chkbrokencygwin() 266 # Disable threads on RHL9 267 chkrhl9() 268 # Threads don't work for cygwin & python... 269 chkcygwinpython() 270 chkcygwinlink() 271 chkdosfiles() 272 273 # Should be run from the toplevel 274 configDir = os.path.abspath('config') 275 bsDir = os.path.join(configDir, 'BuildSystem') 276 if not os.path.isdir(configDir): 277 raise RuntimeError('Run configure from $PETSC_DIR, not '+os.path.abspath('.')) 278 sys.path.insert(0, bsDir) 279 sys.path.insert(0, configDir) 280 import config.base 281 import config.framework 282 import cPickle 283 284 framework = None 285 try: 286 framework = config.framework.Framework(['--configModules=PETSc.Configure','--optionsModule=PETSc.compilerOptions']+sys.argv[1:], loadArgDB = 0) 287 framework.setup() 288 framework.logPrint('\n'.join(extraLogs)) 289 framework.configure(out = sys.stdout) 290 framework.storeSubstitutions(framework.argDB) 291 framework.argDB['configureCache'] = cPickle.dumps(framework) 292 framework.printSummary() 293 framework.argDB.save(force = True) 294 framework.logClear() 295 framework.closeLog() 296 try: 297 move_configure_log(framework) 298 except: 299 # perhaps print an error about unable to shuffle logs? 300 pass 301 return 0 302 except (RuntimeError, config.base.ConfigureSetupError), e: 303 emsg = str(e) 304 if not emsg.endswith('\n'): emsg = emsg+'\n' 305 msg ='*******************************************************************************\n'\ 306 +' UNABLE to CONFIGURE with GIVEN OPTIONS (see configure.log for details):\n' \ 307 +'-------------------------------------------------------------------------------\n' \ 308 +emsg+'*******************************************************************************\n' 309 se = '' 310 except (TypeError, ValueError), e: 311 emsg = str(e) 312 if not emsg.endswith('\n'): emsg = emsg+'\n' 313 msg ='*******************************************************************************\n'\ 314 +' ERROR in COMMAND LINE ARGUMENT to ./configure \n' \ 315 +'-------------------------------------------------------------------------------\n' \ 316 +emsg+'*******************************************************************************\n' 317 se = '' 318 except ImportError, e : 319 emsg = str(e) 320 if not emsg.endswith('\n'): emsg = emsg+'\n' 321 msg ='*******************************************************************************\n'\ 322 +' UNABLE to FIND MODULE for ./configure \n' \ 323 +'-------------------------------------------------------------------------------\n' \ 324 +emsg+'*******************************************************************************\n' 325 se = '' 326 except OSError, e : 327 emsg = str(e) 328 if not emsg.endswith('\n'): emsg = emsg+'\n' 329 msg ='*******************************************************************************\n'\ 330 +' UNABLE to EXECUTE BINARIES for ./configure \n' \ 331 +'-------------------------------------------------------------------------------\n' \ 332 +emsg+'*******************************************************************************\n' 333 se = '' 334 except SystemExit, e: 335 if e.code is None or e.code == 0: 336 return 337 msg ='*******************************************************************************\n'\ 338 +' CONFIGURATION FAILURE (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \ 339 +'*******************************************************************************\n' 340 se = str(e) 341 except Exception, e: 342 msg ='*******************************************************************************\n'\ 343 +' CONFIGURATION CRASH (Please send configure.log to petsc-maint@mcs.anl.gov)\n' \ 344 +'*******************************************************************************\n' 345 se = str(e) 346 347 print msg 348 if not framework is None: 349 framework.logClear() 350 if hasattr(framework, 'log'): 351 try: 352 framework.log.write('**** Configure header conftest.h ****\n') 353 framework.outputHeader(framework.log) 354 framework.log.write('**** C specific Configure header conffix.h ****\n') 355 framework.outputCHeader(framework.log) 356 except Exception, e: 357 framework.log.write('Problem writing headers to log: '+str(e)) 358 import traceback 359 try: 360 framework.log.write(msg+se) 361 traceback.print_tb(sys.exc_info()[2], file = framework.log) 362 if hasattr(framework,'log'): framework.log.close() 363 move_configure_log(framework) 364 except: 365 pass 366 sys.exit(1) 367 else: 368 print se 369 import traceback 370 traceback.print_tb(sys.exc_info()[2]) 371 if hasattr(framework,'log'): framework.log.close() 372 373if __name__ == '__main__': 374 petsc_configure([]) 375 376