123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- #!/usr/bin/env python
- """
- f2py2e - Fortran to Python C/API generator. 2nd Edition.
- See __usage__ below.
- Copyright 1999--2011 Pearu Peterson all rights reserved,
- Pearu Peterson <pearu@cens.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: 2005/05/06 08:31:19 $
- Pearu Peterson
- """
- from __future__ import division, absolute_import, print_function
- import sys
- import os
- import pprint
- import re
- from . import crackfortran
- from . import rules
- from . import cb_rules
- from . import auxfuncs
- from . import cfuncs
- from . import f90mod_rules
- from . import __version__
- f2py_version = __version__.version
- errmess = sys.stderr.write
- # outmess=sys.stdout.write
- show = pprint.pprint
- outmess = auxfuncs.outmess
- try:
- from numpy import __version__ as numpy_version
- except ImportError:
- numpy_version = 'N/A'
- __usage__ = """\
- Usage:
- 1) To construct extension module sources:
- f2py [<options>] <fortran files> [[[only:]||[skip:]] \\
- <fortran functions> ] \\
- [: <fortran files> ...]
- 2) To compile fortran files and build extension modules:
- f2py -c [<options>, <build_flib options>, <extra options>] <fortran files>
- 3) To generate signature files:
- f2py -h <filename.pyf> ...< same options as in (1) >
- Description: This program generates a Python C/API file (<modulename>module.c)
- that contains wrappers for given fortran functions so that they
- can be called from Python. With the -c option the corresponding
- extension modules are built.
- Options:
- --2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT]
- --2d-numeric Use f2py2e tool with Numeric support.
- --2d-numarray Use f2py2e tool with Numarray support.
- --g3-numpy Use 3rd generation f2py from the separate f2py package.
- [NOT AVAILABLE YET]
- -h <filename> Write signatures of the fortran routines to file <filename>
- and exit. You can then edit <filename> and use it instead
- of <fortran files>. If <filename>==stdout then the
- signatures are printed to stdout.
- <fortran functions> Names of fortran routines for which Python C/API
- functions will be generated. Default is all that are found
- in <fortran files>.
- <fortran files> Paths to fortran/signature files that will be scanned for
- <fortran functions> in order to determine their signatures.
- skip: Ignore fortran functions that follow until `:'.
- only: Use only fortran functions that follow until `:'.
- : Get back to <fortran files> mode.
- -m <modulename> Name of the module; f2py generates a Python/C API
- file <modulename>module.c or extension module <modulename>.
- Default is 'untitled'.
- --[no-]lower Do [not] lower the cases in <fortran files>. By default,
- --lower is assumed with -h key, and --no-lower without -h key.
- --build-dir <dirname> All f2py generated files are created in <dirname>.
- Default is tempfile.mkdtemp().
- --overwrite-signature Overwrite existing signature file.
- --[no-]latex-doc Create (or not) <modulename>module.tex.
- Default is --no-latex-doc.
- --short-latex Create 'incomplete' LaTeX document (without commands
- \\documentclass, \\tableofcontents, and \\begin{document},
- \\end{document}).
- --[no-]rest-doc Create (or not) <modulename>module.rst.
- Default is --no-rest-doc.
- --debug-capi Create C/API code that reports the state of the wrappers
- during runtime. Useful for debugging.
- --[no-]wrap-functions Create Fortran subroutine wrappers to Fortran 77
- functions. --wrap-functions is default because it ensures
- maximum portability/compiler independence.
- --include-paths <path1>:<path2>:... Search include files from the given
- directories.
- --help-link [..] List system resources found by system_info.py. See also
- --link-<resource> switch below. [..] is optional list
- of resources names. E.g. try 'f2py --help-link lapack_opt'.
- --quiet Run quietly.
- --verbose Run with extra verbosity.
- -v Print f2py version ID and exit.
- numpy.distutils options (only effective with -c):
- --fcompiler= Specify Fortran compiler type by vendor
- --compiler= Specify C compiler type (as defined by distutils)
- --help-fcompiler List available Fortran compilers and exit
- --f77exec= Specify the path to F77 compiler
- --f90exec= Specify the path to F90 compiler
- --f77flags= Specify F77 compiler flags
- --f90flags= Specify F90 compiler flags
- --opt= Specify optimization flags
- --arch= Specify architecture specific optimization flags
- --noopt Compile without optimization
- --noarch Compile without arch-dependent optimization
- --debug Compile with debugging information
- Extra options (only effective with -c):
- --link-<resource> Link extension module with <resource> as defined
- by numpy.distutils/system_info.py. E.g. to link
- with optimized LAPACK libraries (vecLib on MacOSX,
- ATLAS elsewhere), use --link-lapack_opt.
- See also --help-link switch.
- -L/path/to/lib/ -l<libname>
- -D<define> -U<name>
- -I/path/to/include/
- <filename>.o <filename>.so <filename>.a
- Using the following macros may be required with non-gcc Fortran
- compilers:
- -DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN
- -DUNDERSCORE_G77
- When using -DF2PY_REPORT_ATEXIT, a performance report of F2PY
- interface is printed out at exit (platforms: Linux).
- When using -DF2PY_REPORT_ON_ARRAY_COPY=<int>, a message is
- sent to stderr whenever F2PY interface makes a copy of an
- array. Integer <int> sets the threshold for array sizes when
- a message should be shown.
- Version: %s
- numpy Version: %s
- Requires: Python 2.3 or higher.
- License: NumPy license (see LICENSE.txt in the NumPy source code)
- Copyright 1999 - 2011 Pearu Peterson all rights reserved.
- http://cens.ioc.ee/projects/f2py2e/""" % (f2py_version, numpy_version)
- def scaninputline(inputline):
- files, skipfuncs, onlyfuncs, debug = [], [], [], []
- f, f2, f3, f5, f6, f7, f8, f9 = 1, 0, 0, 0, 0, 0, 0, 0
- verbose = 1
- dolc = -1
- dolatexdoc = 0
- dorestdoc = 0
- wrapfuncs = 1
- buildpath = '.'
- include_paths = []
- signsfile, modulename = None, None
- options = {'buildpath': buildpath,
- 'coutput': None,
- 'f2py_wrapper_output': None}
- for l in inputline:
- if l == '':
- pass
- elif l == 'only:':
- f = 0
- elif l == 'skip:':
- f = -1
- elif l == ':':
- f = 1
- elif l[:8] == '--debug-':
- debug.append(l[8:])
- elif l == '--lower':
- dolc = 1
- elif l == '--build-dir':
- f6 = 1
- elif l == '--no-lower':
- dolc = 0
- elif l == '--quiet':
- verbose = 0
- elif l == '--verbose':
- verbose += 1
- elif l == '--latex-doc':
- dolatexdoc = 1
- elif l == '--no-latex-doc':
- dolatexdoc = 0
- elif l == '--rest-doc':
- dorestdoc = 1
- elif l == '--no-rest-doc':
- dorestdoc = 0
- elif l == '--wrap-functions':
- wrapfuncs = 1
- elif l == '--no-wrap-functions':
- wrapfuncs = 0
- elif l == '--short-latex':
- options['shortlatex'] = 1
- elif l == '--coutput':
- f8 = 1
- elif l == '--f2py-wrapper-output':
- f9 = 1
- elif l == '--overwrite-signature':
- options['h-overwrite'] = 1
- elif l == '-h':
- f2 = 1
- elif l == '-m':
- f3 = 1
- elif l[:2] == '-v':
- print(f2py_version)
- sys.exit()
- elif l == '--show-compilers':
- f5 = 1
- elif l[:8] == '-include':
- cfuncs.outneeds['userincludes'].append(l[9:-1])
- cfuncs.userincludes[l[9:-1]] = '#include ' + l[8:]
- elif l[:15] in '--include_paths':
- outmess(
- 'f2py option --include_paths is deprecated, use --include-paths instead.\n')
- f7 = 1
- elif l[:15] in '--include-paths':
- f7 = 1
- elif l[0] == '-':
- errmess('Unknown option %s\n' % repr(l))
- sys.exit()
- elif f2:
- f2 = 0
- signsfile = l
- elif f3:
- f3 = 0
- modulename = l
- elif f6:
- f6 = 0
- buildpath = l
- elif f7:
- f7 = 0
- include_paths.extend(l.split(os.pathsep))
- elif f8:
- f8 = 0
- options["coutput"] = l
- elif f9:
- f9 = 0
- options["f2py_wrapper_output"] = l
- elif f == 1:
- try:
- open(l).close()
- files.append(l)
- except IOError as detail:
- errmess('IOError: %s. Skipping file "%s".\n' %
- (str(detail), l))
- elif f == -1:
- skipfuncs.append(l)
- elif f == 0:
- onlyfuncs.append(l)
- if not f5 and not files and not modulename:
- print(__usage__)
- sys.exit()
- if not os.path.isdir(buildpath):
- if not verbose:
- outmess('Creating build directory %s' % (buildpath))
- os.mkdir(buildpath)
- if signsfile:
- signsfile = os.path.join(buildpath, signsfile)
- if signsfile and os.path.isfile(signsfile) and 'h-overwrite' not in options:
- errmess(
- 'Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n' % (signsfile))
- sys.exit()
- options['debug'] = debug
- options['verbose'] = verbose
- if dolc == -1 and not signsfile:
- options['do-lower'] = 0
- else:
- options['do-lower'] = dolc
- if modulename:
- options['module'] = modulename
- if signsfile:
- options['signsfile'] = signsfile
- if onlyfuncs:
- options['onlyfuncs'] = onlyfuncs
- if skipfuncs:
- options['skipfuncs'] = skipfuncs
- options['dolatexdoc'] = dolatexdoc
- options['dorestdoc'] = dorestdoc
- options['wrapfuncs'] = wrapfuncs
- options['buildpath'] = buildpath
- options['include_paths'] = include_paths
- return files, options
- def callcrackfortran(files, options):
- rules.options = options
- crackfortran.debug = options['debug']
- crackfortran.verbose = options['verbose']
- if 'module' in options:
- crackfortran.f77modulename = options['module']
- if 'skipfuncs' in options:
- crackfortran.skipfuncs = options['skipfuncs']
- if 'onlyfuncs' in options:
- crackfortran.onlyfuncs = options['onlyfuncs']
- crackfortran.include_paths[:] = options['include_paths']
- crackfortran.dolowercase = options['do-lower']
- postlist = crackfortran.crackfortran(files)
- if 'signsfile' in options:
- outmess('Saving signatures to file "%s"\n' % (options['signsfile']))
- pyf = crackfortran.crack2fortran(postlist)
- if options['signsfile'][-6:] == 'stdout':
- sys.stdout.write(pyf)
- else:
- f = open(options['signsfile'], 'w')
- f.write(pyf)
- f.close()
- if options["coutput"] is None:
- for mod in postlist:
- mod["coutput"] = "%smodule.c" % mod["name"]
- else:
- for mod in postlist:
- mod["coutput"] = options["coutput"]
- if options["f2py_wrapper_output"] is None:
- for mod in postlist:
- mod["f2py_wrapper_output"] = "%s-f2pywrappers.f" % mod["name"]
- else:
- for mod in postlist:
- mod["f2py_wrapper_output"] = options["f2py_wrapper_output"]
- return postlist
- def buildmodules(lst):
- cfuncs.buildcfuncs()
- outmess('Building modules...\n')
- modules, mnames, isusedby = [], [], {}
- for i in range(len(lst)):
- if '__user__' in lst[i]['name']:
- cb_rules.buildcallbacks(lst[i])
- else:
- if 'use' in lst[i]:
- for u in lst[i]['use'].keys():
- if u not in isusedby:
- isusedby[u] = []
- isusedby[u].append(lst[i]['name'])
- modules.append(lst[i])
- mnames.append(lst[i]['name'])
- ret = {}
- for i in range(len(mnames)):
- if mnames[i] in isusedby:
- outmess('\tSkipping module "%s" which is used by %s.\n' % (
- mnames[i], ','.join(['"%s"' % s for s in isusedby[mnames[i]]])))
- else:
- um = []
- if 'use' in modules[i]:
- for u in modules[i]['use'].keys():
- if u in isusedby and u in mnames:
- um.append(modules[mnames.index(u)])
- else:
- outmess(
- '\tModule "%s" uses nonexisting "%s" which will be ignored.\n' % (mnames[i], u))
- ret[mnames[i]] = {}
- dict_append(ret[mnames[i]], rules.buildmodule(modules[i], um))
- return ret
- def dict_append(d_out, d_in):
- for (k, v) in d_in.items():
- if k not in d_out:
- d_out[k] = []
- if isinstance(v, list):
- d_out[k] = d_out[k] + v
- else:
- d_out[k].append(v)
- def run_main(comline_list):
- """
- Equivalent to running::
- f2py <args>
- where ``<args>=string.join(<list>,' ')``, but in Python. Unless
- ``-h`` is used, this function returns a dictionary containing
- information on generated modules and their dependencies on source
- files. For example, the command ``f2py -m scalar scalar.f`` can be
- executed from Python as follows
- You cannot build extension modules with this function, that is,
- using ``-c`` is not allowed. Use ``compile`` command instead
- Examples
- --------
- .. include:: run_main_session.dat
- :literal:
- """
- crackfortran.reset_global_f2py_vars()
- f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__))
- fobjhsrc = os.path.join(f2pydir, 'src', 'fortranobject.h')
- fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c')
- files, options = scaninputline(comline_list)
- auxfuncs.options = options
- postlist = callcrackfortran(files, options)
- isusedby = {}
- for i in range(len(postlist)):
- if 'use' in postlist[i]:
- for u in postlist[i]['use'].keys():
- if u not in isusedby:
- isusedby[u] = []
- isusedby[u].append(postlist[i]['name'])
- for i in range(len(postlist)):
- if postlist[i]['block'] == 'python module' and '__user__' in postlist[i]['name']:
- if postlist[i]['name'] in isusedby:
- # if not quiet:
- outmess('Skipping Makefile build for module "%s" which is used by %s\n' % (
- postlist[i]['name'], ','.join(['"%s"' % s for s in isusedby[postlist[i]['name']]])))
- if 'signsfile' in options:
- if options['verbose'] > 1:
- outmess(
- 'Stopping. Edit the signature file and then run f2py on the signature file: ')
- outmess('%s %s\n' %
- (os.path.basename(sys.argv[0]), options['signsfile']))
- return
- for i in range(len(postlist)):
- if postlist[i]['block'] != 'python module':
- if 'python module' not in options:
- errmess(
- 'Tip: If your original code is Fortran source then you must use -m option.\n')
- raise TypeError('All blocks must be python module blocks but got %s' % (
- repr(postlist[i]['block'])))
- auxfuncs.debugoptions = options['debug']
- f90mod_rules.options = options
- auxfuncs.wrapfuncs = options['wrapfuncs']
- ret = buildmodules(postlist)
- for mn in ret.keys():
- dict_append(ret[mn], {'csrc': fobjcsrc, 'h': fobjhsrc})
- return ret
- def filter_files(prefix, suffix, files, remove_prefix=None):
- """
- Filter files by prefix and suffix.
- """
- filtered, rest = [], []
- match = re.compile(prefix + r'.*' + suffix + r'\Z').match
- if remove_prefix:
- ind = len(prefix)
- else:
- ind = 0
- for file in [x.strip() for x in files]:
- if match(file):
- filtered.append(file[ind:])
- else:
- rest.append(file)
- return filtered, rest
- def get_prefix(module):
- p = os.path.dirname(os.path.dirname(module.__file__))
- return p
- def run_compile():
- """
- Do it all in one call!
- """
- import tempfile
- i = sys.argv.index('-c')
- del sys.argv[i]
- remove_build_dir = 0
- try:
- i = sys.argv.index('--build-dir')
- except ValueError:
- i = None
- if i is not None:
- build_dir = sys.argv[i + 1]
- del sys.argv[i + 1]
- del sys.argv[i]
- else:
- remove_build_dir = 1
- build_dir = tempfile.mkdtemp()
- _reg1 = re.compile(r'[-][-]link[-]')
- sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)]
- sys.argv = [_m for _m in sys.argv if _m not in sysinfo_flags]
- if sysinfo_flags:
- sysinfo_flags = [f[7:] for f in sysinfo_flags]
- _reg2 = re.compile(
- r'[-][-]((no[-]|)(wrap[-]functions|lower)|debug[-]capi|quiet)|[-]include')
- f2py_flags = [_m for _m in sys.argv[1:] if _reg2.match(_m)]
- sys.argv = [_m for _m in sys.argv if _m not in f2py_flags]
- f2py_flags2 = []
- fl = 0
- for a in sys.argv[1:]:
- if a in ['only:', 'skip:']:
- fl = 1
- elif a == ':':
- fl = 0
- if fl or a == ':':
- f2py_flags2.append(a)
- if f2py_flags2 and f2py_flags2[-1] != ':':
- f2py_flags2.append(':')
- f2py_flags.extend(f2py_flags2)
- sys.argv = [_m for _m in sys.argv if _m not in f2py_flags2]
- _reg3 = re.compile(
- r'[-][-]((f(90)?compiler([-]exec|)|compiler)=|help[-]compiler)')
- flib_flags = [_m for _m in sys.argv[1:] if _reg3.match(_m)]
- sys.argv = [_m for _m in sys.argv if _m not in flib_flags]
- _reg4 = re.compile(
- r'[-][-]((f(77|90)(flags|exec)|opt|arch)=|(debug|noopt|noarch|help[-]fcompiler))')
- fc_flags = [_m for _m in sys.argv[1:] if _reg4.match(_m)]
- sys.argv = [_m for _m in sys.argv if _m not in fc_flags]
- if 1:
- del_list = []
- for s in flib_flags:
- v = '--fcompiler='
- if s[:len(v)] == v:
- from numpy.distutils import fcompiler
- fcompiler.load_all_fcompiler_classes()
- allowed_keys = list(fcompiler.fcompiler_class.keys())
- nv = ov = s[len(v):].lower()
- if ov not in allowed_keys:
- vmap = {} # XXX
- try:
- nv = vmap[ov]
- except KeyError:
- if ov not in vmap.values():
- print('Unknown vendor: "%s"' % (s[len(v):]))
- nv = ov
- i = flib_flags.index(s)
- flib_flags[i] = '--fcompiler=' + nv
- continue
- for s in del_list:
- i = flib_flags.index(s)
- del flib_flags[i]
- assert len(flib_flags) <= 2, repr(flib_flags)
- _reg5 = re.compile(r'[-][-](verbose)')
- setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)]
- sys.argv = [_m for _m in sys.argv if _m not in setup_flags]
- if '--quiet' in f2py_flags:
- setup_flags.append('--quiet')
- modulename = 'untitled'
- sources = sys.argv[1:]
- for optname in ['--include_paths', '--include-paths']:
- if optname in sys.argv:
- i = sys.argv.index(optname)
- f2py_flags.extend(sys.argv[i:i + 2])
- del sys.argv[i + 1], sys.argv[i]
- sources = sys.argv[1:]
- if '-m' in sys.argv:
- i = sys.argv.index('-m')
- modulename = sys.argv[i + 1]
- del sys.argv[i + 1], sys.argv[i]
- sources = sys.argv[1:]
- else:
- from numpy.distutils.command.build_src import get_f2py_modulename
- pyf_files, sources = filter_files('', '[.]pyf([.]src|)', sources)
- sources = pyf_files + sources
- for f in pyf_files:
- modulename = get_f2py_modulename(f)
- if modulename:
- break
- extra_objects, sources = filter_files('', '[.](o|a|so)', sources)
- include_dirs, sources = filter_files('-I', '', sources, remove_prefix=1)
- library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1)
- libraries, sources = filter_files('-l', '', sources, remove_prefix=1)
- undef_macros, sources = filter_files('-U', '', sources, remove_prefix=1)
- define_macros, sources = filter_files('-D', '', sources, remove_prefix=1)
- for i in range(len(define_macros)):
- name_value = define_macros[i].split('=', 1)
- if len(name_value) == 1:
- name_value.append(None)
- if len(name_value) == 2:
- define_macros[i] = tuple(name_value)
- else:
- print('Invalid use of -D:', name_value)
- from numpy.distutils.system_info import get_info
- num_info = {}
- if num_info:
- include_dirs.extend(num_info.get('include_dirs', []))
- from numpy.distutils.core import setup, Extension
- ext_args = {'name': modulename, 'sources': sources,
- 'include_dirs': include_dirs,
- 'library_dirs': library_dirs,
- 'libraries': libraries,
- 'define_macros': define_macros,
- 'undef_macros': undef_macros,
- 'extra_objects': extra_objects,
- 'f2py_options': f2py_flags,
- }
- if sysinfo_flags:
- from numpy.distutils.misc_util import dict_append
- for n in sysinfo_flags:
- i = get_info(n)
- if not i:
- outmess('No %s resources found in system'
- ' (try `f2py --help-link`)\n' % (repr(n)))
- dict_append(ext_args, **i)
- ext = Extension(**ext_args)
- sys.argv = [sys.argv[0]] + setup_flags
- sys.argv.extend(['build',
- '--build-temp', build_dir,
- '--build-base', build_dir,
- '--build-platlib', '.'])
- if fc_flags:
- sys.argv.extend(['config_fc'] + fc_flags)
- if flib_flags:
- sys.argv.extend(['build_ext'] + flib_flags)
- setup(ext_modules=[ext])
- if remove_build_dir and os.path.exists(build_dir):
- import shutil
- outmess('Removing build directory %s\n' % (build_dir))
- shutil.rmtree(build_dir)
- def main():
- if '--help-link' in sys.argv[1:]:
- sys.argv.remove('--help-link')
- from numpy.distutils.system_info import show_all
- show_all()
- return
- # Probably outdated options that were not working before 1.16
- if '--g3-numpy' in sys.argv[1:]:
- sys.stderr.write("G3 f2py support is not implemented, yet.\\n")
- sys.exit(1)
- elif '--2e-numeric' in sys.argv[1:]:
- sys.argv.remove('--2e-numeric')
- elif '--2e-numarray' in sys.argv[1:]:
- # Note that this errors becaust the -DNUMARRAY argument is
- # not recognized. Just here for back compatibility and the
- # error message.
- sys.argv.append("-DNUMARRAY")
- sys.argv.remove('--2e-numarray')
- elif '--2e-numpy' in sys.argv[1:]:
- sys.argv.remove('--2e-numpy')
- else:
- pass
- if '-c' in sys.argv[1:]:
- run_compile()
- else:
- run_main(sys.argv[1:])
|