diff options
author | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-04 09:49:54 +0000 |
---|---|---|
committer | Pearu Peterson <pearu.peterson@gmail.com> | 2006-10-04 09:49:54 +0000 |
commit | c620acddd34a07edd6f33baad0adfad6e8cf1bd5 (patch) | |
tree | 3413710782a3f16711c4935cde86fbb5e69c35dd /numpy/f2py/lib/main.py | |
parent | ac93e95702a9047b774b4cdd1838c9e1b1f70739 (diff) | |
download | numpy-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.py | 272 |
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__ |