1df3bd252SSatish Balay#!/usr/bin/env python3 25b6bfdb9SJed Brownfrom __future__ import print_function 3e551db17SScott Krugerimport os, re, shutil, sys 40ee81e68SLisandro Dalcin 55b6bfdb9SJed Brownif 'PETSC_DIR' in os.environ: 60ee81e68SLisandro Dalcin PETSC_DIR = os.environ['PETSC_DIR'] 70ee81e68SLisandro Dalcinelse: 8c6ef1b5bSJed Brown fd = open(os.path.join('lib','petsc','conf','petscvariables')) 90ee81e68SLisandro Dalcin a = fd.readline() 100ee81e68SLisandro Dalcin a = fd.readline() 110ee81e68SLisandro Dalcin PETSC_DIR = a.split('=')[1][0:-1] 120ee81e68SLisandro Dalcin fd.close() 130ee81e68SLisandro Dalcin 145b6bfdb9SJed Brownif 'PETSC_ARCH' in os.environ: 150ee81e68SLisandro Dalcin PETSC_ARCH = os.environ['PETSC_ARCH'] 160ee81e68SLisandro Dalcinelse: 17c6ef1b5bSJed Brown fd = open(os.path.join('lib','petsc','conf','petscvariables')) 180ee81e68SLisandro Dalcin a = fd.readline() 190ee81e68SLisandro Dalcin PETSC_ARCH = a.split('=')[1][0:-1] 200ee81e68SLisandro Dalcin fd.close() 210ee81e68SLisandro Dalcin 225b6bfdb9SJed Brownprint('*** Using PETSC_DIR='+PETSC_DIR+' PETSC_ARCH='+PETSC_ARCH+' ***') 230ee81e68SLisandro Dalcinsys.path.insert(0, os.path.join(PETSC_DIR, 'config')) 240ee81e68SLisandro Dalcinsys.path.insert(0, os.path.join(PETSC_DIR, 'config', 'BuildSystem')) 250ee81e68SLisandro Dalcin 260ee81e68SLisandro Dalcinimport script 270ee81e68SLisandro Dalcin 280ee81e68SLisandro Dalcintry: 290ee81e68SLisandro Dalcin WindowsError 300ee81e68SLisandro Dalcinexcept NameError: 310ee81e68SLisandro Dalcin WindowsError = None 320ee81e68SLisandro Dalcin 330ee81e68SLisandro Dalcinclass Installer(script.Script): 340ee81e68SLisandro Dalcin def __init__(self, clArgs = None): 350ee81e68SLisandro Dalcin import RDict 360ee81e68SLisandro Dalcin argDB = RDict.RDict(None, None, 0, 0, readonly = True) 37af0996ceSBarry Smith argDB.saveFilename = os.path.join(PETSC_DIR, PETSC_ARCH, 'lib','petsc','conf', 'RDict.db') 380ee81e68SLisandro Dalcin argDB.load() 390ee81e68SLisandro Dalcin script.Script.__init__(self, argDB = argDB) 400ee81e68SLisandro Dalcin if not clArgs is None: self.clArgs = clArgs 410ee81e68SLisandro Dalcin self.copies = [] 420ee81e68SLisandro Dalcin return 430ee81e68SLisandro Dalcin 440ee81e68SLisandro Dalcin def setupHelp(self, help): 450ee81e68SLisandro Dalcin import nargs 460ee81e68SLisandro Dalcin script.Script.setupHelp(self, help) 47a26d7103SSatish Balay help.addArgument('Installer', '-destDir=<path>', nargs.Arg(None, '', 'Destination Directory for install')) 48fad83eadSPatrick Sanan help.addArgument('Installer', '-no-examples', nargs.Arg(None, '', 'Skip installing examples')) 490ee81e68SLisandro Dalcin return 500ee81e68SLisandro Dalcin 510ee81e68SLisandro Dalcin 520ee81e68SLisandro Dalcin def setupModules(self): 530ee81e68SLisandro Dalcin self.setCompilers = self.framework.require('config.setCompilers', None) 540ee81e68SLisandro Dalcin self.arch = self.framework.require('PETSc.options.arch', None) 550ee81e68SLisandro Dalcin self.petscdir = self.framework.require('PETSc.options.petscdir', None) 560ee81e68SLisandro Dalcin self.compilers = self.framework.require('config.compilers', None) 5732cabb2fSBarry Smith self.mpi = self.framework.require('config.packages.MPI', None) 580ee81e68SLisandro Dalcin return 590ee81e68SLisandro Dalcin 600ee81e68SLisandro Dalcin def setup(self): 610ee81e68SLisandro Dalcin script.Script.setup(self) 620ee81e68SLisandro Dalcin self.framework = self.loadConfigure() 630ee81e68SLisandro Dalcin self.setupModules() 640ee81e68SLisandro Dalcin return 650ee81e68SLisandro Dalcin 660ee81e68SLisandro Dalcin def setupDirectories(self): 670ee81e68SLisandro Dalcin self.rootDir = self.petscdir.dir 684a08bad0SBarry Smith self.installDir = os.path.abspath(os.path.expanduser(self.framework.argDB['prefix'])) 698727f567SSatish Balay self.destDir = os.path.abspath(self.argDB['destDir']+self.installDir) 700ee81e68SLisandro Dalcin self.arch = self.arch.arch 7102e047dfSSatish Balay self.archDir = os.path.join(self.rootDir, self.arch) 720ee81e68SLisandro Dalcin self.rootIncludeDir = os.path.join(self.rootDir, 'include') 730ee81e68SLisandro Dalcin self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') 74af0996ceSBarry Smith self.rootConfDir = os.path.join(self.rootDir, 'lib','petsc','conf') 75af0996ceSBarry Smith self.archConfDir = os.path.join(self.rootDir, self.arch, 'lib','petsc','conf') 76c3a89c15SBarry Smith self.rootBinDir = os.path.join(self.rootDir, 'lib','petsc','bin') 770ee81e68SLisandro Dalcin self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') 780ee81e68SLisandro Dalcin self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') 790ee81e68SLisandro Dalcin self.destIncludeDir = os.path.join(self.destDir, 'include') 80af0996ceSBarry Smith self.destConfDir = os.path.join(self.destDir, 'lib','petsc','conf') 810ee81e68SLisandro Dalcin self.destLibDir = os.path.join(self.destDir, 'lib') 82c3a89c15SBarry Smith self.destBinDir = os.path.join(self.destDir, 'lib','petsc','bin') 830ee81e68SLisandro Dalcin self.installIncludeDir = os.path.join(self.installDir, 'include') 84c3a89c15SBarry Smith self.installBinDir = os.path.join(self.installDir, 'lib','petsc','bin') 850ee81e68SLisandro Dalcin self.rootShareDir = os.path.join(self.rootDir, 'share') 860ee81e68SLisandro Dalcin self.destShareDir = os.path.join(self.destDir, 'share') 8779eaf171SScott Kruger self.rootSrcDir = os.path.join(self.rootDir, 'src') 880ee81e68SLisandro Dalcin 890ee81e68SLisandro Dalcin self.ranlib = self.compilers.RANLIB 900ee81e68SLisandro Dalcin self.arLibSuffix = self.compilers.AR_LIB_SUFFIX 910ee81e68SLisandro Dalcin return 920ee81e68SLisandro Dalcin 930ee81e68SLisandro Dalcin def checkPrefix(self): 940ee81e68SLisandro Dalcin if not self.installDir: 955b6bfdb9SJed Brown print('********************************************************************') 965b6bfdb9SJed Brown print('PETSc is built without prefix option. So "make install" is not appropriate.') 975b6bfdb9SJed Brown print('If you need a prefix install of PETSc - rerun configure with --prefix option.') 985b6bfdb9SJed Brown print('********************************************************************') 990ee81e68SLisandro Dalcin sys.exit(1) 1000ee81e68SLisandro Dalcin return 1010ee81e68SLisandro Dalcin 1020ee81e68SLisandro Dalcin def checkDestdir(self): 1030ee81e68SLisandro Dalcin if os.path.exists(self.destDir): 1040ee81e68SLisandro Dalcin if os.path.samefile(self.destDir, self.rootDir): 1055b6bfdb9SJed Brown print('********************************************************************') 1065b6bfdb9SJed Brown print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR') 1075b6bfdb9SJed Brown print('********************************************************************') 1080ee81e68SLisandro Dalcin sys.exit(1) 1090ee81e68SLisandro Dalcin if os.path.samefile(self.destDir, os.path.join(self.rootDir,self.arch)): 1105b6bfdb9SJed Brown print('********************************************************************') 1115b6bfdb9SJed Brown print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR/PETSC_ARCH') 1125b6bfdb9SJed Brown print('********************************************************************') 1130ee81e68SLisandro Dalcin sys.exit(1) 1140ee81e68SLisandro Dalcin if not os.path.isdir(os.path.realpath(self.destDir)): 1155b6bfdb9SJed Brown print('********************************************************************') 1165b6bfdb9SJed Brown print('Specified destDir', self.destDir, 'is not a directory. Cannot proceed!') 1175b6bfdb9SJed Brown print('********************************************************************') 1180ee81e68SLisandro Dalcin sys.exit(1) 1190ee81e68SLisandro Dalcin if not os.access(self.destDir, os.W_OK): 1205b6bfdb9SJed Brown print('********************************************************************') 1215b6bfdb9SJed Brown print('Unable to write to ', self.destDir, 'Perhaps you need to do "sudo make install"') 1225b6bfdb9SJed Brown print('********************************************************************') 1230ee81e68SLisandro Dalcin sys.exit(1) 1240ee81e68SLisandro Dalcin return 1250ee81e68SLisandro Dalcin 1260ee81e68SLisandro Dalcin def copyfile(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 1270ee81e68SLisandro Dalcin """Copies a single file """ 1280ee81e68SLisandro Dalcin copies = [] 1290ee81e68SLisandro Dalcin errors = [] 1300ee81e68SLisandro Dalcin if not os.path.exists(dst): 1310ee81e68SLisandro Dalcin os.makedirs(dst) 1320ee81e68SLisandro Dalcin elif not os.path.isdir(dst): 1335b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 1340ee81e68SLisandro Dalcin srcname = src 1350ee81e68SLisandro Dalcin dstname = os.path.join(dst, os.path.basename(src)) 1360ee81e68SLisandro Dalcin try: 1370ee81e68SLisandro Dalcin if symlinks and os.path.islink(srcname): 1380ee81e68SLisandro Dalcin linkto = os.readlink(srcname) 1390ee81e68SLisandro Dalcin os.symlink(linkto, dstname) 1400ee81e68SLisandro Dalcin else: 1410ee81e68SLisandro Dalcin copyFunc(srcname, dstname) 1420ee81e68SLisandro Dalcin copies.append((srcname, dstname)) 1435b6bfdb9SJed Brown except (IOError, os.error) as why: 1440ee81e68SLisandro Dalcin errors.append((srcname, dstname, str(why))) 1455b6bfdb9SJed Brown except shutil.Error as err: 1462c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 1470ee81e68SLisandro Dalcin if errors: 1485b6bfdb9SJed Brown raise shutil.Error(errors) 1490ee81e68SLisandro Dalcin return copies 1500ee81e68SLisandro Dalcin 15126e8aaceSBarry Smith def fixExamplesMakefile(self, src): 15226e8aaceSBarry Smith '''Change ././${PETSC_ARCH} in makefile in root petsc directory with ${PETSC_DIR}''' 15326e8aaceSBarry Smith lines = [] 15426e8aaceSBarry Smith oldFile = open(src, 'r') 155e551db17SScott Kruger alllines=oldFile.read() 15626e8aaceSBarry Smith oldFile.close() 157e551db17SScott Kruger newlines=alllines.split('\n')[0]+'\n' # Firstline 158d5b43468SJose E. Roman # Hardcode PETSC_DIR and PETSC_ARCH to avoid users doing the wrong thing 159e551db17SScott Kruger newlines+='PETSC_DIR='+self.installDir+'\n' 160e551db17SScott Kruger newlines+='PETSC_ARCH=\n' 161e551db17SScott Kruger for line in alllines.split('\n')[1:]: 1624ff3c6a1SScott Kruger if line.startswith('TESTLOGFILE'): 163c173c275SScott Kruger newlines+='TESTLOGFILE = $(TESTDIR)/examples-install.log\n' 164e551db17SScott Kruger elif line.startswith('CONFIGDIR'): 165e551db17SScott Kruger newlines+='CONFIGDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples/config\n' 166fc46264cSScott Kruger elif line.startswith('$(generatedtest)') and 'petscvariables' in line: 167c173c275SScott Kruger newlines+='all: test\n\n'+line+'\n' 168e551db17SScott Kruger else: 1694ff3c6a1SScott Kruger newlines+=line+'\n' 17026e8aaceSBarry Smith newFile = open(src, 'w') 171e551db17SScott Kruger newFile.write(newlines) 17226e8aaceSBarry Smith newFile.close() 17326e8aaceSBarry Smith return 17426e8aaceSBarry Smith 175e551db17SScott Kruger def copyConfig(self, src, dst): 1762f21b5d8SJed Brown """Copy configuration/testing files 177e551db17SScott Kruger """ 178e551db17SScott Kruger if not os.path.isdir(dst): 1795b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 180e551db17SScott Kruger 181adf35c6eSSatish Balay self.copies.extend(self.copyfile('gmakefile.test',dst)) 182e551db17SScott Kruger newConfigDir=os.path.join(dst,'config') # Am not renaming at present 183e551db17SScott Kruger if not os.path.isdir(newConfigDir): os.mkdir(newConfigDir) 184e551db17SScott Kruger testConfFiles="gmakegentest.py gmakegen.py testparse.py example_template.py".split() 18558780e5dSStefano Zampini testConfFiles+="petsc_harness.sh report_tests.py query_tests.py".split() 186e551db17SScott Kruger for tf in testConfFiles: 187adf35c6eSSatish Balay self.copies.extend(self.copyfile(os.path.join('config',tf),newConfigDir)) 188e551db17SScott Kruger return 189e551db17SScott Kruger 19026e8aaceSBarry Smith def copyExamples(self, src, dst): 1914ff3c6a1SScott Kruger """copy the examples directories 19226e8aaceSBarry Smith """ 193ad246c4dSSatish Balay for root, dirs, files in os.walk(src, topdown=False): 1942f21b5d8SJed Brown if os.path.basename(root) not in ("tests", "tutorials"): continue 195ad246c4dSSatish Balay self.copies.extend(self.copytree(root, root.replace(src,dst))) 1964ff3c6a1SScott Kruger return 1970ee81e68SLisandro Dalcin 1980080bb28SSatish Balay def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2, exclude = [], exclude_ext= ['.DSYM','.o','.pyc'], recurse = 1): 1990ee81e68SLisandro Dalcin """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 2000ee81e68SLisandro Dalcin 2010ee81e68SLisandro Dalcin The copyFunc() you provide is only used on the top level, lower levels always use shutil.copy2 2020ee81e68SLisandro Dalcin 2030ee81e68SLisandro Dalcin The destination directory must not already exist. 2040ee81e68SLisandro Dalcin If exception(s) occur, an shutil.Error is raised with a list of reasons. 2050ee81e68SLisandro Dalcin 2060ee81e68SLisandro Dalcin If the optional symlinks flag is true, symbolic links in the 2070ee81e68SLisandro Dalcin source tree result in symbolic links in the destination tree; if 2080ee81e68SLisandro Dalcin it is false, the contents of the files pointed to by symbolic 2090ee81e68SLisandro Dalcin links are copied. 2100ee81e68SLisandro Dalcin """ 2110ee81e68SLisandro Dalcin copies = [] 2120ee81e68SLisandro Dalcin names = os.listdir(src) 2130ee81e68SLisandro Dalcin if not os.path.exists(dst): 2140ee81e68SLisandro Dalcin os.makedirs(dst) 2150ee81e68SLisandro Dalcin elif not os.path.isdir(dst): 2165b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 2170ee81e68SLisandro Dalcin errors = [] 2182c72da00SPierre Jolivet srclinks = [] 2192c72da00SPierre Jolivet dstlinks = [] 2200ee81e68SLisandro Dalcin for name in names: 2210ee81e68SLisandro Dalcin srcname = os.path.join(src, name) 2220ee81e68SLisandro Dalcin dstname = os.path.join(dst, name) 2230ee81e68SLisandro Dalcin try: 2240ee81e68SLisandro Dalcin if symlinks and os.path.islink(srcname): 2250ee81e68SLisandro Dalcin linkto = os.readlink(srcname) 2260ee81e68SLisandro Dalcin os.symlink(linkto, dstname) 22732cabb2fSBarry Smith elif os.path.isdir(srcname) and recurse and not os.path.basename(srcname) in exclude: 228adf35c6eSSatish Balay copies.extend(self.copytree(srcname, dstname, symlinks,exclude = exclude, exclude_ext = exclude_ext)) 229adf35c6eSSatish Balay elif os.path.isfile(srcname) and not os.path.basename(srcname) in exclude and os.path.splitext(name)[1] not in exclude_ext : 2302c72da00SPierre Jolivet if os.path.islink(srcname): 2312c72da00SPierre Jolivet srclinks.append(srcname) 2322c72da00SPierre Jolivet dstlinks.append(dstname) 2332c72da00SPierre Jolivet else: 2340ee81e68SLisandro Dalcin copyFunc(srcname, dstname) 2350ee81e68SLisandro Dalcin copies.append((srcname, dstname)) 2360ee81e68SLisandro Dalcin # XXX What about devices, sockets etc.? 2375b6bfdb9SJed Brown except (IOError, os.error) as why: 2380ee81e68SLisandro Dalcin errors.append((srcname, dstname, str(why))) 2390ee81e68SLisandro Dalcin # catch the Error from the recursive copytree so that we can 2400ee81e68SLisandro Dalcin # continue with other files 2415b6bfdb9SJed Brown except shutil.Error as err: 2422c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 2432c72da00SPierre Jolivet for srcname, dstname in zip(srclinks, dstlinks): 2442c72da00SPierre Jolivet try: 2452c72da00SPierre Jolivet copyFunc(srcname, dstname) 2462c72da00SPierre Jolivet copies.append((srcname, dstname)) 2472c72da00SPierre Jolivet except (IOError, os.error) as why: 2482c72da00SPierre Jolivet errors.append((srcname, dstname, str(why))) 2492c72da00SPierre Jolivet # catch the Error from the recursive copytree so that we can 2502c72da00SPierre Jolivet # continue with other files 2512c72da00SPierre Jolivet except shutil.Error as err: 2522c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 2530ee81e68SLisandro Dalcin try: 2540ee81e68SLisandro Dalcin shutil.copystat(src, dst) 2555b6bfdb9SJed Brown except OSError as e: 2560ee81e68SLisandro Dalcin if WindowsError is not None and isinstance(e, WindowsError): 2570ee81e68SLisandro Dalcin # Copying file access times may fail on Windows 2580ee81e68SLisandro Dalcin pass 2590ee81e68SLisandro Dalcin else: 2602c852529SBarry Smith errors.append((src, dst, str(e))) 2610ee81e68SLisandro Dalcin if errors: 2625b6bfdb9SJed Brown raise shutil.Error(errors) 2630ee81e68SLisandro Dalcin return copies 2640ee81e68SLisandro Dalcin 2650ee81e68SLisandro Dalcin 2660ee81e68SLisandro Dalcin def fixConfFile(self, src): 2670ee81e68SLisandro Dalcin lines = [] 2680ee81e68SLisandro Dalcin oldFile = open(src, 'r') 2690ee81e68SLisandro Dalcin for line in oldFile.readlines(): 2705a21677cSJed Brown if line.startswith('PETSC_CC_INCLUDES =') or line.startswith('PETSC_FC_INCLUDES ='): 2715a21677cSJed Brown continue 2725a21677cSJed Brown line = line.replace('PETSC_CC_INCLUDES_INSTALL', 'PETSC_CC_INCLUDES') 2735a21677cSJed Brown line = line.replace('PETSC_FC_INCLUDES_INSTALL', 'PETSC_FC_INCLUDES') 2740ee81e68SLisandro Dalcin # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 2750ee81e68SLisandro Dalcin line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir) 2760ee81e68SLisandro Dalcin line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '') 2770ee81e68SLisandro Dalcin line = line.replace('${PETSC_DIR}', self.installDir) 278011f288aSSatish Balay # replace PETSC_DIR/lib/petsc/bin with prefix/lib/petsc/bin 279011f288aSSatish Balay line = line.replace(self.rootBinDir,self.destBinDir) 2800ee81e68SLisandro Dalcin lines.append(line) 2810ee81e68SLisandro Dalcin oldFile.close() 2820ee81e68SLisandro Dalcin newFile = open(src, 'w') 2830ee81e68SLisandro Dalcin newFile.write(''.join(lines)) 2840ee81e68SLisandro Dalcin newFile.close() 2850ee81e68SLisandro Dalcin return 2860ee81e68SLisandro Dalcin 2870ee81e68SLisandro Dalcin def fixConf(self): 2880ee81e68SLisandro Dalcin import shutil 289cb5db241SBarry Smith for file in ['rules', 'rules_doc.mk', 'rules_util.mk', 'variables', 'petscrules', 'petscvariables']: 2900ee81e68SLisandro Dalcin self.fixConfFile(os.path.join(self.destConfDir,file)) 2910ee81e68SLisandro Dalcin return 2920ee81e68SLisandro Dalcin 293*5ee53db2SLisandro Dalcin def fixPythonWheel(self): 294*5ee53db2SLisandro Dalcin import glob 295*5ee53db2SLisandro Dalcin import shutil 296*5ee53db2SLisandro Dalcin # 297*5ee53db2SLisandro Dalcin for pattern in ( 298*5ee53db2SLisandro Dalcin self.destLibDir + '/*.a', 299*5ee53db2SLisandro Dalcin self.destLibDir + '/*.la', 300*5ee53db2SLisandro Dalcin self.destLibDir + '/pkgconfig', # TODO: keep? 301*5ee53db2SLisandro Dalcin self.destConfDir + '/configure-hash', 302*5ee53db2SLisandro Dalcin self.destConfDir + '/uninstall.py', 303*5ee53db2SLisandro Dalcin self.destConfDir + '/reconfigure-*.py', 304*5ee53db2SLisandro Dalcin self.destConfDir + '/pkg.conf.*', 305*5ee53db2SLisandro Dalcin self.destConfDir + '/pkg.git*.*', 306*5ee53db2SLisandro Dalcin self.destConfDir + '/modules', # TODO: keep? 307*5ee53db2SLisandro Dalcin self.destShareDir + '/*/examples/src/*', 308*5ee53db2SLisandro Dalcin self.destShareDir + '/*/datafiles', 309*5ee53db2SLisandro Dalcin ): 310*5ee53db2SLisandro Dalcin for pathname in glob.glob(pattern): 311*5ee53db2SLisandro Dalcin if os.path.isdir(pathname): 312*5ee53db2SLisandro Dalcin shutil.rmtree(pathname) 313*5ee53db2SLisandro Dalcin elif os.path.exists(pathname): 314*5ee53db2SLisandro Dalcin os.remove(pathname) 315*5ee53db2SLisandro Dalcin # 316*5ee53db2SLisandro Dalcin for filename in ( 317*5ee53db2SLisandro Dalcin self.destIncludeDir + '/petscconf.h', 318*5ee53db2SLisandro Dalcin self.destIncludeDir + '/petscconfiginfo.h', 319*5ee53db2SLisandro Dalcin self.destIncludeDir + '/petscmachineinfo.h', 320*5ee53db2SLisandro Dalcin self.destShareDir + '/petsc/examples/gmakefile.test', 321*5ee53db2SLisandro Dalcin self.destConfDir + '/rules', 322*5ee53db2SLisandro Dalcin self.destConfDir + '/rules_doc.mk', 323*5ee53db2SLisandro Dalcin self.destConfDir + '/rules_util.mk', 324*5ee53db2SLisandro Dalcin self.destConfDir + '/petscrules', 325*5ee53db2SLisandro Dalcin self.destConfDir + '/variables', 326*5ee53db2SLisandro Dalcin self.destConfDir + '/petscvariables', 327*5ee53db2SLisandro Dalcin ): 328*5ee53db2SLisandro Dalcin with open(filename, 'r') as oldFile: 329*5ee53db2SLisandro Dalcin contents = oldFile.read() 330*5ee53db2SLisandro Dalcin contents = contents.replace(self.installDir, '${PETSC_DIR}') 331*5ee53db2SLisandro Dalcin contents = contents.replace(self.rootDir, '${PETSC_DIR}') 332*5ee53db2SLisandro Dalcin contents = re.sub( 333*5ee53db2SLisandro Dalcin r'^(PYTHON(_EXE)?) = (.*)$', 334*5ee53db2SLisandro Dalcin r'\1 = python%d' % sys.version_info[0], 335*5ee53db2SLisandro Dalcin contents, flags=re.MULTILINE, 336*5ee53db2SLisandro Dalcin ) 337*5ee53db2SLisandro Dalcin with open(filename, 'w') as newFile: 338*5ee53db2SLisandro Dalcin newFile.write(contents) 339*5ee53db2SLisandro Dalcin # 340*5ee53db2SLisandro Dalcin def lsdir(dirname, *patterns): 341*5ee53db2SLisandro Dalcin return glob.glob(os.path.join(dirname, *patterns)) 342*5ee53db2SLisandro Dalcin def shell(*args): 343*5ee53db2SLisandro Dalcin return self.executeShellCommand(' '.join(args))[0] 344*5ee53db2SLisandro Dalcin libdir = os.path.join(self.installDir, 'lib') 345*5ee53db2SLisandro Dalcin if sys.platform == 'linux': 346*5ee53db2SLisandro Dalcin libraries = [ 347*5ee53db2SLisandro Dalcin lib for lib in lsdir(self.destLibDir, 'lib*.so*') 348*5ee53db2SLisandro Dalcin if not os.path.islink(lib) 349*5ee53db2SLisandro Dalcin ] 350*5ee53db2SLisandro Dalcin for shlib in libraries: 351*5ee53db2SLisandro Dalcin # fix shared library rpath 352*5ee53db2SLisandro Dalcin rpath = shell('patchelf', '--print-rpath', shlib) 353*5ee53db2SLisandro Dalcin rpath = rpath.split(os.path.pathsep) 354*5ee53db2SLisandro Dalcin if libdir in rpath: 355*5ee53db2SLisandro Dalcin rpath.insert(0, '$ORIGIN') 356*5ee53db2SLisandro Dalcin while libdir in rpath: 357*5ee53db2SLisandro Dalcin rpath.remove(libdir) 358*5ee53db2SLisandro Dalcin if rpath: 359*5ee53db2SLisandro Dalcin rpath = os.path.pathsep.join(rpath) 360*5ee53db2SLisandro Dalcin shell('patchelf', '--set-rpath', "'%s'" % rpath, shlib) 361*5ee53db2SLisandro Dalcin # fix shared library file and symlink 362*5ee53db2SLisandro Dalcin basename = os.path.basename(shlib) 363*5ee53db2SLisandro Dalcin libname, ext, _ = basename.partition('.so') 364*5ee53db2SLisandro Dalcin liblink = libname + ext 365*5ee53db2SLisandro Dalcin soname = shell('patchelf', '--print-soname', shlib) 366*5ee53db2SLisandro Dalcin for symlink in lsdir(self.destLibDir, liblink + '*'): 367*5ee53db2SLisandro Dalcin if os.path.islink(symlink): 368*5ee53db2SLisandro Dalcin os.unlink(symlink) 369*5ee53db2SLisandro Dalcin curdir = os.getcwd() 370*5ee53db2SLisandro Dalcin try: 371*5ee53db2SLisandro Dalcin os.chdir(os.path.dirname(shlib)) 372*5ee53db2SLisandro Dalcin if soname != basename: 373*5ee53db2SLisandro Dalcin os.rename(basename, soname) 374*5ee53db2SLisandro Dalcin if soname != liblink: 375*5ee53db2SLisandro Dalcin os.symlink(soname, liblink) 376*5ee53db2SLisandro Dalcin finally: 377*5ee53db2SLisandro Dalcin os.chdir(curdir) 378*5ee53db2SLisandro Dalcin if sys.platform == 'darwin': 379*5ee53db2SLisandro Dalcin def otool(cmd, dylib): 380*5ee53db2SLisandro Dalcin pattern = r''' 381*5ee53db2SLisandro Dalcin ^\s+ cmd \s %s$\n 382*5ee53db2SLisandro Dalcin ^\s+ cmdsize \s \d+$\n 383*5ee53db2SLisandro Dalcin ^\s+ (?:name|path) \s (.*) \s \(offset \s \d+\)$ 384*5ee53db2SLisandro Dalcin ''' % cmd 385*5ee53db2SLisandro Dalcin return re.findall( 386*5ee53db2SLisandro Dalcin pattern, shell('otool', '-l', dylib), 387*5ee53db2SLisandro Dalcin flags=re.VERBOSE | re.MULTILINE, 388*5ee53db2SLisandro Dalcin ) 389*5ee53db2SLisandro Dalcin libraries = [ 390*5ee53db2SLisandro Dalcin lib for lib in lsdir(self.destLibDir, 'lib*.dylib') 391*5ee53db2SLisandro Dalcin if not os.path.islink(lib) 392*5ee53db2SLisandro Dalcin ] 393*5ee53db2SLisandro Dalcin for dylib in libraries: 394*5ee53db2SLisandro Dalcin install_name = otool('LC_ID_DYLIB', dylib)[0] 395*5ee53db2SLisandro Dalcin dependencies = otool('LC_LOAD_DYLIB', dylib) 396*5ee53db2SLisandro Dalcin runtime_path = otool('LC_RPATH', dylib) 397*5ee53db2SLisandro Dalcin # fix shared library install name and rpath 398*5ee53db2SLisandro Dalcin install_name = '@rpath/' + os.path.basename(install_name) 399*5ee53db2SLisandro Dalcin shell('install_name_tool', '-id', install_name, dylib) 400*5ee53db2SLisandro Dalcin if libdir in runtime_path: 401*5ee53db2SLisandro Dalcin shell('install_name_tool', '-delete_rpath', libdir, dylib) 402*5ee53db2SLisandro Dalcin for rpath in ('@loader_path',): 403*5ee53db2SLisandro Dalcin if rpath not in runtime_path: 404*5ee53db2SLisandro Dalcin shell('install_name_tool', '-add_rpath', rpath, dylib) 405*5ee53db2SLisandro Dalcin for dep in dependencies: 406*5ee53db2SLisandro Dalcin if os.path.dirname(dep) in (libdir,): 407*5ee53db2SLisandro Dalcin newid = '@rpath/' + os.path.basename(dep) 408*5ee53db2SLisandro Dalcin shell('install_name_tool', '-change', dep, newid, dylib) 409*5ee53db2SLisandro Dalcin # fix shared library file and symlink 410*5ee53db2SLisandro Dalcin basename = os.path.basename(dylib) 411*5ee53db2SLisandro Dalcin libname, ext = os.path.splitext(basename) 412*5ee53db2SLisandro Dalcin libname = libname.partition('.')[0] 413*5ee53db2SLisandro Dalcin liblink = libname + ext 414*5ee53db2SLisandro Dalcin dyname = os.path.basename(install_name) 415*5ee53db2SLisandro Dalcin for symlink in lsdir(self.destLibDir, libname + '*' + ext): 416*5ee53db2SLisandro Dalcin if os.path.islink(symlink): 417*5ee53db2SLisandro Dalcin os.unlink(symlink) 418*5ee53db2SLisandro Dalcin curdir = os.getcwd() 419*5ee53db2SLisandro Dalcin try: 420*5ee53db2SLisandro Dalcin os.chdir(os.path.dirname(dylib)) 421*5ee53db2SLisandro Dalcin if dyname != basename: 422*5ee53db2SLisandro Dalcin os.rename(basename, dyname) 423*5ee53db2SLisandro Dalcin if dyname != liblink: 424*5ee53db2SLisandro Dalcin os.symlink(dyname, liblink) 425*5ee53db2SLisandro Dalcin finally: 426*5ee53db2SLisandro Dalcin os.chdir(curdir) 427*5ee53db2SLisandro Dalcin # 428*5ee53db2SLisandro Dalcin return 429*5ee53db2SLisandro Dalcin 4300ee81e68SLisandro Dalcin def createUninstaller(self): 4310ee81e68SLisandro Dalcin uninstallscript = os.path.join(self.destConfDir, 'uninstall.py') 4320ee81e68SLisandro Dalcin f = open(uninstallscript, 'w') 4330ee81e68SLisandro Dalcin # Could use the Python AST to do this 4340ee81e68SLisandro Dalcin f.write('#!'+sys.executable+'\n') 4350ee81e68SLisandro Dalcin f.write('import os\n') 436d97f9ea1SSatish Balay f.write('prefixdir = "'+self.installDir+'"\n') 437d97f9ea1SSatish Balay files = [dst.replace(self.destDir,self.installDir) for src, dst in self.copies] 438d97f9ea1SSatish Balay files.append(uninstallscript.replace(self.destDir,self.installDir)) 439d97f9ea1SSatish Balay f.write('files = '+repr(files)) 4400ee81e68SLisandro Dalcin f.write(''' 441d97f9ea1SSatish Balayfor file in files: 442d97f9ea1SSatish Balay if os.path.exists(file) or os.path.islink(file): 443d97f9ea1SSatish Balay os.remove(file) 444d97f9ea1SSatish Balay dir = os.path.dirname(file) 4452b39596bSSatish Balay while dir not in [os.path.dirname(prefixdir),'/']: 4462b39596bSSatish Balay try: os.rmdir(dir) 4472b39596bSSatish Balay except: break 448d97f9ea1SSatish Balay dir = os.path.dirname(dir) 4490ee81e68SLisandro Dalcin''') 4500ee81e68SLisandro Dalcin f.close() 4515b6bfdb9SJed Brown os.chmod(uninstallscript,0o744) 4520ee81e68SLisandro Dalcin return 4530ee81e68SLisandro Dalcin 4540ee81e68SLisandro Dalcin def installIncludes(self): 45532cabb2fSBarry Smith exclude = ['makefile'] 45632cabb2fSBarry Smith if not hasattr(self.compilers.setCompilers, 'FC'): 45732cabb2fSBarry Smith exclude.append('finclude') 45832cabb2fSBarry Smith if not self.mpi.usingMPIUni: 45932cabb2fSBarry Smith exclude.append('mpiuni') 46032cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude)) 4610ee81e68SLisandro Dalcin self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir)) 4620ee81e68SLisandro Dalcin return 4630ee81e68SLisandro Dalcin 4640ee81e68SLisandro Dalcin def installConf(self): 46532cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log'])) 466a035e9faSPierre Jolivet self.copies.extend(self.copytree(self.archConfDir, self.destConfDir, exclude = ['sowing', 'configure.log.bkp','configure.log','make.log','gmake.log','test.log','error.log','memoryerror.log','files','testfiles','RDict.db'])) 4670ee81e68SLisandro Dalcin return 4680ee81e68SLisandro Dalcin 4690ee81e68SLisandro Dalcin def installBin(self): 47032cabb2fSBarry Smith exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml'] 47132cabb2fSBarry Smith self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude )) 47232cabb2fSBarry Smith exclude = ['maint'] 47332cabb2fSBarry Smith if not self.mpi.usingMPIUni: 47432cabb2fSBarry Smith exclude.append('petsc-mpiexec.uni') 47532cabb2fSBarry Smith self.setCompilers.pushLanguage('C') 476011f288aSSatish Balay if self.setCompilers.getCompiler().find('win32fe') < 0: 47732cabb2fSBarry Smith exclude.append('win32fe') 47832cabb2fSBarry Smith self.setCompilers.popLanguage() 47932cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude )) 4800ee81e68SLisandro Dalcin return 4810ee81e68SLisandro Dalcin 4820ee81e68SLisandro Dalcin def installShare(self): 4830ee81e68SLisandro Dalcin self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir)) 484c173c275SScott Kruger examplesdir=os.path.join(self.destShareDir,'petsc','examples') 485c173c275SScott Kruger if os.path.exists(examplesdir): 486c173c275SScott Kruger shutil.rmtree(examplesdir) 487c173c275SScott Kruger os.mkdir(examplesdir) 48879eaf171SScott Kruger os.mkdir(os.path.join(examplesdir,'src')) 489c173c275SScott Kruger self.copyConfig(self.rootDir,examplesdir) 490fad83eadSPatrick Sanan if not self.argDB['no-examples']: 491fad83eadSPatrick Sanan self.copyExamples(self.rootSrcDir,os.path.join(examplesdir,'src')) 492c173c275SScott Kruger self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test')) 4930ee81e68SLisandro Dalcin return 4940ee81e68SLisandro Dalcin 4950ee81e68SLisandro Dalcin def copyLib(self, src, dst): 4960ee81e68SLisandro Dalcin '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac''' 4970ee81e68SLisandro Dalcin # Symlinks (assumed local) are recreated at dst 4980ee81e68SLisandro Dalcin if os.path.islink(src): 4990ee81e68SLisandro Dalcin linkto = os.readlink(src) 5000ee81e68SLisandro Dalcin try: 5010ee81e68SLisandro Dalcin os.remove(dst) # In case it already exists 5020ee81e68SLisandro Dalcin except OSError: 5030ee81e68SLisandro Dalcin pass 5040ee81e68SLisandro Dalcin os.symlink(linkto, dst) 5050ee81e68SLisandro Dalcin return 5060ee81e68SLisandro Dalcin shutil.copy2(src, dst) 507011f288aSSatish Balay if self.setCompilers.getCompiler().find('win32fe') < 0 and os.path.splitext(dst)[1] == '.'+self.arLibSuffix: 5080ee81e68SLisandro Dalcin self.executeShellCommand(self.ranlib+' '+dst) 5090ee81e68SLisandro Dalcin if os.path.splitext(dst)[1] == '.dylib' and os.path.isfile('/usr/bin/install_name_tool'): 510af2c601bSBarry Smith [output,err,flg] = self.executeShellCommand("otool -D "+src) 511af2c601bSBarry Smith oldname = output[output.find("\n")+1:] 512d4c3e6c5SSatish Balay installName = oldname.replace(os.path.realpath(self.archDir), self.installDir) 5130ee81e68SLisandro Dalcin self.executeShellCommand('/usr/bin/install_name_tool -id ' + installName + ' ' + dst) 5140ee81e68SLisandro Dalcin # preserve the original timestamps - so that the .a vs .so time order is preserved 5150ee81e68SLisandro Dalcin shutil.copystat(src,dst) 5160ee81e68SLisandro Dalcin return 5170ee81e68SLisandro Dalcin 5180ee81e68SLisandro Dalcin def installLib(self): 51932cabb2fSBarry Smith self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 52032cabb2fSBarry Smith self.copies.extend(self.copytree(os.path.join(self.archLibDir,'pkgconfig'), os.path.join(self.destLibDir,'pkgconfig'), copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 5210ee81e68SLisandro Dalcin return 5220ee81e68SLisandro Dalcin 5230ee81e68SLisandro Dalcin 5240ee81e68SLisandro Dalcin def outputInstallDone(self): 5255b4fc442SVaclav Hapla from config.packages.make import getMakeUserPath 5265b6bfdb9SJed Brown print('''\ 5270ee81e68SLisandro Dalcin==================================== 5280ee81e68SLisandro DalcinInstall complete. 5290ee81e68SLisandro DalcinNow to check if the libraries are working do (in current directory): 5305b4fc442SVaclav Hapla%s PETSC_DIR=%s PETSC_ARCH="" check 5310ee81e68SLisandro Dalcin====================================\ 5325b4fc442SVaclav Hapla''' % (getMakeUserPath(self.arch), self.installDir)) 5330ee81e68SLisandro Dalcin return 5340ee81e68SLisandro Dalcin 5350ee81e68SLisandro Dalcin def outputDestDirDone(self): 5365b6bfdb9SJed Brown print('''\ 5370ee81e68SLisandro Dalcin==================================== 5380ee81e68SLisandro DalcinCopy to DESTDIR %s is now complete. 5390ee81e68SLisandro DalcinBefore use - please copy/install over to specified prefix: %s 5400ee81e68SLisandro Dalcin====================================\ 5415b6bfdb9SJed Brown''' % (self.destDir,self.installDir)) 5420ee81e68SLisandro Dalcin return 5430ee81e68SLisandro Dalcin 5440ee81e68SLisandro Dalcin def runsetup(self): 5450ee81e68SLisandro Dalcin self.setup() 5460ee81e68SLisandro Dalcin self.setupDirectories() 5470ee81e68SLisandro Dalcin self.checkPrefix() 5480ee81e68SLisandro Dalcin self.checkDestdir() 5490ee81e68SLisandro Dalcin return 5500ee81e68SLisandro Dalcin 5510ee81e68SLisandro Dalcin def runcopy(self): 5520ee81e68SLisandro Dalcin if self.destDir == self.installDir: 5535b6bfdb9SJed Brown print('*** Installing PETSc at prefix location:',self.destDir, ' ***') 5540ee81e68SLisandro Dalcin else: 5555b6bfdb9SJed Brown print('*** Copying PETSc to DESTDIR location:',self.destDir, ' ***') 5560ee81e68SLisandro Dalcin if not os.path.exists(self.destDir): 5570ee81e68SLisandro Dalcin try: 5580ee81e68SLisandro Dalcin os.makedirs(self.destDir) 5590ee81e68SLisandro Dalcin except: 5605b6bfdb9SJed Brown print('********************************************************************') 5615b6bfdb9SJed Brown print('Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"') 5625b6bfdb9SJed Brown print('********************************************************************') 5630ee81e68SLisandro Dalcin sys.exit(1) 5640ee81e68SLisandro Dalcin self.installIncludes() 5650ee81e68SLisandro Dalcin self.installConf() 5660ee81e68SLisandro Dalcin self.installBin() 5670ee81e68SLisandro Dalcin self.installLib() 5680ee81e68SLisandro Dalcin self.installShare() 569*5ee53db2SLisandro Dalcin self.createUninstaller() 5700ee81e68SLisandro Dalcin return 5710ee81e68SLisandro Dalcin 5720ee81e68SLisandro Dalcin def runfix(self): 5730ee81e68SLisandro Dalcin self.fixConf() 574*5ee53db2SLisandro Dalcin if os.environ.get('PEP517_BUILD_BACKEND'): 575*5ee53db2SLisandro Dalcin self.fixPythonWheel() 5760ee81e68SLisandro Dalcin return 5770ee81e68SLisandro Dalcin 5780ee81e68SLisandro Dalcin def rundone(self): 5790ee81e68SLisandro Dalcin if self.destDir == self.installDir: 5800ee81e68SLisandro Dalcin self.outputInstallDone() 5810ee81e68SLisandro Dalcin else: 5820ee81e68SLisandro Dalcin self.outputDestDirDone() 5830ee81e68SLisandro Dalcin return 5840ee81e68SLisandro Dalcin 5850ee81e68SLisandro Dalcin def run(self): 5860ee81e68SLisandro Dalcin self.runsetup() 5870ee81e68SLisandro Dalcin self.runcopy() 5880ee81e68SLisandro Dalcin self.runfix() 5890ee81e68SLisandro Dalcin self.rundone() 5900ee81e68SLisandro Dalcin return 5910ee81e68SLisandro Dalcin 5920ee81e68SLisandro Dalcinif __name__ == '__main__': 5930ee81e68SLisandro Dalcin Installer(sys.argv[1:]).run() 5940ee81e68SLisandro Dalcin # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 59503e6d329SSatish Balay delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp'] 5960ee81e68SLisandro Dalcin for delfile in delfiles: 5970ee81e68SLisandro Dalcin if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 5980ee81e68SLisandro Dalcin os.remove(delfile) 599