123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- """ Build swig and f2py sources.
- """
- import os
- import re
- import sys
- import shlex
- import copy
- from distutils.command import build_ext
- from distutils.dep_util import newer_group, newer
- from distutils.util import get_platform
- from distutils.errors import DistutilsError, DistutilsSetupError
- # this import can't be done here, as it uses numpy stuff only available
- # after it's installed
- #import numpy.f2py
- from numpy.distutils import log
- from numpy.distutils.misc_util import (
- fortran_ext_match, appendpath, is_string, is_sequence, get_cmd
- )
- from numpy.distutils.from_template import process_file as process_f_file
- from numpy.distutils.conv_template import process_file as process_c_file
- def subst_vars(target, source, d):
- """Substitute any occurrence of @foo@ by d['foo'] from source file into
- target."""
- var = re.compile('@([a-zA-Z_]+)@')
- with open(source, 'r') as fs:
- with open(target, 'w') as ft:
- for l in fs:
- m = var.search(l)
- if m:
- ft.write(l.replace('@%s@' % m.group(1), d[m.group(1)]))
- else:
- ft.write(l)
- class build_src(build_ext.build_ext):
- description = "build sources from SWIG, F2PY files or a function"
- user_options = [
- ('build-src=', 'd', "directory to \"build\" sources to"),
- ('f2py-opts=', None, "list of f2py command line options"),
- ('swig=', None, "path to the SWIG executable"),
- ('swig-opts=', None, "list of SWIG command line options"),
- ('swig-cpp', None, "make SWIG create C++ files (default is autodetected from sources)"),
- ('f2pyflags=', None, "additional flags to f2py (use --f2py-opts= instead)"), # obsolete
- ('swigflags=', None, "additional flags to swig (use --swig-opts= instead)"), # obsolete
- ('force', 'f', "forcibly build everything (ignore file timestamps)"),
- ('inplace', 'i',
- "ignore build-lib and put compiled extensions into the source " +
- "directory alongside your pure Python modules"),
- ('verbose-cfg', None,
- "change logging level from WARN to INFO which will show all " +
- "compiler output")
- ]
- boolean_options = ['force', 'inplace', 'verbose-cfg']
- help_options = []
- def initialize_options(self):
- self.extensions = None
- self.package = None
- self.py_modules = None
- self.py_modules_dict = None
- self.build_src = None
- self.build_lib = None
- self.build_base = None
- self.force = None
- self.inplace = None
- self.package_dir = None
- self.f2pyflags = None # obsolete
- self.f2py_opts = None
- self.swigflags = None # obsolete
- self.swig_opts = None
- self.swig_cpp = None
- self.swig = None
- self.verbose_cfg = None
- def finalize_options(self):
- self.set_undefined_options('build',
- ('build_base', 'build_base'),
- ('build_lib', 'build_lib'),
- ('force', 'force'))
- if self.package is None:
- self.package = self.distribution.ext_package
- self.extensions = self.distribution.ext_modules
- self.libraries = self.distribution.libraries or []
- self.py_modules = self.distribution.py_modules or []
- self.data_files = self.distribution.data_files or []
- if self.build_src is None:
- plat_specifier = ".{}-{}.{}".format(get_platform(), *sys.version_info[:2])
- self.build_src = os.path.join(self.build_base, 'src'+plat_specifier)
- # py_modules_dict is used in build_py.find_package_modules
- self.py_modules_dict = {}
- if self.f2pyflags:
- if self.f2py_opts:
- log.warn('ignoring --f2pyflags as --f2py-opts already used')
- else:
- self.f2py_opts = self.f2pyflags
- self.f2pyflags = None
- if self.f2py_opts is None:
- self.f2py_opts = []
- else:
- self.f2py_opts = shlex.split(self.f2py_opts)
- if self.swigflags:
- if self.swig_opts:
- log.warn('ignoring --swigflags as --swig-opts already used')
- else:
- self.swig_opts = self.swigflags
- self.swigflags = None
- if self.swig_opts is None:
- self.swig_opts = []
- else:
- self.swig_opts = shlex.split(self.swig_opts)
- # use options from build_ext command
- build_ext = self.get_finalized_command('build_ext')
- if self.inplace is None:
- self.inplace = build_ext.inplace
- if self.swig_cpp is None:
- self.swig_cpp = build_ext.swig_cpp
- for c in ['swig', 'swig_opt']:
- o = '--'+c.replace('_', '-')
- v = getattr(build_ext, c, None)
- if v:
- if getattr(self, c):
- log.warn('both build_src and build_ext define %s option' % (o))
- else:
- log.info('using "%s=%s" option from build_ext command' % (o, v))
- setattr(self, c, v)
- def run(self):
- log.info("build_src")
- if not (self.extensions or self.libraries):
- return
- self.build_sources()
- def build_sources(self):
- if self.inplace:
- self.get_package_dir = \
- self.get_finalized_command('build_py').get_package_dir
- self.build_py_modules_sources()
- for libname_info in self.libraries:
- self.build_library_sources(*libname_info)
- if self.extensions:
- self.check_extensions_list(self.extensions)
- for ext in self.extensions:
- self.build_extension_sources(ext)
- self.build_data_files_sources()
- self.build_npy_pkg_config()
- def build_data_files_sources(self):
- if not self.data_files:
- return
- log.info('building data_files sources')
- from numpy.distutils.misc_util import get_data_files
- new_data_files = []
- for data in self.data_files:
- if isinstance(data, str):
- new_data_files.append(data)
- elif isinstance(data, tuple):
- d, files = data
- if self.inplace:
- build_dir = self.get_package_dir('.'.join(d.split(os.sep)))
- else:
- build_dir = os.path.join(self.build_src, d)
- funcs = [f for f in files if hasattr(f, '__call__')]
- files = [f for f in files if not hasattr(f, '__call__')]
- for f in funcs:
- if f.__code__.co_argcount==1:
- s = f(build_dir)
- else:
- s = f()
- if s is not None:
- if isinstance(s, list):
- files.extend(s)
- elif isinstance(s, str):
- files.append(s)
- else:
- raise TypeError(repr(s))
- filenames = get_data_files((d, files))
- new_data_files.append((d, filenames))
- else:
- raise TypeError(repr(data))
- self.data_files[:] = new_data_files
- def _build_npy_pkg_config(self, info, gd):
- template, install_dir, subst_dict = info
- template_dir = os.path.dirname(template)
- for k, v in gd.items():
- subst_dict[k] = v
- if self.inplace == 1:
- generated_dir = os.path.join(template_dir, install_dir)
- else:
- generated_dir = os.path.join(self.build_src, template_dir,
- install_dir)
- generated = os.path.basename(os.path.splitext(template)[0])
- generated_path = os.path.join(generated_dir, generated)
- if not os.path.exists(generated_dir):
- os.makedirs(generated_dir)
- subst_vars(generated_path, template, subst_dict)
- # Where to install relatively to install prefix
- full_install_dir = os.path.join(template_dir, install_dir)
- return full_install_dir, generated_path
- def build_npy_pkg_config(self):
- log.info('build_src: building npy-pkg config files')
- # XXX: another ugly workaround to circumvent distutils brain damage. We
- # need the install prefix here, but finalizing the options of the
- # install command when only building sources cause error. Instead, we
- # copy the install command instance, and finalize the copy so that it
- # does not disrupt how distutils want to do things when with the
- # original install command instance.
- install_cmd = copy.copy(get_cmd('install'))
- if not install_cmd.finalized == 1:
- install_cmd.finalize_options()
- build_npkg = False
- if self.inplace == 1:
- top_prefix = '.'
- build_npkg = True
- elif hasattr(install_cmd, 'install_libbase'):
- top_prefix = install_cmd.install_libbase
- build_npkg = True
- if build_npkg:
- for pkg, infos in self.distribution.installed_pkg_config.items():
- pkg_path = self.distribution.package_dir[pkg]
- prefix = os.path.join(os.path.abspath(top_prefix), pkg_path)
- d = {'prefix': prefix}
- for info in infos:
- install_dir, generated = self._build_npy_pkg_config(info, d)
- self.distribution.data_files.append((install_dir,
- [generated]))
- def build_py_modules_sources(self):
- if not self.py_modules:
- return
- log.info('building py_modules sources')
- new_py_modules = []
- for source in self.py_modules:
- if is_sequence(source) and len(source)==3:
- package, module_base, source = source
- if self.inplace:
- build_dir = self.get_package_dir(package)
- else:
- build_dir = os.path.join(self.build_src,
- os.path.join(*package.split('.')))
- if hasattr(source, '__call__'):
- target = os.path.join(build_dir, module_base + '.py')
- source = source(target)
- if source is None:
- continue
- modules = [(package, module_base, source)]
- if package not in self.py_modules_dict:
- self.py_modules_dict[package] = []
- self.py_modules_dict[package] += modules
- else:
- new_py_modules.append(source)
- self.py_modules[:] = new_py_modules
- def build_library_sources(self, lib_name, build_info):
- sources = list(build_info.get('sources', []))
- if not sources:
- return
- log.info('building library "%s" sources' % (lib_name))
- sources = self.generate_sources(sources, (lib_name, build_info))
- sources = self.template_sources(sources, (lib_name, build_info))
- sources, h_files = self.filter_h_files(sources)
- if h_files:
- log.info('%s - nothing done with h_files = %s',
- self.package, h_files)
- #for f in h_files:
- # self.distribution.headers.append((lib_name,f))
- build_info['sources'] = sources
- return
- def build_extension_sources(self, ext):
- sources = list(ext.sources)
- log.info('building extension "%s" sources' % (ext.name))
- fullname = self.get_ext_fullname(ext.name)
- modpath = fullname.split('.')
- package = '.'.join(modpath[0:-1])
- if self.inplace:
- self.ext_target_dir = self.get_package_dir(package)
- sources = self.generate_sources(sources, ext)
- sources = self.template_sources(sources, ext)
- sources = self.swig_sources(sources, ext)
- sources = self.f2py_sources(sources, ext)
- sources = self.pyrex_sources(sources, ext)
- sources, py_files = self.filter_py_files(sources)
- if package not in self.py_modules_dict:
- self.py_modules_dict[package] = []
- modules = []
- for f in py_files:
- module = os.path.splitext(os.path.basename(f))[0]
- modules.append((package, module, f))
- self.py_modules_dict[package] += modules
- sources, h_files = self.filter_h_files(sources)
- if h_files:
- log.info('%s - nothing done with h_files = %s',
- package, h_files)
- #for f in h_files:
- # self.distribution.headers.append((package,f))
- ext.sources = sources
- def generate_sources(self, sources, extension):
- new_sources = []
- func_sources = []
- for source in sources:
- if is_string(source):
- new_sources.append(source)
- else:
- func_sources.append(source)
- if not func_sources:
- return new_sources
- if self.inplace and not is_sequence(extension):
- build_dir = self.ext_target_dir
- else:
- if is_sequence(extension):
- name = extension[0]
- # if 'include_dirs' not in extension[1]:
- # extension[1]['include_dirs'] = []
- # incl_dirs = extension[1]['include_dirs']
- else:
- name = extension.name
- # incl_dirs = extension.include_dirs
- #if self.build_src not in incl_dirs:
- # incl_dirs.append(self.build_src)
- build_dir = os.path.join(*([self.build_src]
- +name.split('.')[:-1]))
- self.mkpath(build_dir)
- if self.verbose_cfg:
- new_level = log.INFO
- else:
- new_level = log.WARN
- old_level = log.set_threshold(new_level)
- for func in func_sources:
- source = func(extension, build_dir)
- if not source:
- continue
- if is_sequence(source):
- [log.info(" adding '%s' to sources." % (s,)) for s in source]
- new_sources.extend(source)
- else:
- log.info(" adding '%s' to sources." % (source,))
- new_sources.append(source)
- log.set_threshold(old_level)
- return new_sources
- def filter_py_files(self, sources):
- return self.filter_files(sources, ['.py'])
- def filter_h_files(self, sources):
- return self.filter_files(sources, ['.h', '.hpp', '.inc'])
- def filter_files(self, sources, exts = []):
- new_sources = []
- files = []
- for source in sources:
- (base, ext) = os.path.splitext(source)
- if ext in exts:
- files.append(source)
- else:
- new_sources.append(source)
- return new_sources, files
- def template_sources(self, sources, extension):
- new_sources = []
- if is_sequence(extension):
- depends = extension[1].get('depends')
- include_dirs = extension[1].get('include_dirs')
- else:
- depends = extension.depends
- include_dirs = extension.include_dirs
- for source in sources:
- (base, ext) = os.path.splitext(source)
- if ext == '.src': # Template file
- if self.inplace:
- target_dir = os.path.dirname(base)
- else:
- target_dir = appendpath(self.build_src, os.path.dirname(base))
- self.mkpath(target_dir)
- target_file = os.path.join(target_dir, os.path.basename(base))
- if (self.force or newer_group([source] + depends, target_file)):
- if _f_pyf_ext_match(base):
- log.info("from_template:> %s" % (target_file))
- outstr = process_f_file(source)
- else:
- log.info("conv_template:> %s" % (target_file))
- outstr = process_c_file(source)
- with open(target_file, 'w') as fid:
- fid.write(outstr)
- if _header_ext_match(target_file):
- d = os.path.dirname(target_file)
- if d not in include_dirs:
- log.info(" adding '%s' to include_dirs." % (d))
- include_dirs.append(d)
- new_sources.append(target_file)
- else:
- new_sources.append(source)
- return new_sources
- def pyrex_sources(self, sources, extension):
- """Pyrex not supported; this remains for Cython support (see below)"""
- new_sources = []
- ext_name = extension.name.split('.')[-1]
- for source in sources:
- (base, ext) = os.path.splitext(source)
- if ext == '.pyx':
- target_file = self.generate_a_pyrex_source(base, ext_name,
- source,
- extension)
- new_sources.append(target_file)
- else:
- new_sources.append(source)
- return new_sources
- def generate_a_pyrex_source(self, base, ext_name, source, extension):
- """Pyrex is not supported, but some projects monkeypatch this method.
- That allows compiling Cython code, see gh-6955.
- This method will remain here for compatibility reasons.
- """
- return []
- def f2py_sources(self, sources, extension):
- new_sources = []
- f2py_sources = []
- f_sources = []
- f2py_targets = {}
- target_dirs = []
- ext_name = extension.name.split('.')[-1]
- skip_f2py = 0
- for source in sources:
- (base, ext) = os.path.splitext(source)
- if ext == '.pyf': # F2PY interface file
- if self.inplace:
- target_dir = os.path.dirname(base)
- else:
- target_dir = appendpath(self.build_src, os.path.dirname(base))
- if os.path.isfile(source):
- name = get_f2py_modulename(source)
- if name != ext_name:
- raise DistutilsSetupError('mismatch of extension names: %s '
- 'provides %r but expected %r' % (
- source, name, ext_name))
- target_file = os.path.join(target_dir, name+'module.c')
- else:
- log.debug(' source %s does not exist: skipping f2py\'ing.' \
- % (source))
- name = ext_name
- skip_f2py = 1
- target_file = os.path.join(target_dir, name+'module.c')
- if not os.path.isfile(target_file):
- log.warn(' target %s does not exist:\n '\
- 'Assuming %smodule.c was generated with '\
- '"build_src --inplace" command.' \
- % (target_file, name))
- target_dir = os.path.dirname(base)
- target_file = os.path.join(target_dir, name+'module.c')
- if not os.path.isfile(target_file):
- raise DistutilsSetupError("%r missing" % (target_file,))
- log.info(' Yes! Using %r as up-to-date target.' \
- % (target_file))
- target_dirs.append(target_dir)
- f2py_sources.append(source)
- f2py_targets[source] = target_file
- new_sources.append(target_file)
- elif fortran_ext_match(ext):
- f_sources.append(source)
- else:
- new_sources.append(source)
- if not (f2py_sources or f_sources):
- return new_sources
- for d in target_dirs:
- self.mkpath(d)
- f2py_options = extension.f2py_options + self.f2py_opts
- if self.distribution.libraries:
- for name, build_info in self.distribution.libraries:
- if name in extension.libraries:
- f2py_options.extend(build_info.get('f2py_options', []))
- log.info("f2py options: %s" % (f2py_options))
- if f2py_sources:
- if len(f2py_sources) != 1:
- raise DistutilsSetupError(
- 'only one .pyf file is allowed per extension module but got'\
- ' more: %r' % (f2py_sources,))
- source = f2py_sources[0]
- target_file = f2py_targets[source]
- target_dir = os.path.dirname(target_file) or '.'
- depends = [source] + extension.depends
- if (self.force or newer_group(depends, target_file, 'newer')) \
- and not skip_f2py:
- log.info("f2py: %s" % (source))
- import numpy.f2py
- numpy.f2py.run_main(f2py_options
- + ['--build-dir', target_dir, source])
- else:
- log.debug(" skipping '%s' f2py interface (up-to-date)" % (source))
- else:
- #XXX TODO: --inplace support for sdist command
- if is_sequence(extension):
- name = extension[0]
- else: name = extension.name
- target_dir = os.path.join(*([self.build_src]
- +name.split('.')[:-1]))
- target_file = os.path.join(target_dir, ext_name + 'module.c')
- new_sources.append(target_file)
- depends = f_sources + extension.depends
- if (self.force or newer_group(depends, target_file, 'newer')) \
- and not skip_f2py:
- log.info("f2py:> %s" % (target_file))
- self.mkpath(target_dir)
- import numpy.f2py
- numpy.f2py.run_main(f2py_options + ['--lower',
- '--build-dir', target_dir]+\
- ['-m', ext_name]+f_sources)
- else:
- log.debug(" skipping f2py fortran files for '%s' (up-to-date)"\
- % (target_file))
- if not os.path.isfile(target_file):
- raise DistutilsError("f2py target file %r not generated" % (target_file,))
- build_dir = os.path.join(self.build_src, target_dir)
- target_c = os.path.join(build_dir, 'fortranobject.c')
- target_h = os.path.join(build_dir, 'fortranobject.h')
- log.info(" adding '%s' to sources." % (target_c))
- new_sources.append(target_c)
- if build_dir not in extension.include_dirs:
- log.info(" adding '%s' to include_dirs." % (build_dir))
- extension.include_dirs.append(build_dir)
- if not skip_f2py:
- import numpy.f2py
- d = os.path.dirname(numpy.f2py.__file__)
- source_c = os.path.join(d, 'src', 'fortranobject.c')
- source_h = os.path.join(d, 'src', 'fortranobject.h')
- if newer(source_c, target_c) or newer(source_h, target_h):
- self.mkpath(os.path.dirname(target_c))
- self.copy_file(source_c, target_c)
- self.copy_file(source_h, target_h)
- else:
- if not os.path.isfile(target_c):
- raise DistutilsSetupError("f2py target_c file %r not found" % (target_c,))
- if not os.path.isfile(target_h):
- raise DistutilsSetupError("f2py target_h file %r not found" % (target_h,))
- for name_ext in ['-f2pywrappers.f', '-f2pywrappers2.f90']:
- filename = os.path.join(target_dir, ext_name + name_ext)
- if os.path.isfile(filename):
- log.info(" adding '%s' to sources." % (filename))
- f_sources.append(filename)
- return new_sources + f_sources
- def swig_sources(self, sources, extension):
- # Assuming SWIG 1.3.14 or later. See compatibility note in
- # http://www.swig.org/Doc1.3/Python.html#Python_nn6
- new_sources = []
- swig_sources = []
- swig_targets = {}
- target_dirs = []
- py_files = [] # swig generated .py files
- target_ext = '.c'
- if '-c++' in extension.swig_opts:
- typ = 'c++'
- is_cpp = True
- extension.swig_opts.remove('-c++')
- elif self.swig_cpp:
- typ = 'c++'
- is_cpp = True
- else:
- typ = None
- is_cpp = False
- skip_swig = 0
- ext_name = extension.name.split('.')[-1]
- for source in sources:
- (base, ext) = os.path.splitext(source)
- if ext == '.i': # SWIG interface file
- # the code below assumes that the sources list
- # contains not more than one .i SWIG interface file
- if self.inplace:
- target_dir = os.path.dirname(base)
- py_target_dir = self.ext_target_dir
- else:
- target_dir = appendpath(self.build_src, os.path.dirname(base))
- py_target_dir = target_dir
- if os.path.isfile(source):
- name = get_swig_modulename(source)
- if name != ext_name[1:]:
- raise DistutilsSetupError(
- 'mismatch of extension names: %s provides %r'
- ' but expected %r' % (source, name, ext_name[1:]))
- if typ is None:
- typ = get_swig_target(source)
- is_cpp = typ=='c++'
- else:
- typ2 = get_swig_target(source)
- if typ2 is None:
- log.warn('source %r does not define swig target, assuming %s swig target' \
- % (source, typ))
- elif typ!=typ2:
- log.warn('expected %r but source %r defines %r swig target' \
- % (typ, source, typ2))
- if typ2=='c++':
- log.warn('resetting swig target to c++ (some targets may have .c extension)')
- is_cpp = True
- else:
- log.warn('assuming that %r has c++ swig target' % (source))
- if is_cpp:
- target_ext = '.cpp'
- target_file = os.path.join(target_dir, '%s_wrap%s' \
- % (name, target_ext))
- else:
- log.warn(' source %s does not exist: skipping swig\'ing.' \
- % (source))
- name = ext_name[1:]
- skip_swig = 1
- target_file = _find_swig_target(target_dir, name)
- if not os.path.isfile(target_file):
- log.warn(' target %s does not exist:\n '\
- 'Assuming %s_wrap.{c,cpp} was generated with '\
- '"build_src --inplace" command.' \
- % (target_file, name))
- target_dir = os.path.dirname(base)
- target_file = _find_swig_target(target_dir, name)
- if not os.path.isfile(target_file):
- raise DistutilsSetupError("%r missing" % (target_file,))
- log.warn(' Yes! Using %r as up-to-date target.' \
- % (target_file))
- target_dirs.append(target_dir)
- new_sources.append(target_file)
- py_files.append(os.path.join(py_target_dir, name+'.py'))
- swig_sources.append(source)
- swig_targets[source] = new_sources[-1]
- else:
- new_sources.append(source)
- if not swig_sources:
- return new_sources
- if skip_swig:
- return new_sources + py_files
- for d in target_dirs:
- self.mkpath(d)
- swig = self.swig or self.find_swig()
- swig_cmd = [swig, "-python"] + extension.swig_opts
- if is_cpp:
- swig_cmd.append('-c++')
- for d in extension.include_dirs:
- swig_cmd.append('-I'+d)
- for source in swig_sources:
- target = swig_targets[source]
- depends = [source] + extension.depends
- if self.force or newer_group(depends, target, 'newer'):
- log.info("%s: %s" % (os.path.basename(swig) \
- + (is_cpp and '++' or ''), source))
- self.spawn(swig_cmd + self.swig_opts \
- + ["-o", target, '-outdir', py_target_dir, source])
- else:
- log.debug(" skipping '%s' swig interface (up-to-date)" \
- % (source))
- return new_sources + py_files
- _f_pyf_ext_match = re.compile(r'.*\.(f90|f95|f77|for|ftn|f|pyf)\Z', re.I).match
- _header_ext_match = re.compile(r'.*\.(inc|h|hpp)\Z', re.I).match
- #### SWIG related auxiliary functions ####
- _swig_module_name_match = re.compile(r'\s*%module\s*(.*\(\s*package\s*=\s*"(?P<package>[\w_]+)".*\)|)\s*(?P<name>[\w_]+)',
- re.I).match
- _has_c_header = re.compile(r'-\*-\s*c\s*-\*-', re.I).search
- _has_cpp_header = re.compile(r'-\*-\s*c\+\+\s*-\*-', re.I).search
- def get_swig_target(source):
- with open(source, 'r') as f:
- result = None
- line = f.readline()
- if _has_cpp_header(line):
- result = 'c++'
- if _has_c_header(line):
- result = 'c'
- return result
- def get_swig_modulename(source):
- with open(source, 'r') as f:
- name = None
- for line in f:
- m = _swig_module_name_match(line)
- if m:
- name = m.group('name')
- break
- return name
- def _find_swig_target(target_dir, name):
- for ext in ['.cpp', '.c']:
- target = os.path.join(target_dir, '%s_wrap%s' % (name, ext))
- if os.path.isfile(target):
- break
- return target
- #### F2PY related auxiliary functions ####
- _f2py_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]+)',
- re.I).match
- _f2py_user_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]*?'
- r'__user__[\w_]*)', re.I).match
- def get_f2py_modulename(source):
- name = None
- with open(source) as f:
- for line in f:
- m = _f2py_module_name_match(line)
- if m:
- if _f2py_user_module_name_match(line): # skip *__user__* names
- continue
- name = m.group('name')
- break
- return name
- ##########################################
|