123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- #!/usr/bin/env python3
- """
- Rules for building C/API module with f2py2e.
- Copyright 1999,2000 Pearu Peterson all rights reserved,
- Pearu Peterson <pearu@ioc.ee>
- Permission to use, modify, and distribute this software is given under the
- terms of the NumPy License.
- NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
- $Date: 2004/11/26 11:13:06 $
- Pearu Peterson
- """
- import copy
- from .auxfuncs import (
- getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
- isintent_out, islogicalfunction, ismoduleroutine, isscalar,
- issubroutine, issubroutine_wrap, outmess, show
- )
- from ._isocbind import isoc_kindmap
- def var2fixfortran(vars, a, fa=None, f90mode=None):
- if fa is None:
- fa = a
- if a not in vars:
- show(vars)
- outmess('var2fixfortran: No definition for argument "%s".\n' % a)
- return ''
- if 'typespec' not in vars[a]:
- show(vars[a])
- outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
- return ''
- vardef = vars[a]['typespec']
- if vardef == 'type' and 'typename' in vars[a]:
- vardef = '%s(%s)' % (vardef, vars[a]['typename'])
- selector = {}
- lk = ''
- if 'kindselector' in vars[a]:
- selector = vars[a]['kindselector']
- lk = 'kind'
- elif 'charselector' in vars[a]:
- selector = vars[a]['charselector']
- lk = 'len'
- if '*' in selector:
- if f90mode:
- if selector['*'] in ['*', ':', '(*)']:
- vardef = '%s(len=*)' % (vardef)
- else:
- vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
- else:
- if selector['*'] in ['*', ':']:
- vardef = '%s*(%s)' % (vardef, selector['*'])
- else:
- vardef = '%s*%s' % (vardef, selector['*'])
- else:
- if 'len' in selector:
- vardef = '%s(len=%s' % (vardef, selector['len'])
- if 'kind' in selector:
- vardef = '%s,kind=%s)' % (vardef, selector['kind'])
- else:
- vardef = '%s)' % (vardef)
- elif 'kind' in selector:
- vardef = '%s(kind=%s)' % (vardef, selector['kind'])
- vardef = '%s %s' % (vardef, fa)
- if 'dimension' in vars[a]:
- vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
- return vardef
- def useiso_c_binding(rout):
- useisoc = False
- for key, value in rout['vars'].items():
- kind_value = value.get('kindselector', {}).get('kind')
- if kind_value in isoc_kindmap:
- return True
- return useisoc
- def createfuncwrapper(rout, signature=0):
- assert isfunction(rout)
- extra_args = []
- vars = rout['vars']
- for a in rout['args']:
- v = rout['vars'][a]
- for i, d in enumerate(v.get('dimension', [])):
- if d == ':':
- dn = 'f2py_%s_d%s' % (a, i)
- dv = dict(typespec='integer', intent=['hide'])
- dv['='] = 'shape(%s, %s)' % (a, i)
- extra_args.append(dn)
- vars[dn] = dv
- v['dimension'][i] = dn
- rout['args'].extend(extra_args)
- need_interface = bool(extra_args)
- ret = ['']
- def add(line, ret=ret):
- ret[0] = '%s\n %s' % (ret[0], line)
- name = rout['name']
- fortranname = getfortranname(rout)
- f90mode = ismoduleroutine(rout)
- newname = '%sf2pywrap' % (name)
- if newname not in vars:
- vars[newname] = vars[name]
- args = [newname] + rout['args'][1:]
- else:
- args = [newname] + rout['args']
- l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
- if l_tmpl[:13] == 'character*(*)':
- if f90mode:
- l_tmpl = 'character(len=10)' + l_tmpl[13:]
- else:
- l_tmpl = 'character*10' + l_tmpl[13:]
- charselect = vars[name]['charselector']
- if charselect.get('*', '') == '(*)':
- charselect['*'] = '10'
- l1 = l_tmpl.replace('@@@NAME@@@', newname)
- rl = None
- useisoc = useiso_c_binding(rout)
- sargs = ', '.join(args)
- if f90mode:
- # gh-23598 fix warning
- # Essentially, this gets called again with modules where the name of the
- # function is added to the arguments, which is not required, and removed
- sargs = sargs.replace(f"{name}, ", '')
- args = [arg for arg in args if arg != name]
- rout['args'] = args
- add('subroutine f2pywrap_%s_%s (%s)' %
- (rout['modulename'], name, sargs))
- if not signature:
- add('use %s, only : %s' % (rout['modulename'], fortranname))
- if useisoc:
- add('use iso_c_binding')
- else:
- add('subroutine f2pywrap%s (%s)' % (name, sargs))
- if useisoc:
- add('use iso_c_binding')
- if not need_interface:
- add('external %s' % (fortranname))
- rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
- if need_interface:
- for line in rout['saved_interface'].split('\n'):
- if line.lstrip().startswith('use ') and '__user__' not in line:
- add(line)
- args = args[1:]
- dumped_args = []
- for a in args:
- if isexternal(vars[a]):
- add('external %s' % (a))
- dumped_args.append(a)
- for a in args:
- if a in dumped_args:
- continue
- if isscalar(vars[a]):
- add(var2fixfortran(vars, a, f90mode=f90mode))
- dumped_args.append(a)
- for a in args:
- if a in dumped_args:
- continue
- if isintent_in(vars[a]):
- add(var2fixfortran(vars, a, f90mode=f90mode))
- dumped_args.append(a)
- for a in args:
- if a in dumped_args:
- continue
- add(var2fixfortran(vars, a, f90mode=f90mode))
- add(l1)
- if rl is not None:
- add(rl)
- if need_interface:
- if f90mode:
- # f90 module already defines needed interface
- pass
- else:
- add('interface')
- add(rout['saved_interface'].lstrip())
- add('end interface')
- sargs = ', '.join([a for a in args if a not in extra_args])
- if not signature:
- if islogicalfunction(rout):
- add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
- else:
- add('%s = %s(%s)' % (newname, fortranname, sargs))
- if f90mode:
- add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
- else:
- add('end')
- return ret[0]
- def createsubrwrapper(rout, signature=0):
- assert issubroutine(rout)
- extra_args = []
- vars = rout['vars']
- for a in rout['args']:
- v = rout['vars'][a]
- for i, d in enumerate(v.get('dimension', [])):
- if d == ':':
- dn = 'f2py_%s_d%s' % (a, i)
- dv = dict(typespec='integer', intent=['hide'])
- dv['='] = 'shape(%s, %s)' % (a, i)
- extra_args.append(dn)
- vars[dn] = dv
- v['dimension'][i] = dn
- rout['args'].extend(extra_args)
- need_interface = bool(extra_args)
- ret = ['']
- def add(line, ret=ret):
- ret[0] = '%s\n %s' % (ret[0], line)
- name = rout['name']
- fortranname = getfortranname(rout)
- f90mode = ismoduleroutine(rout)
- args = rout['args']
- useisoc = useiso_c_binding(rout)
- sargs = ', '.join(args)
- if f90mode:
- add('subroutine f2pywrap_%s_%s (%s)' %
- (rout['modulename'], name, sargs))
- if useisoc:
- add('use iso_c_binding')
- if not signature:
- add('use %s, only : %s' % (rout['modulename'], fortranname))
- else:
- add('subroutine f2pywrap%s (%s)' % (name, sargs))
- if useisoc:
- add('use iso_c_binding')
- if not need_interface:
- add('external %s' % (fortranname))
- if need_interface:
- for line in rout['saved_interface'].split('\n'):
- if line.lstrip().startswith('use ') and '__user__' not in line:
- add(line)
- dumped_args = []
- for a in args:
- if isexternal(vars[a]):
- add('external %s' % (a))
- dumped_args.append(a)
- for a in args:
- if a in dumped_args:
- continue
- if isscalar(vars[a]):
- add(var2fixfortran(vars, a, f90mode=f90mode))
- dumped_args.append(a)
- for a in args:
- if a in dumped_args:
- continue
- add(var2fixfortran(vars, a, f90mode=f90mode))
- if need_interface:
- if f90mode:
- # f90 module already defines needed interface
- pass
- else:
- add('interface')
- for line in rout['saved_interface'].split('\n'):
- if line.lstrip().startswith('use ') and '__user__' in line:
- continue
- add(line)
- add('end interface')
- sargs = ', '.join([a for a in args if a not in extra_args])
- if not signature:
- add('call %s(%s)' % (fortranname, sargs))
- if f90mode:
- add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
- else:
- add('end')
- return ret[0]
- def assubr(rout):
- if isfunction_wrap(rout):
- fortranname = getfortranname(rout)
- name = rout['name']
- outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
- name, fortranname))
- rout = copy.copy(rout)
- fname = name
- rname = fname
- if 'result' in rout:
- rname = rout['result']
- rout['vars'][fname] = rout['vars'][rname]
- fvar = rout['vars'][fname]
- if not isintent_out(fvar):
- if 'intent' not in fvar:
- fvar['intent'] = []
- fvar['intent'].append('out')
- flag = 1
- for i in fvar['intent']:
- if i.startswith('out='):
- flag = 0
- break
- if flag:
- fvar['intent'].append('out=%s' % (rname))
- rout['args'][:] = [fname] + rout['args']
- return rout, createfuncwrapper(rout)
- if issubroutine_wrap(rout):
- fortranname = getfortranname(rout)
- name = rout['name']
- outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
- % (name, fortranname))
- rout = copy.copy(rout)
- return rout, createsubrwrapper(rout)
- return rout, ''
|