summaryrefslogtreecommitdiff
path: root/numpy/f2py/lib/main.py
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2006-10-04 09:49:54 +0000
committerPearu Peterson <pearu.peterson@gmail.com>2006-10-04 09:49:54 +0000
commitc620acddd34a07edd6f33baad0adfad6e8cf1bd5 (patch)
tree3413710782a3f16711c4935cde86fbb5e69c35dd /numpy/f2py/lib/main.py
parentac93e95702a9047b774b4cdd1838c9e1b1f70739 (diff)
downloadnumpy-c620acddd34a07edd6f33baad0adfad6e8cf1bd5.tar.gz
F2PY G3: exposed wrappers via f2py script. A working example: wrap F90 module containing derived type with scalar components.
Diffstat (limited to 'numpy/f2py/lib/main.py')
-rw-r--r--numpy/f2py/lib/main.py272
1 files changed, 231 insertions, 41 deletions
diff --git a/numpy/f2py/lib/main.py b/numpy/f2py/lib/main.py
index 64b9447f5..c5b40cf35 100644
--- a/numpy/f2py/lib/main.py
+++ b/numpy/f2py/lib/main.py
@@ -12,7 +12,9 @@ Created: Oct 2006
"""
import os
+import re
import sys
+import tempfile
try:
from numpy import __version__ as numpy_version
@@ -44,53 +46,92 @@ Options
"""
-from parser.api import parse, PythonModule, EndStatement
+import re
+import shutil
+from parser.api import parse, PythonModule, EndStatement, Module, Subroutine, Function
-def dump_signature():
- """ Read Fortran files and dump the signatures to file or stdout.
+def get_values(sys_argv, prefix='', suffix='', strip_prefix=False, strip_suffix=False):
"""
- # get signature output
- i = sys.argv.index('-h')
- if len(sys.argv)-1==i:
- signature_output = 'stdout'
- else:
- signature_output = sys.argv[i+1]
- del sys.argv[i+1]
- del sys.argv[i]
+ Return a list of values with pattern
+ <prefix><value><suffix>.
+ The corresponding items will be removed from sys_argv.
+ """
+ match = re.compile(prefix + r'.*' + suffix + '\Z').match
+ ret = [item for item in sys_argv if match(item)]
+ [sys_argv.remove(item) for item in ret]
+ if strip_prefix and prefix:
+ i = len(prefix)
+ ret = [item[i:] for item in ret]
+ if strip_suffix and suffix:
+ i = len(suffix)
+ ret = [item[:-i] for item in ret]
+ return ret
- # get module name
+def get_option(sys_argv, option, default_return = None):
+ """
+ Return True if sys_argv has <option>.
+ If <option> is not in sys_argv, return default_return.
+ <option> (when present) will be removed from sys_argv.
+ """
try:
- i = sys.argv.index('-m')
+ i = sys_argv.index(option)
except ValueError:
- i = None
- module_name = 'unknown'
- if i is not None:
- if len(sys.argv)-1==i:
- module_name = 'unspecified'
- else:
- module_name = sys.argv[i+1]
- del sys.argv[i+1]
- del sys.argv[i]
+ return default_return
+ del sys_argv[i]
+ return True
+
+def get_option_value(sys_argv, option, default_value = None, default_return = None):
+ """
+ Return <value> from
+ sys_argv = [...,<option>,<value>,...]
+ list.
+ If <option> is the last element, return default_value.
+ If <option> is not in sys_argv, return default_return.
+ Both <option> and <value> (when present) will be removed from sys_argv.
+ """
+ try:
+ i = sys_argv.index(option)
+ except ValueError:
+ return default_return
+ if len(sys_argv)-1==i:
+ del sys_argv[i]
+ return default_value
+ value = sys_argv[i+1]
+ del sys_argv[i+1]
+ del sys_argv[i]
+ return value
+
+def get_signature_output(sys_argv):
+ return get_option_value(sys_argv,'-h','stdout')
+
+def dump_signature(sys_argv):
+ """ Read Fortran files and dump the signatures to file or stdout.
+ XXX: Not well tested.
+ """
+ signature_output = get_signature_output(sys_argv)
# initialize output stream
if signature_output in ['stdout','stderr']:
output_stream = getattr(sys, signature_output)
+ modulename = get_option_value(sys_argv,'-m','untitled','unknown')
else:
+ name,ext = os.path.splitext(signature_output)
+ if ext != '.pyf':
+ signature_output += '.pyf'
if os.path.isfile(signature_output):
- try:
- i = sys.argv.index('--overwrite-signature')
- del sys.argv[i]
- except ValueError:
+ overwrite = get_option(sys_argv, '--overwrite-signature', False)
+ if not overwrite:
print >> sys.stderr, 'Signature file %r exists. Use --overwrite-signature to overwrite.' % (signature_output)
sys.exit()
+ modulename = get_option_value(sys_argv,'-m',os.path.basename(name),os.path.basename(name))
output_stream = open(signature_output,'w')
flag = 'file'
- file_names = []
+ file_names = []
only_names = []
skip_names = []
options = []
- for word in sys.argv[1:]:
+ for word in sys_argv[1:]:
if word=='': pass
elif word=='only:': flag = 'only'
elif word=='skip:': flag = 'skip'
@@ -99,15 +140,22 @@ def dump_signature():
else:
{'file': file_names,'only': only_names, 'skip': skip_names}[flag].append(word)
+ if options:
+ sys.stderr.write('Unused options: %s\n' % (', '.join(options)))
+
output_stream.write('''! -*- f90 -*-
! Note: the context of this file is case sensitive.
''')
output_stream.write('PYTHON MODULE %s\n' % (module_name))
output_stream.write(' INTERFACE\n\n')
for filename in file_names:
+ if not os.path.isfile(filename):
+ sys.stderr.write('No or not a file %r. Skipping.\n' % (filename))
+ continue
+ sys.stderr.write('Parsing %r..\n' % (filename))
block = parse(filename)
- output_stream.write('! File: %s, source mode = %s\n' % (filename, block.reader.mode))
- if isinstance(block.content[0],PythonModule):
+ output_stream.write('! File: %s, source mode = %r\n' % (filename, block.reader.mode))
+ if block.content and isinstance(block.content[0],PythonModule):
for subblock in block.content[0].content[0].content:
if isinstance(subblock, EndStatement):
break
@@ -121,23 +169,165 @@ def dump_signature():
output_stream.close()
return
-def build_extension():
- raise NotImplementedError,'build_extension'
+def build_extension(sys_argv):
+ """
+ Build wrappers to Fortran 90 modules and external subprograms.
+ """
+ modulename = get_option_value(sys_argv,'-m','untitled','unknown')
+
+ build_dir = get_option_value('--build-dir','.',None)
+ if build_dir is None:
+ build_dir = tempfile.mktemp()
+ clean_build_dir = True
+ else:
+ clean_build_dir = False
+ if not os.path.exists(build_dir): os.makedirs(build_dir)
+
+ include_dirs = get_values(sys_argv,'-I',strip_prefix=True)
+ library_dirs = get_values(sys_argv,'-L',strip_prefix=True)
+ libraries = get_values(sys_argv,'-l',strip_prefix=True)
+ _define_macros = get_values(sys_argv,'-D',strip_prefix=True)
+ undef_macros = get_values(sys_argv,'-U',strip_prefix=True)
+ extra_objects = get_values(sys_argv,'','[.](o|a|so|dll|dynlib|sl)')
+
+ define_macros = []
+ for item in _define_macros:
+ name_value = item.split('=',1)
+ if len(name_value)==1:
+ name_value.append(None)
+ if len(name_value)==2:
+ define_macros.append(tuple(name_value))
+ else:
+ print 'Invalid use of -D:',name_value
+
+ pyf_files = get_values(sys_argv,'','[.]pyf')
+ fortran_files = get_values(sys_argv,'','[.](f|f90|F90|F)')
+ c_files = get_values(sys_argv,'','[.](c|cpp|C|CPP|c[+][+])')
+
+ fc_flags = get_values(sys_argv,'--fcompiler=')
+
+ options = get_values(sys_argv,'-')
+ if options:
+ sys.stderr.write('Unused options: %s\n' % (', '.join(options)))
+
+ if pyf_files:
+ parse_files = pyf_files
+ else:
+ parse_files = fortran_files + c_files
+
+ f90_modules = []
+ external_subprograms = []
+
+ for filename in parse_files:
+ if not os.path.isfile(filename):
+ sys.stderr.write('No or not a file %r. Skipping.\n' % (filename))
+ continue
+ sys.stderr.write('Parsing %r..\n' % (filename))
+ for block in parse(filename, include_dirs=include_dirs).content:
+ if isinstance(block, Module):
+ f90_modules.append(block)
+ elif isinstance(block, (Subroutine, Function)):
+ external_subprograms.append(block)
+ else:
+ sys.stderr.write("Unhandled structure: %r\n" % (block.__class__))
+
+ from py_wrap import PythonWrapperModule
+ def configuration(parent_package='', top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('',parent_package,top_path)
+ flibname = modulename + '_fortran_f2py'
+ if fortran_files:
+ config.add_library(flibname,
+ sources = fortran_files)
+ libraries.insert(0,flibname)
+
+ for block in f90_modules:
+ wrapper = PythonWrapperModule(block.name)
+ wrapper.add(block)
+ c_code = wrapper.c_code()
+ f_code = wrapper.fortran_code()
+ c_fn = os.path.join(build_dir,'%smodule.c' % (block.name))
+ f_fn = os.path.join(build_dir,'%s_f_wrappers_f2py.f' % (block.name))
+ f = open(c_fn,'w')
+ f.write(c_code)
+ f.close()
+ f = open(f_fn,'w')
+ f.write(f_code)
+ f.close()
+ f_lib = '%s_f_wrappers_f2py' % (block.name)
+ config.add_library(f_lib,
+ sources = [f_fn])
+ config.add_extension(block.name,
+ sources=[c_fn] + c_files,
+ libraries = [f_lib] + libraries,
+ define_macros = define_macros,
+ undef_macros = undef_macros,
+ include_dirs = include_dirs,
+ extra_objects = extra_objects,
+ )
+ if external_subprograms:
+ wrapper = PythonWrapper(modulename)
+ for block in external_subprograms:
+ wrapper.add(block)
+ c_code = wrapper.c_code()
+ f_code = wrapper.fortran_code()
+ c_fn = os.path.join(temp_dir,'%smodule.c' % (modulename))
+ f_fn = os.path.join(temp_dir,'%s_f_wrappers_f2py.f' % (modulename))
+ f = open(c_fn,'w')
+ f.write(c_code)
+ f.close()
+ f = open(f_fn,'w')
+ f.write(f_code)
+ f.close()
+ f_lib = '%s_f_wrappers_f2py' % (modulename)
+ config.add_library(f_lib,
+ sources = [f_fn])
+ config.add_extension(modulename,
+ sources=[c_fn] + c_files,
+ libraries = [f_lib] + libraries,
+ define_macros = define_macros,
+ undef_macros = undef_macros,
+ include_dirs = include_dirs,
+ extra_objects = extra_objects,
+ )
+ return config
+
+ old_sys_argv = sys.argv[:]
+ new_sys_argv = [sys.argv[0]] + ['build',
+ '--build-temp',build_dir,
+ '--build-base',build_dir,
+ '--build-platlib','.']
+ if fc_flags:
+ new_sys_argv += ['config_fc'] + fc_flags
+ sys.argv[:] = new_sys_argv
+
+ sys.stderr.write('setup arguments: %r' % (' '.join(sys.argv)))
+
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
+
+ sys.argv[:] = old_sys_argv
+
+ if clean_build_dir and os.path.exists(build_dir):
+ sys.stderr.write('Removing build directory %s\n'%(build_dir))
+ shutil.rmtree(build_dir)
+ return
-def main():
+def main(sys_argv = None):
""" Main function of f2py script.
"""
- if '--help-link' in sys.argv[1:]:
- sys.argv.remove('--help-link')
+ if sys_argv is None:
+ sys_argv = sys.argv[1:]
+ if '--help-link' in sys_argv:
+ sys_argv.remove('--help-link')
from numpy.distutils.system_info import show_all
show_all()
return
- if '-c' in sys.argv[1:]:
- i = sys.argv.index('-c')
- del sys.argv[i]
- build_extension()
+ if '-c' in sys_argv:
+ sys_argv.remove('-c')
+ build_extension(sys_argv)
return
- if '-h' in sys.argv[1:]:
- dump_signature()
+ if '-h' in sys_argv:
+ dump_signature(sys_argv)
return
print >> sys.stdout, __usage__