Subversion Repositories slepc-dev

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!/usr/bin/env python
#!/bin/env python
#
#  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#  SLEPc - Scalable Library for Eigenvalue Problem Computations
#  Copyright (c) 2002-2009, Universidad Politecnica de Valencia, Spain
#
#  This file is part of SLEPc.
#    
#  SLEPc is free software: you can redistribute it and/or modify it under  the
#  terms of version 3 of the GNU Lesser General Public License as published by
#  the Free Software Foundation.
#
#  SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
#  WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
#  FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
#  more details.
#
#  You  should have received a copy of the GNU Lesser General  Public  License
#  along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
#  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
#    Generates fortran stubs for PETSc using Sowings bfort program
#
import os
#
#  Opens all generated files and fixes them; also generates list in makefile.src
#
def FixFile(filename):
  import re
  ff = open(filename)
  data = ff.read()
  ff.close()

  # gotta be a better way to do this
  data = re.subn('\nvoid ','\nvoid PETSC_STDCALL ',data)[0]
  data = re.subn('\nPetscErrorCode ','\nvoid PETSC_STDCALL ',data)[0]
  data = re.subn('Petsc([ToRm]*)Pointer\(int\)','Petsc\\1Pointer(void*)',data)[0]        
  data = re.subn('PetscToPointer\(a\) \(a\)','PetscToPointer(a) (*(long *)(a))',data)[0]
  data = re.subn('PetscFromPointer\(a\) \(int\)\(a\)','PetscFromPointer(a) (long)(a)',data)[0]
  data = re.subn('PetscToPointer\( \*\(int\*\)','PetscToPointer(',data)[0]
  data = re.subn('MPI_Comm comm','MPI_Comm *comm',data)[0]
  data = re.subn('\(MPI_Comm\)PetscToPointer\( \(comm\) \)','MPI_Comm_f2c(*(MPI_Fint*)(comm))',data)[0]
  data = re.subn('\(PetscInt\* \)PetscToPointer','',data)[0]
  match = re.compile(r"""\b(PETSC)(_DLL|VEC_DLL|MAT_DLL|DM_DLL|KSP_DLL|SNES_DLL|TS_DLL|FORTRAN_DLL)(EXPORT)""")
  data = match.sub(r'',data)

  ff = open(filename, 'w')
  ff.write('#include "petsc.h"\n#include "petscfix.h"\n'+data)
  ff.close()
  return

def FixDir(petscdir,dir):
  mansec = 'unknown'
  cnames = []
  hnames = []
  parentdir =os.path.abspath(os.path.join(dir,'..'))
  for f in os.listdir(dir):
    ext = os.path.splitext(f)[1]
    if ext == '.c':
      FixFile(os.path.join(dir, f))
      cnames.append(f)
    elif ext == '.h90':
      hnames.append(f)
  if (cnames != [] or hnames != []):
    mfile=os.path.abspath(os.path.join(parentdir,'makefile'))
    try:
      fd=open(mfile,'r')
    except:
      print 'Error! missing file:', mfile
      return
    inbuf = fd.read()
    fd.close()
    cppflags = ""
    libbase = ""
    locdir = ""
    for line in inbuf.splitlines():
      if line.find('CPPFLAGS') >=0:
        cppflags = line
      if line.find('LIBBASE') >=0:
        libbase = line
      elif line.find('LOCDIR') >=0:
        locdir = line.rstrip() + 'ftn-auto/'
      elif line.find('MANSEC') >=0:
        mansec = line.split('=')[1].lower().strip()

    # now assemble the makefile
    outbuf  =  '\n'
    outbuf +=  "#requirespackage   'PETSC_HAVE_FORTRAN'\n"
    outbuf +=  'ALL: lib\n'
    outbuf +=   cppflags + '\n'
    outbuf +=  'CFLAGS   =\n'
    outbuf +=  'FFLAGS   =\n'
    outbuf +=  'SOURCEC  = ' +' '.join(cnames)+ '\n'
    outbuf +=  'OBJSC    = ' +' '.join(cnames).replace('.c','.o')+ '\n'    
    outbuf +=  'SOURCEF  =\n'
    outbuf +=  'SOURCEH  = ' +' '.join(hnames)+ '\n'
    outbuf +=  'DIRS     =\n'
    outbuf +=  libbase + '\n'
    outbuf +=  locdir + '\n'
#    outbuf +=  'include ${PETSC_DIR}/conf/base\n'
#    outbuf +=  'include ${PETSC_DIR}/conf/test\n'
    outbuf +=  'include ${SLEPC_DIR}/conf/slepc_common  \n'
    ff = open(os.path.join(dir, 'makefile'), 'w')
    ff.write(outbuf)
    ff.close()

  # if dir is empty - remove it
  if os.path.exists(dir) and os.path.isdir(dir) and os.listdir(dir) == []:
    os.rmdir(dir)

  # Now process f90module.f90 file - and update include/finclude/ftn-auto
  modfile = os.path.join(parentdir,'f90module.f90')
  if os.path.exists(modfile):
    fd = open(modfile)
    txt = fd.read()
    fd.close()

    if txt and mansec == 'unknown':
      print 'makefile has missing MANSEC',parentdir
    elif txt:
      ftype = 'w'
      f90inc = os.path.join(petscdir,'include','finclude','ftn-auto','slepc'+mansec+'.h90')
      if os.path.exists(f90inc): ftype = 'a'
      fd = open(f90inc,ftype)
      fd.write(txt)
      fd.close()
    os.remove(modfile)
  return

def PrepFtnDir(dir):
  if os.path.exists(dir) and not os.path.isdir(dir):
    raise RuntimeError('Error - specified path is not a dir: ' + dir)
  elif not os.path.exists(dir):
    os.mkdir(dir)
  else:
    files = os.listdir(dir)
    for file in files:
      os.remove(os.path.join(dir,file))
  return

def processDir(arg,dirname,names):
  import commands
  petscdir = arg[0]
  bfort    = arg[1]
  newls = []
  outdir = os.path.join(dirname,'ftn-auto')

  # skip include/finclude/ftn-auto - as this is processed separately
  if os.path.realpath(os.path.join(petscdir,'include','finclude','ftn-auto')) == os.path.realpath(outdir): return

  for l in names:
    if os.path.splitext(l)[1] =='.c' or os.path.splitext(l)[1] == '.h':
      newls.append(l)
  if newls:
    PrepFtnDir(outdir)
    options = ['-dir '+outdir, '-mnative', '-ansi', '-nomsgs', '-noprofile', '-anyname', '-mapptr',
               '-mpi', '-mpi2', '-ferr', '-ptrprefix Petsc', '-ptr64 PETSC_USE_POINTER_CONVERSION',
               '-fcaps PETSC_HAVE_FORTRAN_CAPS', '-fuscore PETSC_HAVE_FORTRAN_UNDERSCORE','-f90mod_skip_header']
    (status,output) = commands.getstatusoutput('cd '+dirname+';'+bfort+' '+' '.join(options+newls))
    if status:
      raise RuntimeError('Error running bfort '+output)
    FixDir(petscdir,outdir)
  for name in ['.hg','SCCS', 'output', 'BitKeeper', 'examples', 'externalpackages', 'bilinear', 'ftn-auto','fortran','bin','maint','ftn-custom','config','f90-custom']:
    if name in names:
      names.remove(name)
  # check for configure generated PETSC_ARCHes
  rmnames=[]
  for name in names:
    if os.path.isdir(os.path.join(name,'conf')):
      rmnames.append(name)
  for rmname in rmnames:
    names.remove(rmname)
  return

def main(bfort):
  petscdir = os.getcwd()
  tmpdir = os.path
  ftnautoinc = os.path.join(petscdir,'include','finclude','ftn-auto')
  PrepFtnDir(ftnautoinc)
  os.path.walk(petscdir, processDir, [petscdir, bfort])
  FixDir(petscdir,ftnautoinc)
  return
#
# The classes in this file can also be used in other python-programs by using 'import'
#
if __name__ ==  '__main__':
  import sys
  if len(sys.argv) < 2:
    sys.exit('Must give the BFORT program as the first argument')
  main(sys.argv[1])