Spaces:
Sleeping
Sleeping
| """ | |
| Rules for building C/API module with f2py2e. | |
| Copyright 1999 -- 2011 Pearu Peterson all rights reserved. | |
| Copyright 2011 -- present NumPy Developers. | |
| 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. | |
| """ | |
| import copy | |
| from ._isocbind import isoc_kindmap | |
| from .auxfuncs import ( | |
| getfortranname, | |
| isexternal, | |
| isfunction, | |
| isfunction_wrap, | |
| isintent_in, | |
| isintent_out, | |
| islogicalfunction, | |
| ismoduleroutine, | |
| isscalar, | |
| issubroutine, | |
| issubroutine_wrap, | |
| outmess, | |
| show, | |
| ) | |
| def var2fixfortran(vars, a, fa=None, f90mode=None): | |
| if fa is None: | |
| fa = a | |
| if a not in vars: | |
| show(vars) | |
| outmess(f'var2fixfortran: No definition for argument "{a}".\n') | |
| return '' | |
| if 'typespec' not in vars[a]: | |
| show(vars[a]) | |
| outmess(f'var2fixfortran: No typespec for argument "{a}".\n') | |
| return '' | |
| vardef = vars[a]['typespec'] | |
| if vardef == 'type' and 'typename' in vars[a]: | |
| vardef = f"{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 = f'{vardef}(len=*)' | |
| else: | |
| vardef = f"{vardef}({lk}={selector['*']})" | |
| elif selector['*'] in ['*', ':']: | |
| vardef = f"{vardef}*({selector['*']})" | |
| else: | |
| vardef = f"{vardef}*{selector['*']}" | |
| elif 'len' in selector: | |
| vardef = f"{vardef}(len={selector['len']}" | |
| if 'kind' in selector: | |
| vardef = f"{vardef},kind={selector['kind']})" | |
| else: | |
| vardef = f'{vardef})' | |
| elif 'kind' in selector: | |
| vardef = f"{vardef}(kind={selector['kind']})" | |
| vardef = f'{vardef} {fa}' | |
| if 'dimension' in vars[a]: | |
| vardef = f"{vardef}({','.join(vars[a]['dimension'])})" | |
| return vardef | |
| def useiso_c_binding(rout): | |
| useisoc = False | |
| for value in rout['vars'].values(): | |
| 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 = f'f2py_{a}_d{i}' | |
| dv = {'typespec': 'integer', 'intent': ['hide']} | |
| dv['='] = f'shape({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] = f'{ret[0]}\n {line}' | |
| name = rout['name'] | |
| fortranname = getfortranname(rout) | |
| f90mode = ismoduleroutine(rout) | |
| newname = f'{name}f2pywrap' | |
| 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(f"subroutine f2pywrap_{rout['modulename']}_{name} ({sargs})") | |
| if not signature: | |
| add(f"use {rout['modulename']}, only : {fortranname}") | |
| if useisoc: | |
| add('use iso_c_binding') | |
| else: | |
| add(f'subroutine f2pywrap{name} ({sargs})') | |
| if useisoc: | |
| add('use iso_c_binding') | |
| if not need_interface: | |
| add(f'external {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(f'external {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(f'{newname} = .not.(.not.{fortranname}({sargs}))') | |
| else: | |
| add(f'{newname} = {fortranname}({sargs})') | |
| if f90mode: | |
| add(f"end subroutine f2pywrap_{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 = f'f2py_{a}_d{i}' | |
| dv = {'typespec': 'integer', 'intent': ['hide']} | |
| dv['='] = f'shape({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] = f'{ret[0]}\n {line}' | |
| name = rout['name'] | |
| fortranname = getfortranname(rout) | |
| f90mode = ismoduleroutine(rout) | |
| args = rout['args'] | |
| useisoc = useiso_c_binding(rout) | |
| sargs = ', '.join(args) | |
| if f90mode: | |
| add(f"subroutine f2pywrap_{rout['modulename']}_{name} ({sargs})") | |
| if useisoc: | |
| add('use iso_c_binding') | |
| if not signature: | |
| add(f"use {rout['modulename']}, only : {fortranname}") | |
| else: | |
| add(f'subroutine f2pywrap{name} ({sargs})') | |
| if useisoc: | |
| add('use iso_c_binding') | |
| if not need_interface: | |
| add(f'external {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(f'external {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(f'call {fortranname}({sargs})') | |
| if f90mode: | |
| add(f"end subroutine f2pywrap_{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(f'out={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, '' | |