xref: /petsc/config/install.py (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1#!/usr/bin/env python3
2from __future__ import print_function
3import os, re, shutil, sys
4
5if 'PETSC_DIR' in os.environ:
6  PETSC_DIR = os.environ['PETSC_DIR']
7else:
8  fd = open(os.path.join('lib','petsc','conf','petscvariables'))
9  a = fd.readline()
10  a = fd.readline()
11  PETSC_DIR = a.split('=')[1][0:-1]
12  fd.close()
13
14if 'PETSC_ARCH' in os.environ:
15  PETSC_ARCH = os.environ['PETSC_ARCH']
16else:
17  fd = open(os.path.join('lib','petsc','conf','petscvariables'))
18  a = fd.readline()
19  PETSC_ARCH = a.split('=')[1][0:-1]
20  fd.close()
21
22print('*** Using PETSC_DIR='+PETSC_DIR+' PETSC_ARCH='+PETSC_ARCH+' ***')
23sys.path.insert(0, os.path.join(PETSC_DIR, 'config'))
24sys.path.insert(0, os.path.join(PETSC_DIR, 'config', 'BuildSystem'))
25
26import script
27
28try:
29  WindowsError
30except NameError:
31  WindowsError = None
32
33class Installer(script.Script):
34  def __init__(self, clArgs = None):
35    import RDict
36    argDB = RDict.RDict(None, None, 0, 0, readonly = True)
37    argDB.saveFilename = os.path.join(PETSC_DIR, PETSC_ARCH, 'lib','petsc','conf', 'RDict.db')
38    argDB.load()
39    script.Script.__init__(self, argDB = argDB)
40    if not clArgs is None: self.clArgs = clArgs
41    self.copies = []
42    return
43
44  def setupHelp(self, help):
45    import nargs
46    script.Script.setupHelp(self, help)
47    help.addArgument('Installer', '-destDir=<path>', nargs.Arg(None, '', 'Destination Directory for install'))
48    help.addArgument('Installer', '-no-examples', nargs.Arg(None, '', 'Skip installing examples'))
49    return
50
51
52  def setupModules(self):
53    self.setCompilers  = self.framework.require('config.setCompilers',         None)
54    self.arch          = self.framework.require('PETSc.options.arch',          None)
55    self.petscdir      = self.framework.require('PETSc.options.petscdir',      None)
56    self.compilers     = self.framework.require('config.compilers',            None)
57    self.mpi           = self.framework.require('config.packages.MPI',         None)
58    return
59
60  def setup(self):
61    script.Script.setup(self)
62    self.framework = self.loadConfigure()
63    self.setupModules()
64    return
65
66  def setupDirectories(self):
67    self.rootDir    = self.petscdir.dir
68    self.installDir = os.path.abspath(os.path.expanduser(self.framework.argDB['prefix']))
69    self.destDir    = os.path.abspath(self.argDB['destDir']+self.installDir)
70    self.arch       = self.arch.arch
71    self.archDir           = os.path.join(self.rootDir, self.arch)
72    self.rootIncludeDir    = os.path.join(self.rootDir, 'include')
73    self.archIncludeDir    = os.path.join(self.rootDir, self.arch, 'include')
74    self.rootConfDir       = os.path.join(self.rootDir, 'lib','petsc','conf')
75    self.archConfDir       = os.path.join(self.rootDir, self.arch, 'lib','petsc','conf')
76    self.rootBinDir        = os.path.join(self.rootDir, 'lib','petsc','bin')
77    self.archBinDir        = os.path.join(self.rootDir, self.arch, 'bin')
78    self.archLibDir        = os.path.join(self.rootDir, self.arch, 'lib')
79    self.destIncludeDir    = os.path.join(self.destDir, 'include')
80    self.destConfDir       = os.path.join(self.destDir, 'lib','petsc','conf')
81    self.destLibDir        = os.path.join(self.destDir, 'lib')
82    self.destBinDir        = os.path.join(self.destDir, 'lib','petsc','bin')
83    self.installIncludeDir = os.path.join(self.installDir, 'include')
84    self.installBinDir     = os.path.join(self.installDir, 'lib','petsc','bin')
85    self.rootShareDir      = os.path.join(self.rootDir, 'share')
86    self.destShareDir      = os.path.join(self.destDir, 'share')
87    self.rootSrcDir        = os.path.join(self.rootDir, 'src')
88
89    self.ranlib      = self.compilers.RANLIB
90    self.arLibSuffix = self.compilers.AR_LIB_SUFFIX
91    return
92
93  def checkPrefix(self):
94    if not self.installDir:
95      print('********************************************************************')
96      print('PETSc is built without prefix option. So "make install" is not appropriate.')
97      print('If you need a prefix install of PETSc - rerun configure with --prefix option.')
98      print('********************************************************************')
99      sys.exit(1)
100    return
101
102  def checkDestdir(self):
103    if os.path.exists(self.destDir):
104      if os.path.samefile(self.destDir, self.rootDir):
105        print('********************************************************************')
106        print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR')
107        print('********************************************************************')
108        sys.exit(1)
109      if os.path.samefile(self.destDir, os.path.join(self.rootDir,self.arch)):
110        print('********************************************************************')
111        print('Incorrect prefix usage. Specified destDir same as current PETSC_DIR/PETSC_ARCH')
112        print('********************************************************************')
113        sys.exit(1)
114      if not os.path.isdir(os.path.realpath(self.destDir)):
115        print('********************************************************************')
116        print('Specified destDir', self.destDir, 'is not a directory. Cannot proceed!')
117        print('********************************************************************')
118        sys.exit(1)
119      if not os.access(self.destDir, os.W_OK):
120        print('********************************************************************')
121        print('Unable to write to ', self.destDir, 'Perhaps you need to do "sudo make install"')
122        print('********************************************************************')
123        sys.exit(1)
124    return
125
126  def copyfile(self, src, dst, symlinks = False, copyFunc = shutil.copy2):
127    """Copies a single file    """
128    copies = []
129    errors = []
130    if not os.path.exists(dst):
131      os.makedirs(dst)
132    elif not os.path.isdir(dst):
133      raise shutil.Error('Destination is not a directory')
134    srcname = src
135    dstname = os.path.join(dst, os.path.basename(src))
136    try:
137      if symlinks and os.path.islink(srcname):
138        linkto = os.readlink(srcname)
139        os.symlink(linkto, dstname)
140      else:
141        copyFunc(srcname, dstname)
142        copies.append((srcname, dstname))
143    except (IOError, os.error) as why:
144      errors.append((srcname, dstname, str(why)))
145    except shutil.Error as err:
146      errors.append((srcname,dstname,str(err.args[0])))
147    if errors:
148      raise shutil.Error(errors)
149    return copies
150
151  def fixExamplesMakefile(self, src):
152    '''Change ././${PETSC_ARCH} in makefile in root petsc directory with ${PETSC_DIR}'''
153    lines   = []
154    oldFile = open(src, 'r')
155    alllines=oldFile.read()
156    oldFile.close()
157    newlines=alllines.split('\n')[0]+'\n'  # Firstline
158    # Hardcode PETSC_DIR and PETSC_ARCH to avoid users doing the wrong thing
159    newlines+='PETSC_DIR='+self.installDir+'\n'
160    newlines+='PETSC_ARCH=\n'
161    for line in alllines.split('\n')[1:]:
162      if line.startswith('TESTLOGFILE'):
163        newlines+='TESTLOGFILE = $(TESTDIR)/examples-install.log\n'
164      elif line.startswith('CONFIGDIR'):
165        newlines+='CONFIGDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples/config\n'
166      elif line.startswith('$(generatedtest)') and 'petscvariables' in line:
167        newlines+='all: test\n\n'+line+'\n'
168      else:
169        newlines+=line+'\n'
170    newFile = open(src, 'w')
171    newFile.write(newlines)
172    newFile.close()
173    return
174
175  def copyConfig(self, src, dst):
176    """Copy configuration/testing files
177    """
178    if not os.path.isdir(dst):
179      raise shutil.Error('Destination is not a directory')
180
181    self.copies.extend(self.copyfile('gmakefile.test',dst))
182    newConfigDir=os.path.join(dst,'config')  # Am not renaming at present
183    if not os.path.isdir(newConfigDir): os.mkdir(newConfigDir)
184    testConfFiles="gmakegentest.py gmakegen.py testparse.py example_template.py".split()
185    testConfFiles+="petsc_harness.sh report_tests.py query_tests.py".split()
186    for tf in testConfFiles:
187      self.copies.extend(self.copyfile(os.path.join('config',tf),newConfigDir))
188    return
189
190  def copyExamples(self, src, dst):
191    """copy the examples directories
192    """
193    for root, dirs, files in os.walk(src, topdown=False):
194      if os.path.basename(root) not in ("tests", "tutorials"): continue
195      self.copies.extend(self.copytree(root, root.replace(src,dst)))
196    return
197
198  def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2, exclude = [], exclude_ext= ['.DSYM','.o','.pyc'], recurse = 1):
199    """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2().
200
201       The copyFunc() you provide is only used on the top level, lower levels always use shutil.copy2
202
203    The destination directory must not already exist.
204    If exception(s) occur, an shutil.Error is raised with a list of reasons.
205
206    If the optional symlinks flag is true, symbolic links in the
207    source tree result in symbolic links in the destination tree; if
208    it is false, the contents of the files pointed to by symbolic
209    links are copied.
210    """
211    copies = []
212    names  = os.listdir(src)
213    if not os.path.exists(dst):
214      os.makedirs(dst)
215    elif not os.path.isdir(dst):
216      raise shutil.Error('Destination is not a directory')
217    errors = []
218    srclinks = []
219    dstlinks = []
220    for name in names:
221      srcname = os.path.join(src, name)
222      dstname = os.path.join(dst, name)
223      try:
224        if symlinks and os.path.islink(srcname):
225          linkto = os.readlink(srcname)
226          os.symlink(linkto, dstname)
227        elif os.path.isdir(srcname) and recurse and not os.path.basename(srcname) in exclude:
228          copies.extend(self.copytree(srcname, dstname, symlinks,exclude = exclude, exclude_ext = exclude_ext))
229        elif os.path.isfile(srcname) and not os.path.basename(srcname) in exclude and os.path.splitext(name)[1] not in exclude_ext :
230          if os.path.islink(srcname):
231            srclinks.append(srcname)
232            dstlinks.append(dstname)
233          else:
234            copyFunc(srcname, dstname)
235            copies.append((srcname, dstname))
236        # XXX What about devices, sockets etc.?
237      except (IOError, os.error) as why:
238        errors.append((srcname, dstname, str(why)))
239      # catch the Error from the recursive copytree so that we can
240      # continue with other files
241      except shutil.Error as err:
242        errors.append((srcname,dstname,str(err.args[0])))
243    for srcname, dstname in zip(srclinks, dstlinks):
244      try:
245        copyFunc(srcname, dstname)
246        copies.append((srcname, dstname))
247      except (IOError, os.error) as why:
248        errors.append((srcname, dstname, str(why)))
249      # catch the Error from the recursive copytree so that we can
250      # continue with other files
251      except shutil.Error as err:
252        errors.append((srcname,dstname,str(err.args[0])))
253    try:
254      shutil.copystat(src, dst)
255    except OSError as e:
256      if WindowsError is not None and isinstance(e, WindowsError):
257        # Copying file access times may fail on Windows
258        pass
259      else:
260        errors.append((src, dst, str(e)))
261    if errors:
262      raise shutil.Error(errors)
263    return copies
264
265
266  def fixConfFile(self, src):
267    lines   = []
268    oldFile = open(src, 'r')
269    for line in oldFile.readlines():
270      if line.startswith('PETSC_CC_INCLUDES =') or line.startswith('PETSC_FC_INCLUDES ='):
271        continue
272      line = line.replace('PETSC_CC_INCLUDES_INSTALL', 'PETSC_CC_INCLUDES')
273      line = line.replace('PETSC_FC_INCLUDES_INSTALL', 'PETSC_FC_INCLUDES')
274      # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary
275      line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir)
276      line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '')
277      line = line.replace('${PETSC_DIR}', self.installDir)
278      # replace PETSC_DIR/lib/petsc/bin with prefix/lib/petsc/bin
279      line = line.replace(self.rootBinDir,self.destBinDir)
280      lines.append(line)
281    oldFile.close()
282    newFile = open(src, 'w')
283    newFile.write(''.join(lines))
284    newFile.close()
285    return
286
287  def fixConf(self):
288    import shutil
289    for file in ['rules', 'rules_doc.mk', 'rules_util.mk', 'variables', 'petscrules', 'petscvariables']:
290      self.fixConfFile(os.path.join(self.destConfDir,file))
291    return
292
293  def fixPythonWheel(self):
294    import glob
295    import shutil
296    #
297    for pattern in (
298        self.destLibDir  + '/*.a',
299        self.destLibDir  + '/*.la',
300        self.destLibDir  + '/pkgconfig',  # TODO: keep?
301        self.destConfDir + '/configure-hash',
302        self.destConfDir + '/uninstall.py',
303        self.destConfDir + '/reconfigure-*.py',
304        self.destConfDir + '/pkg.conf.*',
305        self.destConfDir + '/pkg.git*.*',
306        self.destConfDir + '/modules',  # TODO: keep?
307        self.destShareDir + '/*/examples/src/*',
308        self.destShareDir + '/*/datafiles',
309    ):
310      for pathname in glob.glob(pattern):
311        if os.path.isdir(pathname):
312          shutil.rmtree(pathname)
313        elif os.path.exists(pathname):
314          os.remove(pathname)
315    #
316    for filename in (
317      self.destIncludeDir + '/petscconf.h',
318      self.destIncludeDir + '/petscconfiginfo.h',
319      self.destIncludeDir + '/petscmachineinfo.h',
320      self.destShareDir + '/petsc/examples/gmakefile.test',
321      self.destConfDir + '/rules',
322      self.destConfDir + '/rules_doc.mk',
323      self.destConfDir + '/rules_util.mk',
324      self.destConfDir + '/petscrules',
325      self.destConfDir + '/variables',
326      self.destConfDir + '/petscvariables',
327    ):
328      with open(filename, 'r') as oldFile:
329        contents = oldFile.read()
330      contents = contents.replace(self.installDir, '${PETSC_DIR}')
331      contents = contents.replace(self.rootDir, '${PETSC_DIR}')
332      contents = re.sub(
333        r'^(PYTHON(_EXE)?) = (.*)$',
334        r'\1 = python%d' % sys.version_info[0],
335        contents, flags=re.MULTILINE,
336      )
337      with open(filename, 'w') as newFile:
338        newFile.write(contents)
339    #
340    def lsdir(dirname, *patterns):
341      return glob.glob(os.path.join(dirname, *patterns))
342    def shell(*args):
343      return self.executeShellCommand(' '.join(args))[0]
344    libdir = os.path.join(self.installDir, 'lib')
345    if sys.platform == 'linux':
346      libraries = [
347        lib for lib in lsdir(self.destLibDir, 'lib*.so*')
348        if not os.path.islink(lib)
349      ]
350      for shlib in libraries:
351        # fix shared library rpath
352        rpath = shell('patchelf', '--print-rpath', shlib)
353        rpath = rpath.split(os.path.pathsep)
354        if libdir in rpath:
355          rpath.insert(0, '$ORIGIN')
356          while libdir in rpath:
357            rpath.remove(libdir)
358        if rpath:
359          rpath = os.path.pathsep.join(rpath)
360          shell('patchelf', '--set-rpath', "'%s'" % rpath, shlib)
361        # fix shared library file and symlink
362        basename = os.path.basename(shlib)
363        libname, ext, _ = basename.partition('.so')
364        liblink = libname + ext
365        soname = shell('patchelf', '--print-soname', shlib)
366        for symlink in lsdir(self.destLibDir, liblink + '*'):
367          if os.path.islink(symlink):
368            os.unlink(symlink)
369        curdir = os.getcwd()
370        try:
371          os.chdir(os.path.dirname(shlib))
372          if soname != basename:
373            os.rename(basename, soname)
374          if soname != liblink:
375            os.symlink(soname, liblink)
376        finally:
377          os.chdir(curdir)
378    if sys.platform == 'darwin':
379      def otool(cmd, dylib):
380        pattern = r'''
381          ^\s+ cmd \s %s$\n
382          ^\s+ cmdsize \s \d+$\n
383          ^\s+ (?:name|path) \s (.*) \s \(offset \s \d+\)$
384        ''' % cmd
385        return re.findall(
386          pattern, shell('otool', '-l', dylib),
387          flags=re.VERBOSE | re.MULTILINE,
388        )
389      libraries = [
390        lib for lib in lsdir(self.destLibDir, 'lib*.dylib')
391        if not os.path.islink(lib)
392      ]
393      for dylib in libraries:
394        install_name = otool('LC_ID_DYLIB', dylib)[0]
395        dependencies = otool('LC_LOAD_DYLIB', dylib)
396        runtime_path = otool('LC_RPATH', dylib)
397        # fix shared library install name and rpath
398        install_name = '@rpath/' + os.path.basename(install_name)
399        shell('install_name_tool', '-id', install_name, dylib)
400        if libdir in runtime_path:
401          shell('install_name_tool', '-delete_rpath', libdir, dylib)
402        for rpath in ('@loader_path',):
403          if rpath not in runtime_path:
404            shell('install_name_tool', '-add_rpath', rpath, dylib)
405        for dep in dependencies:
406          if os.path.dirname(dep) in (libdir,):
407            newid = '@rpath/' + os.path.basename(dep)
408            shell('install_name_tool', '-change', dep, newid, dylib)
409        # fix shared library file and symlink
410        basename = os.path.basename(dylib)
411        libname, ext = os.path.splitext(basename)
412        libname = libname.partition('.')[0]
413        liblink = libname + ext
414        dyname = os.path.basename(install_name)
415        for symlink in lsdir(self.destLibDir, libname + '*' + ext):
416          if os.path.islink(symlink):
417            os.unlink(symlink)
418        curdir = os.getcwd()
419        try:
420          os.chdir(os.path.dirname(dylib))
421          if dyname != basename:
422            os.rename(basename, dyname)
423          if dyname != liblink:
424            os.symlink(dyname, liblink)
425        finally:
426          os.chdir(curdir)
427    #
428    return
429
430  def createUninstaller(self):
431    uninstallscript = os.path.join(self.destConfDir, 'uninstall.py')
432    f = open(uninstallscript, 'w')
433    # Could use the Python AST to do this
434    f.write('#!'+sys.executable+'\n')
435    f.write('import os\n')
436    f.write('prefixdir = "'+self.installDir+'"\n')
437    files = [dst.replace(self.destDir,self.installDir) for src, dst in self.copies]
438    files.append(uninstallscript.replace(self.destDir,self.installDir))
439    f.write('files = '+repr(files))
440    f.write('''
441for file in files:
442  if os.path.exists(file) or os.path.islink(file):
443    os.remove(file)
444    dir = os.path.dirname(file)
445    while dir not in [os.path.dirname(prefixdir),'/']:
446      try: os.rmdir(dir)
447      except: break
448      dir = os.path.dirname(dir)
449''')
450    f.close()
451    os.chmod(uninstallscript,0o744)
452    return
453
454  def installIncludes(self):
455    exclude = ['makefile']
456    if not hasattr(self.compilers.setCompilers, 'FC'):
457      exclude.append('finclude')
458    if not self.mpi.usingMPIUni:
459      exclude.append('mpiuni')
460    self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude))
461    self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir))
462    return
463
464  def installConf(self):
465    self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log']))
466    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']))
467    return
468
469  def installBin(self):
470    exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml']
471    self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude ))
472    exclude = ['maint']
473    if not self.mpi.usingMPIUni:
474      exclude.append('petsc-mpiexec.uni')
475    self.setCompilers.pushLanguage('C')
476    if self.setCompilers.getCompiler().find('win32fe') < 0:
477      exclude.append('win32fe')
478    self.setCompilers.popLanguage()
479    self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude ))
480    return
481
482  def installShare(self):
483    self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir))
484    examplesdir=os.path.join(self.destShareDir,'petsc','examples')
485    if os.path.exists(examplesdir):
486      shutil.rmtree(examplesdir)
487    os.mkdir(examplesdir)
488    os.mkdir(os.path.join(examplesdir,'src'))
489    self.copyConfig(self.rootDir,examplesdir)
490    if not self.argDB['no-examples']:
491        self.copyExamples(self.rootSrcDir,os.path.join(examplesdir,'src'))
492        self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test'))
493    return
494
495  def copyLib(self, src, dst):
496    '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac'''
497    # Symlinks (assumed local) are recreated at dst
498    if os.path.islink(src):
499      linkto = os.readlink(src)
500      try:
501        os.remove(dst)            # In case it already exists
502      except OSError:
503        pass
504      os.symlink(linkto, dst)
505      return
506    shutil.copy2(src, dst)
507    if self.setCompilers.getCompiler().find('win32fe') < 0 and os.path.splitext(dst)[1] == '.'+self.arLibSuffix:
508      self.executeShellCommand(self.ranlib+' '+dst)
509    if os.path.splitext(dst)[1] == '.dylib' and os.path.isfile('/usr/bin/install_name_tool'):
510      [output,err,flg] = self.executeShellCommand("otool -D "+src)
511      oldname = output[output.find("\n")+1:]
512      installName = oldname.replace(os.path.realpath(self.archDir), self.installDir)
513      self.executeShellCommand('/usr/bin/install_name_tool -id ' + installName + ' ' + dst)
514    # preserve the original timestamps - so that the .a vs .so time order is preserved
515    shutil.copystat(src,dst)
516    return
517
518  def installLib(self):
519    self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0))
520    self.copies.extend(self.copytree(os.path.join(self.archLibDir,'pkgconfig'), os.path.join(self.destLibDir,'pkgconfig'), copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0))
521    return
522
523
524  def outputInstallDone(self):
525    from config.packages.make import getMakeUserPath
526    print('''\
527====================================
528Install complete.
529Now to check if the libraries are working do (in current directory):
530%s PETSC_DIR=%s PETSC_ARCH="" check
531====================================\
532''' % (getMakeUserPath(self.arch), self.installDir))
533    return
534
535  def outputDestDirDone(self):
536    print('''\
537====================================
538Copy to DESTDIR %s is now complete.
539Before use - please copy/install over to specified prefix: %s
540====================================\
541''' % (self.destDir,self.installDir))
542    return
543
544  def runsetup(self):
545    self.setup()
546    self.setupDirectories()
547    self.checkPrefix()
548    self.checkDestdir()
549    return
550
551  def runcopy(self):
552    if self.destDir == self.installDir:
553      print('*** Installing PETSc at prefix location:',self.destDir, ' ***')
554    else:
555      print('*** Copying PETSc to DESTDIR location:',self.destDir, ' ***')
556    if not os.path.exists(self.destDir):
557      try:
558        os.makedirs(self.destDir)
559      except:
560        print('********************************************************************')
561        print('Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"')
562        print('********************************************************************')
563        sys.exit(1)
564    self.installIncludes()
565    self.installConf()
566    self.installBin()
567    self.installLib()
568    self.installShare()
569    self.createUninstaller()
570    return
571
572  def runfix(self):
573    self.fixConf()
574    if os.environ.get('PEP517_BUILD_BACKEND'):
575      self.fixPythonWheel()
576    return
577
578  def rundone(self):
579    if self.destDir == self.installDir:
580      self.outputInstallDone()
581    else:
582      self.outputDestDirDone()
583    return
584
585  def run(self):
586    self.runsetup()
587    self.runcopy()
588    self.runfix()
589    self.rundone()
590    return
591
592if __name__ == '__main__':
593  Installer(sys.argv[1:]).run()
594  # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked
595  delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp']
596  for delfile in delfiles:
597    if os.path.exists(delfile) and (os.stat(delfile).st_uid==0):
598      os.remove(delfile)
599