1#!/usr/bin/env python 2import os, re, shutil, sys 3 4if os.environ.has_key('PETSC_DIR'): 5 PETSC_DIR = os.environ['PETSC_DIR'] 6else: 7 fd = file(os.path.join('lib','petsc','conf','petscvariables')) 8 a = fd.readline() 9 a = fd.readline() 10 PETSC_DIR = a.split('=')[1][0:-1] 11 fd.close() 12 13if os.environ.has_key('PETSC_ARCH'): 14 PETSC_ARCH = os.environ['PETSC_ARCH'] 15else: 16 fd = file(os.path.join('lib','petsc','conf','petscvariables')) 17 a = fd.readline() 18 PETSC_ARCH = a.split('=')[1][0:-1] 19 fd.close() 20 21print '*** Using PETSC_DIR='+PETSC_DIR+' PETSC_ARCH='+PETSC_ARCH+' ***' 22sys.path.insert(0, os.path.join(PETSC_DIR, 'config')) 23sys.path.insert(0, os.path.join(PETSC_DIR, 'config', 'BuildSystem')) 24 25import script 26 27try: 28 WindowsError 29except NameError: 30 WindowsError = None 31 32class Installer(script.Script): 33 def __init__(self, clArgs = None): 34 import RDict 35 argDB = RDict.RDict(None, None, 0, 0, readonly = True) 36 argDB.saveFilename = os.path.join(PETSC_DIR, PETSC_ARCH, 'lib','petsc','conf', 'RDict.db') 37 argDB.load() 38 script.Script.__init__(self, argDB = argDB) 39 if not clArgs is None: self.clArgs = clArgs 40 self.copies = [] 41 return 42 43 def setupHelp(self, help): 44 import nargs 45 script.Script.setupHelp(self, help) 46 help.addArgument('Installer', '-destDir=<path>', nargs.Arg(None, None, 'Destination Directory for install')) 47 return 48 49 50 def setupModules(self): 51 self.setCompilers = self.framework.require('config.setCompilers', None) 52 self.arch = self.framework.require('PETSc.options.arch', None) 53 self.petscdir = self.framework.require('PETSc.options.petscdir', None) 54 self.compilers = self.framework.require('config.compilers', None) 55 self.mpi = self.framework.require('config.packages.MPI', None) 56 return 57 58 def setup(self): 59 script.Script.setup(self) 60 self.framework = self.loadConfigure() 61 self.setupModules() 62 return 63 64 def setupDirectories(self): 65 self.rootDir = self.petscdir.dir 66 self.destDir = os.path.abspath(self.argDB['destDir']) 67 self.installDir = os.path.abspath(os.path.expanduser(self.framework.argDB['prefix'])) 68 self.arch = self.arch.arch 69 self.archDir = os.path.join(self.rootDir, self.arch) 70 self.rootIncludeDir = os.path.join(self.rootDir, 'include') 71 self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') 72 self.rootConfDir = os.path.join(self.rootDir, 'lib','petsc','conf') 73 self.archConfDir = os.path.join(self.rootDir, self.arch, 'lib','petsc','conf') 74 self.rootBinDir = os.path.join(self.rootDir, 'lib','petsc','bin') 75 self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') 76 self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') 77 self.destIncludeDir = os.path.join(self.destDir, 'include') 78 self.destConfDir = os.path.join(self.destDir, 'lib','petsc','conf') 79 self.destLibDir = os.path.join(self.destDir, 'lib') 80 self.destBinDir = os.path.join(self.destDir, 'lib','petsc','bin') 81 self.installIncludeDir = os.path.join(self.installDir, 'include') 82 self.installBinDir = os.path.join(self.installDir, 'lib','petsc','bin') 83 self.rootShareDir = os.path.join(self.rootDir, 'share') 84 self.destShareDir = os.path.join(self.destDir, 'share') 85 self.rootSrcDir = os.path.join(self.rootDir, 'src') 86 87 self.ranlib = self.compilers.RANLIB 88 self.arLibSuffix = self.compilers.AR_LIB_SUFFIX 89 return 90 91 def checkPrefix(self): 92 if not self.installDir: 93 print '********************************************************************' 94 print 'PETSc is built without prefix option. So "make install" is not appropriate.' 95 print 'If you need a prefix install of PETSc - rerun configure with --prefix option.' 96 print '********************************************************************' 97 sys.exit(1) 98 return 99 100 def checkDestdir(self): 101 if os.path.exists(self.destDir): 102 if os.path.samefile(self.destDir, self.rootDir): 103 print '********************************************************************' 104 print 'Incorrect prefix usage. Specified destDir same as current PETSC_DIR' 105 print '********************************************************************' 106 sys.exit(1) 107 if os.path.samefile(self.destDir, os.path.join(self.rootDir,self.arch)): 108 print '********************************************************************' 109 print 'Incorrect prefix usage. Specified destDir same as current PETSC_DIR/PETSC_ARCH' 110 print '********************************************************************' 111 sys.exit(1) 112 if not os.path.isdir(os.path.realpath(self.destDir)): 113 print '********************************************************************' 114 print 'Specified destDir', self.destDir, 'is not a directory. Cannot proceed!' 115 print '********************************************************************' 116 sys.exit(1) 117 if not os.access(self.destDir, os.W_OK): 118 print '********************************************************************' 119 print 'Unable to write to ', self.destDir, 'Perhaps you need to do "sudo make install"' 120 print '********************************************************************' 121 sys.exit(1) 122 return 123 124 def copyfile(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 125 """Copies a single file """ 126 copies = [] 127 errors = [] 128 if not os.path.exists(dst): 129 os.makedirs(dst) 130 elif not os.path.isdir(dst): 131 raise shutil.Error, 'Destination is not a directory' 132 srcname = src 133 dstname = os.path.join(dst, os.path.basename(src)) 134 try: 135 if symlinks and os.path.islink(srcname): 136 linkto = os.readlink(srcname) 137 os.symlink(linkto, dstname) 138 else: 139 copyFunc(srcname, dstname) 140 copies.append((srcname, dstname)) 141 except (IOError, os.error), why: 142 errors.append((srcname, dstname, str(why))) 143 except shutil.Error, err: 144 errors.extend((srcname,dstname,str(err.args[0]))) 145 if errors: 146 raise shutil.Error, errors 147 return copies 148 149 def copyexamplefiles(self, src, dst, copyFunc = shutil.copy2): 150 """Copies all files, but not directories in a single file """ 151 names = os.listdir(src) 152 for name in names: 153 if not name.endswith('.html'): 154 srcname = os.path.join(src, name) 155 if os.path.isfile(srcname): 156 self.copyfile(srcname,dst) 157 158 def fixExamplesMakefile(self, src): 159 '''Change ././${PETSC_ARCH} in makefile in root petsc directory with ${PETSC_DIR}''' 160 lines = [] 161 oldFile = open(src, 'r') 162 alllines=oldFile.read() 163 oldFile.close() 164 newlines=alllines.split('\n')[0]+'\n' # Firstline 165 # Hardcode PETSC_DIR and PETSC_ARCH to avoid users doing the worng thing 166 newlines+='PETSC_DIR='+self.installDir+'\n' 167 newlines+='PETSC_ARCH=\n' 168 for line in alllines.split('\n')[1:]: 169 if line.startswith('TESTLOGFILE'): 170 newlines+='TESTLOGFILE = $(TESTDIR)/examples-install.log\n' 171 elif line.startswith('CONFIGDIR'): 172 newlines+='CONFIGDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples/config\n' 173 elif line.startswith('$(generatedtest)') and 'petscvariables' in line: 174 newlines+='all: test\n\n'+line+'\n' 175 else: 176 newlines+=line+'\n' 177 newFile = open(src, 'w') 178 newFile.write(newlines) 179 newFile.close() 180 return 181 182 def copyConfig(self, src, dst): 183 """Recursively copy the examples directories 184 """ 185 if not os.path.isdir(dst): 186 raise shutil.Error, 'Destination is not a directory' 187 188 self.copyfile('gmakefile.test',dst) 189 newConfigDir=os.path.join(dst,'config') # Am not renaming at present 190 if not os.path.isdir(newConfigDir): os.mkdir(newConfigDir) 191 testConfFiles="gmakegentest.py gmakegen.py testparse.py example_template.py".split() 192 testConfFiles+="petsc_harness.sh report_tests.py watchtime.sh".split() 193 testConfFiles+=["cmakegen.py"] 194 for tf in testConfFiles: 195 self.copyfile(os.path.join('config',tf),newConfigDir) 196 return 197 198 def copyExamples(self, src, dst): 199 """copy the examples directories 200 """ 201 top=os.path.relpath(src,os.path.abspath(os.curdir)) 202 for root, dirs, files in os.walk(top, topdown=False): 203 if not os.path.basename(root) == "examples": continue 204 shutil.copytree(root, os.path.join(dst,root), 205 ignore=shutil.ignore_patterns('*.dSYM')) 206 207 return 208 209 def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2, exclude = [],recurse = 1): 210 """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 211 212 The copyFunc() you provide is only used on the top level, lower levels always use shutil.copy2 213 214 The destination directory must not already exist. 215 If exception(s) occur, an shutil.Error is raised with a list of reasons. 216 217 If the optional symlinks flag is true, symbolic links in the 218 source tree result in symbolic links in the destination tree; if 219 it is false, the contents of the files pointed to by symbolic 220 links are copied. 221 """ 222 copies = [] 223 names = os.listdir(src) 224 if not os.path.exists(dst): 225 os.makedirs(dst) 226 elif not os.path.isdir(dst): 227 raise shutil.Error, 'Destination is not a directory' 228 errors = [] 229 for name in names: 230 srcname = os.path.join(src, name) 231 dstname = os.path.join(dst, name) 232 try: 233 if symlinks and os.path.islink(srcname): 234 linkto = os.readlink(srcname) 235 os.symlink(linkto, dstname) 236 elif os.path.isdir(srcname) and recurse and not os.path.basename(srcname) in exclude: 237 copies.extend(self.copytree(srcname, dstname, symlinks,exclude = exclude)) 238 elif os.path.isfile(srcname) and not os.path.basename(srcname) in exclude: 239 copyFunc(srcname, dstname) 240 copies.append((srcname, dstname)) 241 # XXX What about devices, sockets etc.? 242 except (IOError, os.error), why: 243 errors.append((srcname, dstname, str(why))) 244 # catch the Error from the recursive copytree so that we can 245 # continue with other files 246 except shutil.Error, err: 247 errors.extend((srcname,dstname,str(err.args[0]))) 248 try: 249 shutil.copystat(src, dst) 250 except OSError, e: 251 if WindowsError is not None and isinstance(e, WindowsError): 252 # Copying file access times may fail on Windows 253 pass 254 else: 255 errors.extend((src, dst, str(e))) 256 if errors: 257 raise shutil.Error, errors 258 return copies 259 260 261 def fixConfFile(self, src): 262 lines = [] 263 oldFile = open(src, 'r') 264 for line in oldFile.readlines(): 265 # paths generated by configure could be different link-path than whats used by user, so fix both 266 line = line.replace(os.path.join(self.rootDir, self.arch), self.installDir) 267 line = line.replace(os.path.realpath(os.path.join(self.rootDir, self.arch)), self.installDir) 268 line = line.replace(os.path.join(self.rootDir, 'bin'), self.installBinDir) 269 line = line.replace(os.path.realpath(os.path.join(self.rootDir, 'bin')), self.installBinDir) 270 line = line.replace(os.path.join(self.rootDir, 'include'), self.installIncludeDir) 271 line = line.replace(os.path.realpath(os.path.join(self.rootDir, 'include')), self.installIncludeDir) 272 line = line.replace(self.rootDir, self.installDir) 273 # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 274 line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir) 275 line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '') 276 line = line.replace('${PETSC_DIR}', self.installDir) 277 lines.append(line) 278 oldFile.close() 279 newFile = open(src, 'w') 280 newFile.write(''.join(lines)) 281 newFile.close() 282 return 283 284 def fixConf(self): 285 import shutil 286 for file in ['rules', 'variables','petscrules', 'petscvariables']: 287 self.fixConfFile(os.path.join(self.destConfDir,file)) 288 self.fixConfFile(os.path.join(self.destLibDir,'pkgconfig','PETSc.pc')) 289 self.fixConfFile(os.path.join(self.destIncludeDir,'petscconf.h')) 290 return 291 292 def createUninstaller(self): 293 uninstallscript = os.path.join(self.destConfDir, 'uninstall.py') 294 f = open(uninstallscript, 'w') 295 # Could use the Python AST to do this 296 f.write('#!'+sys.executable+'\n') 297 f.write('import os\n') 298 299 f.write('copies = '+repr(self.copies).replace(self.destDir,self.installDir)) 300 f.write(''' 301for src, dst in copies: 302 if os.path.exists(dst): 303 os.remove(dst) 304''') 305 f.close() 306 os.chmod(uninstallscript,0744) 307 return 308 309 def installIncludes(self): 310 exclude = ['makefile'] 311 if not hasattr(self.compilers.setCompilers, 'FC'): 312 exclude.append('finclude') 313 if not self.mpi.usingMPIUni: 314 exclude.append('mpiuni') 315 self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude)) 316 self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir)) 317 return 318 319 def installConf(self): 320 self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log'])) 321 self.copies.extend(self.copytree(self.archConfDir, self.destConfDir, exclude = ['sowing', 'configure.log.bkp','configure.log','make.log','gmake.log','test.log','error.log'])) 322 return 323 324 def installBin(self): 325 exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml'] 326 self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude )) 327 exclude = ['maint'] 328 if not self.mpi.usingMPIUni: 329 exclude.append('petsc-mpiexec.uni') 330 self.setCompilers.pushLanguage('C') 331 if not self.setCompilers.isWindows(self.setCompilers.getCompiler(),self.log): 332 exclude.append('win32fe') 333 self.setCompilers.popLanguage() 334 self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude )) 335 return 336 337 def installShare(self): 338 self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir)) 339 examplesdir=os.path.join(self.destShareDir,'petsc','examples') 340 if os.path.exists(examplesdir): 341 shutil.rmtree(examplesdir) 342 os.mkdir(examplesdir) 343 os.mkdir(os.path.join(examplesdir,'src')) 344 self.copyExamples(self.rootSrcDir,examplesdir) 345 self.copyConfig(self.rootDir,examplesdir) 346 self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test')) 347 return 348 349 def copyLib(self, src, dst): 350 '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac''' 351 # Symlinks (assumed local) are recreated at dst 352 if os.path.islink(src): 353 linkto = os.readlink(src) 354 try: 355 os.remove(dst) # In case it already exists 356 except OSError: 357 pass 358 os.symlink(linkto, dst) 359 return 360 # Do not install object files 361 if not os.path.splitext(src)[1] == '.o': 362 shutil.copy2(src, dst) 363 if os.path.splitext(dst)[1] == '.'+self.arLibSuffix: 364 self.executeShellCommand(self.ranlib+' '+dst) 365 if os.path.splitext(dst)[1] == '.dylib' and os.path.isfile('/usr/bin/install_name_tool'): 366 [output,err,flg] = self.executeShellCommand("otool -D "+src) 367 oldname = output[output.find("\n")+1:] 368 installName = oldname.replace(self.archDir, self.installDir) 369 self.executeShellCommand('/usr/bin/install_name_tool -id ' + installName + ' ' + dst) 370 # preserve the original timestamps - so that the .a vs .so time order is preserved 371 shutil.copystat(src,dst) 372 return 373 374 def installLib(self): 375 self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 376 self.copies.extend(self.copytree(os.path.join(self.archLibDir,'pkgconfig'), os.path.join(self.destLibDir,'pkgconfig'), copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 377 return 378 379 380 def outputInstallDone(self): 381 print '''\ 382==================================== 383Install complete. 384Now to check if the libraries are working do (in current directory): 385make PETSC_DIR=%s PETSC_ARCH="" test 386====================================\ 387''' % (self.installDir) 388 return 389 390 def outputDestDirDone(self): 391 print '''\ 392==================================== 393Copy to DESTDIR %s is now complete. 394Before use - please copy/install over to specified prefix: %s 395====================================\ 396''' % (self.destDir,self.installDir) 397 return 398 399 def runsetup(self): 400 self.setup() 401 self.setupDirectories() 402 self.checkPrefix() 403 self.checkDestdir() 404 return 405 406 def runcopy(self): 407 if self.destDir == self.installDir: 408 print '*** Installing PETSc at prefix location:',self.destDir, ' ***' 409 else: 410 print '*** Copying PETSc to DESTDIR location:',self.destDir, ' ***' 411 if not os.path.exists(self.destDir): 412 try: 413 os.makedirs(self.destDir) 414 except: 415 print '********************************************************************' 416 print 'Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"' 417 print '********************************************************************' 418 sys.exit(1) 419 self.installIncludes() 420 self.installConf() 421 self.installBin() 422 self.installLib() 423 self.installShare() 424 return 425 426 def runfix(self): 427 self.fixConf() 428 return 429 430 def rundone(self): 431 self.createUninstaller() 432 if self.destDir == self.installDir: 433 self.outputInstallDone() 434 else: 435 self.outputDestDirDone() 436 return 437 438 def run(self): 439 self.runsetup() 440 self.runcopy() 441 self.runfix() 442 self.rundone() 443 return 444 445if __name__ == '__main__': 446 Installer(sys.argv[1:]).run() 447 # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 448 delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp'] 449 for delfile in delfiles: 450 if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 451 os.remove(delfile) 452