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') 842d10696aSSatish Balay self.installLibDir = os.path.join(self.installDir, 'lib') 85c3a89c15SBarry Smith self.installBinDir = os.path.join(self.installDir, 'lib','petsc','bin') 860ee81e68SLisandro Dalcin self.rootShareDir = os.path.join(self.rootDir, 'share') 870ee81e68SLisandro Dalcin self.destShareDir = os.path.join(self.destDir, 'share') 8879eaf171SScott Kruger self.rootSrcDir = os.path.join(self.rootDir, 'src') 890ee81e68SLisandro Dalcin 900ee81e68SLisandro Dalcin self.ranlib = self.compilers.RANLIB 910ee81e68SLisandro Dalcin self.arLibSuffix = self.compilers.AR_LIB_SUFFIX 920ee81e68SLisandro Dalcin return 930ee81e68SLisandro Dalcin 940ee81e68SLisandro Dalcin def checkPrefix(self): 950ee81e68SLisandro Dalcin if not self.installDir: 965b6bfdb9SJed Brown print('********************************************************************') 975b6bfdb9SJed Brown print('PETSc is built without prefix option. So "make install" is not appropriate.') 985b6bfdb9SJed Brown print('If you need a prefix install of PETSc - rerun configure with --prefix option.') 995b6bfdb9SJed Brown print('********************************************************************') 1000ee81e68SLisandro Dalcin sys.exit(1) 1010ee81e68SLisandro Dalcin return 1020ee81e68SLisandro Dalcin 1030ee81e68SLisandro Dalcin def checkDestdir(self): 1040ee81e68SLisandro Dalcin if os.path.exists(self.destDir): 1050ee81e68SLisandro Dalcin if os.path.samefile(self.destDir, self.rootDir): 1065b6bfdb9SJed Brown print('********************************************************************') 1075b6bfdb9SJed Brown print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR') 1085b6bfdb9SJed Brown print('********************************************************************') 1090ee81e68SLisandro Dalcin sys.exit(1) 1100ee81e68SLisandro Dalcin if os.path.samefile(self.destDir, os.path.join(self.rootDir,self.arch)): 1115b6bfdb9SJed Brown print('********************************************************************') 1125b6bfdb9SJed Brown print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR/PETSC_ARCH') 1135b6bfdb9SJed Brown print('********************************************************************') 1140ee81e68SLisandro Dalcin sys.exit(1) 1150ee81e68SLisandro Dalcin if not os.path.isdir(os.path.realpath(self.destDir)): 1165b6bfdb9SJed Brown print('********************************************************************') 1175b6bfdb9SJed Brown print('Specified destDir', self.destDir, 'is not a directory. Cannot proceed!') 1185b6bfdb9SJed Brown print('********************************************************************') 1190ee81e68SLisandro Dalcin sys.exit(1) 1200ee81e68SLisandro Dalcin if not os.access(self.destDir, os.W_OK): 1215b6bfdb9SJed Brown print('********************************************************************') 1225b6bfdb9SJed Brown print('Unable to write to ', self.destDir, 'Perhaps you need to do "sudo make install"') 1235b6bfdb9SJed Brown print('********************************************************************') 1240ee81e68SLisandro Dalcin sys.exit(1) 1250ee81e68SLisandro Dalcin return 1260ee81e68SLisandro Dalcin 1270ee81e68SLisandro Dalcin def copyfile(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 1280ee81e68SLisandro Dalcin """Copies a single file """ 1290ee81e68SLisandro Dalcin copies = [] 1300ee81e68SLisandro Dalcin errors = [] 1310ee81e68SLisandro Dalcin if not os.path.exists(dst): 1320ee81e68SLisandro Dalcin os.makedirs(dst) 1330ee81e68SLisandro Dalcin elif not os.path.isdir(dst): 1345b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 1350ee81e68SLisandro Dalcin srcname = src 1360ee81e68SLisandro Dalcin dstname = os.path.join(dst, os.path.basename(src)) 1370ee81e68SLisandro Dalcin try: 1380ee81e68SLisandro Dalcin if symlinks and os.path.islink(srcname): 1390ee81e68SLisandro Dalcin linkto = os.readlink(srcname) 1400ee81e68SLisandro Dalcin os.symlink(linkto, dstname) 1410ee81e68SLisandro Dalcin else: 1420ee81e68SLisandro Dalcin copyFunc(srcname, dstname) 1430ee81e68SLisandro Dalcin copies.append((srcname, dstname)) 1445b6bfdb9SJed Brown except (IOError, os.error) as why: 1450ee81e68SLisandro Dalcin errors.append((srcname, dstname, str(why))) 1465b6bfdb9SJed Brown except shutil.Error as err: 1472c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 1480ee81e68SLisandro Dalcin if errors: 1495b6bfdb9SJed Brown raise shutil.Error(errors) 1500ee81e68SLisandro Dalcin return copies 1510ee81e68SLisandro Dalcin 15226e8aaceSBarry Smith def fixExamplesMakefile(self, src): 15326e8aaceSBarry Smith '''Change ././${PETSC_ARCH} in makefile in root petsc directory with ${PETSC_DIR}''' 15426e8aaceSBarry Smith lines = [] 15526e8aaceSBarry Smith oldFile = open(src, 'r') 156e551db17SScott Kruger alllines=oldFile.read() 15726e8aaceSBarry Smith oldFile.close() 158e551db17SScott Kruger newlines=alllines.split('\n')[0]+'\n' # Firstline 159d5b43468SJose E. Roman # Hardcode PETSC_DIR and PETSC_ARCH to avoid users doing the wrong thing 160e551db17SScott Kruger newlines+='PETSC_DIR='+self.installDir+'\n' 161e551db17SScott Kruger newlines+='PETSC_ARCH=\n' 162e551db17SScott Kruger for line in alllines.split('\n')[1:]: 1634ff3c6a1SScott Kruger if line.startswith('TESTLOGFILE'): 164c173c275SScott Kruger newlines+='TESTLOGFILE = $(TESTDIR)/examples-install.log\n' 165e551db17SScott Kruger elif line.startswith('CONFIGDIR'): 166e551db17SScott Kruger newlines+='CONFIGDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples/config\n' 167fc46264cSScott Kruger elif line.startswith('$(generatedtest)') and 'petscvariables' in line: 168c173c275SScott Kruger newlines+='all: test\n\n'+line+'\n' 169e551db17SScott Kruger else: 1704ff3c6a1SScott Kruger newlines+=line+'\n' 17126e8aaceSBarry Smith newFile = open(src, 'w') 172e551db17SScott Kruger newFile.write(newlines) 17326e8aaceSBarry Smith newFile.close() 17426e8aaceSBarry Smith return 17526e8aaceSBarry Smith 176e551db17SScott Kruger def copyConfig(self, src, dst): 1772f21b5d8SJed Brown """Copy configuration/testing files 178e551db17SScott Kruger """ 179e551db17SScott Kruger if not os.path.isdir(dst): 1805b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 181e551db17SScott Kruger 182adf35c6eSSatish Balay self.copies.extend(self.copyfile('gmakefile.test',dst)) 183e551db17SScott Kruger newConfigDir=os.path.join(dst,'config') # Am not renaming at present 184e551db17SScott Kruger if not os.path.isdir(newConfigDir): os.mkdir(newConfigDir) 185e551db17SScott Kruger testConfFiles="gmakegentest.py gmakegen.py testparse.py example_template.py".split() 18658780e5dSStefano Zampini testConfFiles+="petsc_harness.sh report_tests.py query_tests.py".split() 187e551db17SScott Kruger for tf in testConfFiles: 188adf35c6eSSatish Balay self.copies.extend(self.copyfile(os.path.join('config',tf),newConfigDir)) 189e551db17SScott Kruger return 190e551db17SScott Kruger 19126e8aaceSBarry Smith def copyExamples(self, src, dst): 1924ff3c6a1SScott Kruger """copy the examples directories 19326e8aaceSBarry Smith """ 194ad246c4dSSatish Balay for root, dirs, files in os.walk(src, topdown=False): 1952f21b5d8SJed Brown if os.path.basename(root) not in ("tests", "tutorials"): continue 196ad246c4dSSatish Balay self.copies.extend(self.copytree(root, root.replace(src,dst))) 1974ff3c6a1SScott Kruger return 1980ee81e68SLisandro Dalcin 1990080bb28SSatish Balay def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2, exclude = [], exclude_ext= ['.DSYM','.o','.pyc'], recurse = 1): 2000ee81e68SLisandro Dalcin """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 2010ee81e68SLisandro Dalcin 2020ee81e68SLisandro Dalcin The copyFunc() you provide is only used on the top level, lower levels always use shutil.copy2 2030ee81e68SLisandro Dalcin 2040ee81e68SLisandro Dalcin The destination directory must not already exist. 2050ee81e68SLisandro Dalcin If exception(s) occur, an shutil.Error is raised with a list of reasons. 2060ee81e68SLisandro Dalcin 2070ee81e68SLisandro Dalcin If the optional symlinks flag is true, symbolic links in the 2080ee81e68SLisandro Dalcin source tree result in symbolic links in the destination tree; if 2090ee81e68SLisandro Dalcin it is false, the contents of the files pointed to by symbolic 2100ee81e68SLisandro Dalcin links are copied. 2110ee81e68SLisandro Dalcin """ 2120ee81e68SLisandro Dalcin copies = [] 2130ee81e68SLisandro Dalcin names = os.listdir(src) 2140ee81e68SLisandro Dalcin if not os.path.exists(dst): 2150ee81e68SLisandro Dalcin os.makedirs(dst) 2160ee81e68SLisandro Dalcin elif not os.path.isdir(dst): 2175b6bfdb9SJed Brown raise shutil.Error('Destination is not a directory') 2180ee81e68SLisandro Dalcin errors = [] 2192c72da00SPierre Jolivet srclinks = [] 2202c72da00SPierre Jolivet dstlinks = [] 2210ee81e68SLisandro Dalcin for name in names: 2220ee81e68SLisandro Dalcin srcname = os.path.join(src, name) 2230ee81e68SLisandro Dalcin dstname = os.path.join(dst, name) 2240ee81e68SLisandro Dalcin try: 2250ee81e68SLisandro Dalcin if symlinks and os.path.islink(srcname): 2260ee81e68SLisandro Dalcin linkto = os.readlink(srcname) 2270ee81e68SLisandro Dalcin os.symlink(linkto, dstname) 22832cabb2fSBarry Smith elif os.path.isdir(srcname) and recurse and not os.path.basename(srcname) in exclude: 229adf35c6eSSatish Balay copies.extend(self.copytree(srcname, dstname, symlinks,exclude = exclude, exclude_ext = exclude_ext)) 230adf35c6eSSatish Balay elif os.path.isfile(srcname) and not os.path.basename(srcname) in exclude and os.path.splitext(name)[1] not in exclude_ext : 2312c72da00SPierre Jolivet if os.path.islink(srcname): 2322c72da00SPierre Jolivet srclinks.append(srcname) 2332c72da00SPierre Jolivet dstlinks.append(dstname) 2342c72da00SPierre Jolivet else: 2350ee81e68SLisandro Dalcin copyFunc(srcname, dstname) 2360ee81e68SLisandro Dalcin copies.append((srcname, dstname)) 2370ee81e68SLisandro Dalcin # XXX What about devices, sockets etc.? 2385b6bfdb9SJed Brown except (IOError, os.error) as why: 2390ee81e68SLisandro Dalcin errors.append((srcname, dstname, str(why))) 2400ee81e68SLisandro Dalcin # catch the Error from the recursive copytree so that we can 2410ee81e68SLisandro Dalcin # continue with other files 2425b6bfdb9SJed Brown except shutil.Error as err: 2432c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 2442c72da00SPierre Jolivet for srcname, dstname in zip(srclinks, dstlinks): 2452c72da00SPierre Jolivet try: 2462c72da00SPierre Jolivet copyFunc(srcname, dstname) 2472c72da00SPierre Jolivet copies.append((srcname, dstname)) 2482c72da00SPierre Jolivet except (IOError, os.error) as why: 2492c72da00SPierre Jolivet errors.append((srcname, dstname, str(why))) 2502c72da00SPierre Jolivet # catch the Error from the recursive copytree so that we can 2512c72da00SPierre Jolivet # continue with other files 2522c72da00SPierre Jolivet except shutil.Error as err: 2532c852529SBarry Smith errors.append((srcname,dstname,str(err.args[0]))) 2540ee81e68SLisandro Dalcin try: 2550ee81e68SLisandro Dalcin shutil.copystat(src, dst) 2565b6bfdb9SJed Brown except OSError as e: 2570ee81e68SLisandro Dalcin if WindowsError is not None and isinstance(e, WindowsError): 2580ee81e68SLisandro Dalcin # Copying file access times may fail on Windows 2590ee81e68SLisandro Dalcin pass 2600ee81e68SLisandro Dalcin else: 2612c852529SBarry Smith errors.append((src, dst, str(e))) 2620ee81e68SLisandro Dalcin if errors: 2635b6bfdb9SJed Brown raise shutil.Error(errors) 2640ee81e68SLisandro Dalcin return copies 2650ee81e68SLisandro Dalcin 2660ee81e68SLisandro Dalcin 2670ee81e68SLisandro Dalcin def fixConfFile(self, src): 2680ee81e68SLisandro Dalcin lines = [] 2690ee81e68SLisandro Dalcin oldFile = open(src, 'r') 2700ee81e68SLisandro Dalcin for line in oldFile.readlines(): 2715a21677cSJed Brown if line.startswith('PETSC_CC_INCLUDES =') or line.startswith('PETSC_FC_INCLUDES ='): 2725a21677cSJed Brown continue 2735a21677cSJed Brown line = line.replace('PETSC_CC_INCLUDES_INSTALL', 'PETSC_CC_INCLUDES') 2745a21677cSJed Brown line = line.replace('PETSC_FC_INCLUDES_INSTALL', 'PETSC_FC_INCLUDES') 2750ee81e68SLisandro Dalcin # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 2760ee81e68SLisandro Dalcin line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir) 2770ee81e68SLisandro Dalcin line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '') 2780ee81e68SLisandro Dalcin line = line.replace('${PETSC_DIR}', self.installDir) 2792d10696aSSatish Balay # replace PETSC_DIR/PETSC_ARCH/lib (i.e., build location) with prefix/lib 2802d10696aSSatish Balay line = line.replace(self.archLibDir,self.installLibDir) 281011f288aSSatish Balay # replace PETSC_DIR/lib/petsc/bin with prefix/lib/petsc/bin 282011f288aSSatish Balay line = line.replace(self.rootBinDir,self.destBinDir) 2830ee81e68SLisandro Dalcin lines.append(line) 2840ee81e68SLisandro Dalcin oldFile.close() 2850ee81e68SLisandro Dalcin newFile = open(src, 'w') 2860ee81e68SLisandro Dalcin newFile.write(''.join(lines)) 2870ee81e68SLisandro Dalcin newFile.close() 2880ee81e68SLisandro Dalcin return 2890ee81e68SLisandro Dalcin 2900ee81e68SLisandro Dalcin def fixConf(self): 2910ee81e68SLisandro Dalcin import shutil 292cb5db241SBarry Smith for file in ['rules', 'rules_doc.mk', 'rules_util.mk', 'variables', 'petscrules', 'petscvariables']: 2930ee81e68SLisandro Dalcin self.fixConfFile(os.path.join(self.destConfDir,file)) 2940ee81e68SLisandro Dalcin return 2950ee81e68SLisandro Dalcin 2965ee53db2SLisandro Dalcin def fixPythonWheel(self): 2975ee53db2SLisandro Dalcin import glob 2985ee53db2SLisandro Dalcin import shutil 2995ee53db2SLisandro Dalcin # 3005ee53db2SLisandro Dalcin for pattern in ( 3015ee53db2SLisandro Dalcin self.destLibDir + '/*.a', 3025ee53db2SLisandro Dalcin self.destLibDir + '/*.la', 3035ee53db2SLisandro Dalcin self.destLibDir + '/pkgconfig', # TODO: keep? 3045ee53db2SLisandro Dalcin self.destConfDir + '/configure-hash', 3055ee53db2SLisandro Dalcin self.destConfDir + '/uninstall.py', 3065ee53db2SLisandro Dalcin self.destConfDir + '/reconfigure-*.py', 3075ee53db2SLisandro Dalcin self.destConfDir + '/pkg.conf.*', 3085ee53db2SLisandro Dalcin self.destConfDir + '/pkg.git*.*', 3095ee53db2SLisandro Dalcin self.destConfDir + '/modules', # TODO: keep? 3105ee53db2SLisandro Dalcin self.destShareDir + '/*/examples/src/*', 3115ee53db2SLisandro Dalcin self.destShareDir + '/*/datafiles', 3125ee53db2SLisandro Dalcin ): 3135ee53db2SLisandro Dalcin for pathname in glob.glob(pattern): 3145ee53db2SLisandro Dalcin if os.path.isdir(pathname): 3155ee53db2SLisandro Dalcin shutil.rmtree(pathname) 3165ee53db2SLisandro Dalcin elif os.path.exists(pathname): 3175ee53db2SLisandro Dalcin os.remove(pathname) 3185ee53db2SLisandro Dalcin # 3195ee53db2SLisandro Dalcin for filename in ( 3205ee53db2SLisandro Dalcin self.destIncludeDir + '/petscconf.h', 3215ee53db2SLisandro Dalcin self.destIncludeDir + '/petscconfiginfo.h', 3225ee53db2SLisandro Dalcin self.destIncludeDir + '/petscmachineinfo.h', 3235ee53db2SLisandro Dalcin self.destShareDir + '/petsc/examples/gmakefile.test', 3245ee53db2SLisandro Dalcin self.destConfDir + '/rules', 3255ee53db2SLisandro Dalcin self.destConfDir + '/rules_doc.mk', 3265ee53db2SLisandro Dalcin self.destConfDir + '/rules_util.mk', 3275ee53db2SLisandro Dalcin self.destConfDir + '/petscrules', 3285ee53db2SLisandro Dalcin self.destConfDir + '/variables', 3295ee53db2SLisandro Dalcin self.destConfDir + '/petscvariables', 3305ee53db2SLisandro Dalcin ): 3315ee53db2SLisandro Dalcin with open(filename, 'r') as oldFile: 3325ee53db2SLisandro Dalcin contents = oldFile.read() 3335ee53db2SLisandro Dalcin contents = contents.replace(self.installDir, '${PETSC_DIR}') 3345ee53db2SLisandro Dalcin contents = contents.replace(self.rootDir, '${PETSC_DIR}') 3355ee53db2SLisandro Dalcin contents = re.sub( 3365ee53db2SLisandro Dalcin r'^(PYTHON(_EXE)?) = (.*)$', 3375ee53db2SLisandro Dalcin r'\1 = python%d' % sys.version_info[0], 3385ee53db2SLisandro Dalcin contents, flags=re.MULTILINE, 3395ee53db2SLisandro Dalcin ) 3405ee53db2SLisandro Dalcin with open(filename, 'w') as newFile: 3415ee53db2SLisandro Dalcin newFile.write(contents) 3425ee53db2SLisandro Dalcin # 3435ee53db2SLisandro Dalcin def lsdir(dirname, *patterns): 3445ee53db2SLisandro Dalcin return glob.glob(os.path.join(dirname, *patterns)) 3455ee53db2SLisandro Dalcin def shell(*args): 3465ee53db2SLisandro Dalcin return self.executeShellCommand(' '.join(args))[0] 3475ee53db2SLisandro Dalcin libdir = os.path.join(self.installDir, 'lib') 3485ee53db2SLisandro Dalcin if sys.platform == 'linux': 3495ee53db2SLisandro Dalcin libraries = [ 3505ee53db2SLisandro Dalcin lib for lib in lsdir(self.destLibDir, 'lib*.so*') 3515ee53db2SLisandro Dalcin if not os.path.islink(lib) 3525ee53db2SLisandro Dalcin ] 3535ee53db2SLisandro Dalcin for shlib in libraries: 3545ee53db2SLisandro Dalcin # fix shared library rpath 3555ee53db2SLisandro Dalcin rpath = shell('patchelf', '--print-rpath', shlib) 3565ee53db2SLisandro Dalcin rpath = rpath.split(os.path.pathsep) 3575ee53db2SLisandro Dalcin if libdir in rpath: 3585ee53db2SLisandro Dalcin rpath.insert(0, '$ORIGIN') 3595ee53db2SLisandro Dalcin while libdir in rpath: 3605ee53db2SLisandro Dalcin rpath.remove(libdir) 3615ee53db2SLisandro Dalcin if rpath: 3625ee53db2SLisandro Dalcin rpath = os.path.pathsep.join(rpath) 3635ee53db2SLisandro Dalcin shell('patchelf', '--set-rpath', "'%s'" % rpath, shlib) 3645ee53db2SLisandro Dalcin # fix shared library file and symlink 3655ee53db2SLisandro Dalcin basename = os.path.basename(shlib) 3665ee53db2SLisandro Dalcin libname, ext, _ = basename.partition('.so') 3675ee53db2SLisandro Dalcin liblink = libname + ext 3685ee53db2SLisandro Dalcin soname = shell('patchelf', '--print-soname', shlib) 3695ee53db2SLisandro Dalcin for symlink in lsdir(self.destLibDir, liblink + '*'): 3705ee53db2SLisandro Dalcin if os.path.islink(symlink): 3715ee53db2SLisandro Dalcin os.unlink(symlink) 3725ee53db2SLisandro Dalcin curdir = os.getcwd() 3735ee53db2SLisandro Dalcin try: 3745ee53db2SLisandro Dalcin os.chdir(os.path.dirname(shlib)) 3755ee53db2SLisandro Dalcin if soname != basename: 3765ee53db2SLisandro Dalcin os.rename(basename, soname) 3775ee53db2SLisandro Dalcin if soname != liblink: 3785ee53db2SLisandro Dalcin os.symlink(soname, liblink) 3795ee53db2SLisandro Dalcin finally: 3805ee53db2SLisandro Dalcin os.chdir(curdir) 3815ee53db2SLisandro Dalcin if sys.platform == 'darwin': 3825ee53db2SLisandro Dalcin def otool(cmd, dylib): 3835ee53db2SLisandro Dalcin pattern = r''' 3845ee53db2SLisandro Dalcin ^\s+ cmd \s %s$\n 3855ee53db2SLisandro Dalcin ^\s+ cmdsize \s \d+$\n 3865ee53db2SLisandro Dalcin ^\s+ (?:name|path) \s (.*) \s \(offset \s \d+\)$ 3875ee53db2SLisandro Dalcin ''' % cmd 3885ee53db2SLisandro Dalcin return re.findall( 3895ee53db2SLisandro Dalcin pattern, shell('otool', '-l', dylib), 3905ee53db2SLisandro Dalcin flags=re.VERBOSE | re.MULTILINE, 3915ee53db2SLisandro Dalcin ) 3925ee53db2SLisandro Dalcin libraries = [ 3935ee53db2SLisandro Dalcin lib for lib in lsdir(self.destLibDir, 'lib*.dylib') 3945ee53db2SLisandro Dalcin if not os.path.islink(lib) 3955ee53db2SLisandro Dalcin ] 3965ee53db2SLisandro Dalcin for dylib in libraries: 3975ee53db2SLisandro Dalcin install_name = otool('LC_ID_DYLIB', dylib)[0] 3985ee53db2SLisandro Dalcin dependencies = otool('LC_LOAD_DYLIB', dylib) 3995ee53db2SLisandro Dalcin runtime_path = otool('LC_RPATH', dylib) 4005ee53db2SLisandro Dalcin # fix shared library install name and rpath 4015ee53db2SLisandro Dalcin install_name = '@rpath/' + os.path.basename(install_name) 4025ee53db2SLisandro Dalcin shell('install_name_tool', '-id', install_name, dylib) 4035ee53db2SLisandro Dalcin if libdir in runtime_path: 4045ee53db2SLisandro Dalcin shell('install_name_tool', '-delete_rpath', libdir, dylib) 4055ee53db2SLisandro Dalcin for rpath in ('@loader_path',): 4065ee53db2SLisandro Dalcin if rpath not in runtime_path: 4075ee53db2SLisandro Dalcin shell('install_name_tool', '-add_rpath', rpath, dylib) 4085ee53db2SLisandro Dalcin for dep in dependencies: 4095ee53db2SLisandro Dalcin if os.path.dirname(dep) in (libdir,): 4105ee53db2SLisandro Dalcin newid = '@rpath/' + os.path.basename(dep) 4115ee53db2SLisandro Dalcin shell('install_name_tool', '-change', dep, newid, dylib) 4125ee53db2SLisandro Dalcin # fix shared library file and symlink 4135ee53db2SLisandro Dalcin basename = os.path.basename(dylib) 4145ee53db2SLisandro Dalcin libname, ext = os.path.splitext(basename) 4155ee53db2SLisandro Dalcin libname = libname.partition('.')[0] 4165ee53db2SLisandro Dalcin liblink = libname + ext 4175ee53db2SLisandro Dalcin dyname = os.path.basename(install_name) 4185ee53db2SLisandro Dalcin for symlink in lsdir(self.destLibDir, libname + '*' + ext): 4195ee53db2SLisandro Dalcin if os.path.islink(symlink): 4205ee53db2SLisandro Dalcin os.unlink(symlink) 4215ee53db2SLisandro Dalcin curdir = os.getcwd() 4225ee53db2SLisandro Dalcin try: 4235ee53db2SLisandro Dalcin os.chdir(os.path.dirname(dylib)) 4245ee53db2SLisandro Dalcin if dyname != basename: 4255ee53db2SLisandro Dalcin os.rename(basename, dyname) 4265ee53db2SLisandro Dalcin if dyname != liblink: 4275ee53db2SLisandro Dalcin os.symlink(dyname, liblink) 4285ee53db2SLisandro Dalcin finally: 4295ee53db2SLisandro Dalcin os.chdir(curdir) 4305ee53db2SLisandro Dalcin # 4315ee53db2SLisandro Dalcin return 4325ee53db2SLisandro Dalcin 4330ee81e68SLisandro Dalcin def createUninstaller(self): 4340ee81e68SLisandro Dalcin uninstallscript = os.path.join(self.destConfDir, 'uninstall.py') 4350ee81e68SLisandro Dalcin f = open(uninstallscript, 'w') 4360ee81e68SLisandro Dalcin # Could use the Python AST to do this 4370ee81e68SLisandro Dalcin f.write('#!'+sys.executable+'\n') 4380ee81e68SLisandro Dalcin f.write('import os\n') 439d97f9ea1SSatish Balay f.write('prefixdir = "'+self.installDir+'"\n') 440d97f9ea1SSatish Balay files = [dst.replace(self.destDir,self.installDir) for src, dst in self.copies] 441d97f9ea1SSatish Balay files.append(uninstallscript.replace(self.destDir,self.installDir)) 442d97f9ea1SSatish Balay f.write('files = '+repr(files)) 4430ee81e68SLisandro Dalcin f.write(''' 444d97f9ea1SSatish Balayfor file in files: 445d97f9ea1SSatish Balay if os.path.exists(file) or os.path.islink(file): 446d97f9ea1SSatish Balay os.remove(file) 447d97f9ea1SSatish Balay dir = os.path.dirname(file) 4482b39596bSSatish Balay while dir not in [os.path.dirname(prefixdir),'/']: 4492b39596bSSatish Balay try: os.rmdir(dir) 4502b39596bSSatish Balay except: break 451d97f9ea1SSatish Balay dir = os.path.dirname(dir) 4520ee81e68SLisandro Dalcin''') 4530ee81e68SLisandro Dalcin f.close() 4545b6bfdb9SJed Brown os.chmod(uninstallscript,0o744) 4550ee81e68SLisandro Dalcin return 4560ee81e68SLisandro Dalcin 4570ee81e68SLisandro Dalcin def installIncludes(self): 45832cabb2fSBarry Smith exclude = ['makefile'] 45932cabb2fSBarry Smith if not hasattr(self.compilers.setCompilers, 'FC'): 46032cabb2fSBarry Smith exclude.append('finclude') 46132cabb2fSBarry Smith if not self.mpi.usingMPIUni: 46232cabb2fSBarry Smith exclude.append('mpiuni') 46332cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude)) 4640ee81e68SLisandro Dalcin self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir)) 4650ee81e68SLisandro Dalcin return 4660ee81e68SLisandro Dalcin 4670ee81e68SLisandro Dalcin def installConf(self): 46832cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log'])) 469a035e9faSPierre 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'])) 4700ee81e68SLisandro Dalcin return 4710ee81e68SLisandro Dalcin 4720ee81e68SLisandro Dalcin def installBin(self): 47332cabb2fSBarry Smith exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml'] 47432cabb2fSBarry Smith self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude )) 47532cabb2fSBarry Smith exclude = ['maint'] 47632cabb2fSBarry Smith if not self.mpi.usingMPIUni: 47732cabb2fSBarry Smith exclude.append('petsc-mpiexec.uni') 47832cabb2fSBarry Smith self.setCompilers.pushLanguage('C') 479011f288aSSatish Balay if self.setCompilers.getCompiler().find('win32fe') < 0: 48032cabb2fSBarry Smith exclude.append('win32fe') 48132cabb2fSBarry Smith self.setCompilers.popLanguage() 48232cabb2fSBarry Smith self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude )) 4830ee81e68SLisandro Dalcin return 4840ee81e68SLisandro Dalcin 4850ee81e68SLisandro Dalcin def installShare(self): 4860ee81e68SLisandro Dalcin self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir)) 487c173c275SScott Kruger examplesdir=os.path.join(self.destShareDir,'petsc','examples') 488c173c275SScott Kruger if os.path.exists(examplesdir): 489c173c275SScott Kruger shutil.rmtree(examplesdir) 490c173c275SScott Kruger os.mkdir(examplesdir) 49179eaf171SScott Kruger os.mkdir(os.path.join(examplesdir,'src')) 492c173c275SScott Kruger self.copyConfig(self.rootDir,examplesdir) 493fad83eadSPatrick Sanan if not self.argDB['no-examples']: 494fad83eadSPatrick Sanan self.copyExamples(self.rootSrcDir,os.path.join(examplesdir,'src')) 495c173c275SScott Kruger self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test')) 4960ee81e68SLisandro Dalcin return 4970ee81e68SLisandro Dalcin 4980ee81e68SLisandro Dalcin def copyLib(self, src, dst): 4990ee81e68SLisandro Dalcin '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac''' 5000ee81e68SLisandro Dalcin # Symlinks (assumed local) are recreated at dst 5010ee81e68SLisandro Dalcin if os.path.islink(src): 5020ee81e68SLisandro Dalcin linkto = os.readlink(src) 5030ee81e68SLisandro Dalcin try: 5040ee81e68SLisandro Dalcin os.remove(dst) # In case it already exists 5050ee81e68SLisandro Dalcin except OSError: 5060ee81e68SLisandro Dalcin pass 5070ee81e68SLisandro Dalcin os.symlink(linkto, dst) 5080ee81e68SLisandro Dalcin return 5090ee81e68SLisandro Dalcin shutil.copy2(src, dst) 510011f288aSSatish Balay if self.setCompilers.getCompiler().find('win32fe') < 0 and os.path.splitext(dst)[1] == '.'+self.arLibSuffix: 511*abf72cf0SSatish Balay import shlex 512*abf72cf0SSatish Balay self.executeShellCommand(shlex.split(self.ranlib) + [dst]) 513c9e802c5SMin RK if os.path.splitext(dst)[1] == '.dylib' and shutil.which('otool') and shutil.which('install_name_tool'): 514793d7be8SSatish Balay [output,err,flg] = self.executeShellCommand(['otool', '-D', src]) 515af2c601bSBarry Smith oldname = output[output.find("\n")+1:] 516d4c3e6c5SSatish Balay installName = oldname.replace(os.path.realpath(self.archDir), self.installDir) 517793d7be8SSatish Balay self.executeShellCommand(['install_name_tool', '-id', installName, dst]) 5180ee81e68SLisandro Dalcin # preserve the original timestamps - so that the .a vs .so time order is preserved 5190ee81e68SLisandro Dalcin shutil.copystat(src,dst) 5200ee81e68SLisandro Dalcin return 5210ee81e68SLisandro Dalcin 5220ee81e68SLisandro Dalcin def installLib(self): 52332cabb2fSBarry Smith self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 52432cabb2fSBarry 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)) 5250ee81e68SLisandro Dalcin return 5260ee81e68SLisandro Dalcin 5270ee81e68SLisandro Dalcin 5280ee81e68SLisandro Dalcin def outputInstallDone(self): 5295b4fc442SVaclav Hapla from config.packages.make import getMakeUserPath 5305b6bfdb9SJed Brown print('''\ 5310ee81e68SLisandro Dalcin==================================== 5320ee81e68SLisandro DalcinInstall complete. 5330ee81e68SLisandro DalcinNow to check if the libraries are working do (in current directory): 5345b4fc442SVaclav Hapla%s PETSC_DIR=%s PETSC_ARCH="" check 5350ee81e68SLisandro Dalcin====================================\ 5365b4fc442SVaclav Hapla''' % (getMakeUserPath(self.arch), self.installDir)) 5370ee81e68SLisandro Dalcin return 5380ee81e68SLisandro Dalcin 5390ee81e68SLisandro Dalcin def outputDestDirDone(self): 5405b6bfdb9SJed Brown print('''\ 5410ee81e68SLisandro Dalcin==================================== 5420ee81e68SLisandro DalcinCopy to DESTDIR %s is now complete. 5430ee81e68SLisandro DalcinBefore use - please copy/install over to specified prefix: %s 5440ee81e68SLisandro Dalcin====================================\ 5455b6bfdb9SJed Brown''' % (self.destDir,self.installDir)) 5460ee81e68SLisandro Dalcin return 5470ee81e68SLisandro Dalcin 5480ee81e68SLisandro Dalcin def runsetup(self): 5490ee81e68SLisandro Dalcin self.setup() 5500ee81e68SLisandro Dalcin self.setupDirectories() 5510ee81e68SLisandro Dalcin self.checkPrefix() 5520ee81e68SLisandro Dalcin self.checkDestdir() 5530ee81e68SLisandro Dalcin return 5540ee81e68SLisandro Dalcin 5550ee81e68SLisandro Dalcin def runcopy(self): 5560ee81e68SLisandro Dalcin if self.destDir == self.installDir: 5575b6bfdb9SJed Brown print('*** Installing PETSc at prefix location:',self.destDir, ' ***') 5580ee81e68SLisandro Dalcin else: 5595b6bfdb9SJed Brown print('*** Copying PETSc to DESTDIR location:',self.destDir, ' ***') 5600ee81e68SLisandro Dalcin if not os.path.exists(self.destDir): 5610ee81e68SLisandro Dalcin try: 5620ee81e68SLisandro Dalcin os.makedirs(self.destDir) 5630ee81e68SLisandro Dalcin except: 5645b6bfdb9SJed Brown print('********************************************************************') 5655b6bfdb9SJed Brown print('Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"') 5665b6bfdb9SJed Brown print('********************************************************************') 5670ee81e68SLisandro Dalcin sys.exit(1) 5680ee81e68SLisandro Dalcin self.installIncludes() 5690ee81e68SLisandro Dalcin self.installConf() 5700ee81e68SLisandro Dalcin self.installBin() 5710ee81e68SLisandro Dalcin self.installLib() 5720ee81e68SLisandro Dalcin self.installShare() 5735ee53db2SLisandro Dalcin self.createUninstaller() 5740ee81e68SLisandro Dalcin return 5750ee81e68SLisandro Dalcin 5760ee81e68SLisandro Dalcin def runfix(self): 5770ee81e68SLisandro Dalcin self.fixConf() 5781eeab4b4SLisandro Dalcin using_build_backend = any( 5791eeab4b4SLisandro Dalcin os.environ.get(prefix + '_BUILD_BACKEND') 5801eeab4b4SLisandro Dalcin for prefix in ('_PYPROJECT_HOOKS', 'PEP517') 5811eeab4b4SLisandro Dalcin ) 5821eeab4b4SLisandro Dalcin if using_build_backend: 5835ee53db2SLisandro Dalcin self.fixPythonWheel() 5840ee81e68SLisandro Dalcin return 5850ee81e68SLisandro Dalcin 5860ee81e68SLisandro Dalcin def rundone(self): 5870ee81e68SLisandro Dalcin if self.destDir == self.installDir: 5880ee81e68SLisandro Dalcin self.outputInstallDone() 5890ee81e68SLisandro Dalcin else: 5900ee81e68SLisandro Dalcin self.outputDestDirDone() 5910ee81e68SLisandro Dalcin return 5920ee81e68SLisandro Dalcin 5930ee81e68SLisandro Dalcin def run(self): 5940ee81e68SLisandro Dalcin self.runsetup() 5950ee81e68SLisandro Dalcin self.runcopy() 5960ee81e68SLisandro Dalcin self.runfix() 5970ee81e68SLisandro Dalcin self.rundone() 5980ee81e68SLisandro Dalcin return 5990ee81e68SLisandro Dalcin 6000ee81e68SLisandro Dalcinif __name__ == '__main__': 6010ee81e68SLisandro Dalcin Installer(sys.argv[1:]).run() 6020ee81e68SLisandro Dalcin # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 60303e6d329SSatish Balay delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp'] 6040ee81e68SLisandro Dalcin for delfile in delfiles: 6050ee81e68SLisandro Dalcin if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 6060ee81e68SLisandro Dalcin os.remove(delfile) 607