| """Build a Pyrex file from .pyx source to .so loadable module using
|
| the installed distutils infrastructure. Call:
|
|
|
| out_fname = pyx_to_dll("foo.pyx")
|
| """
|
| import os
|
| import sys
|
|
|
| from distutils.errors import DistutilsArgError, DistutilsError, CCompilerError
|
| from distutils.extension import Extension
|
| from distutils.util import grok_environment_error
|
| try:
|
| from Cython.Distutils.build_ext import build_ext
|
| HAS_CYTHON = True
|
| except ImportError:
|
| HAS_CYTHON = False
|
|
|
| DEBUG = 0
|
|
|
| _reloads={}
|
|
|
|
|
| def pyx_to_dll(filename, ext=None, force_rebuild=0, build_in_temp=False, pyxbuild_dir=None,
|
| setup_args=None, reload_support=False, inplace=False):
|
| """Compile a PYX file to a DLL and return the name of the generated .so
|
| or .dll ."""
|
| assert os.path.exists(filename), "Could not find %s" % os.path.abspath(filename)
|
|
|
| path, name = os.path.split(os.path.abspath(filename))
|
|
|
| if not ext:
|
| modname, extension = os.path.splitext(name)
|
| assert extension in (".pyx", ".py"), extension
|
| if not HAS_CYTHON:
|
| filename = filename[:-len(extension)] + '.c'
|
| ext = Extension(name=modname, sources=[filename])
|
|
|
| if setup_args is None:
|
| setup_args = {}
|
| if not pyxbuild_dir:
|
| pyxbuild_dir = os.path.join(path, "_pyxbld")
|
|
|
| package_base_dir = path
|
| for package_name in ext.name.split('.')[-2::-1]:
|
| package_base_dir, pname = os.path.split(package_base_dir)
|
| if pname != package_name:
|
|
|
| package_base_dir = None
|
| break
|
|
|
| script_args=setup_args.get("script_args",[])
|
| if DEBUG or "--verbose" in script_args:
|
| quiet = "--verbose"
|
| else:
|
| quiet = "--quiet"
|
| if build_in_temp:
|
| args = [quiet, "build_ext", '--cython-c-in-temp']
|
| else:
|
| args = [quiet, "build_ext"]
|
| if force_rebuild:
|
| args.append("--force")
|
| if inplace and package_base_dir:
|
| args.extend(['--build-lib', package_base_dir])
|
| if ext.name == '__init__' or ext.name.endswith('.__init__'):
|
|
|
| if not hasattr(ext, 'cython_directives'):
|
| ext.cython_directives = {'set_initial_path' : 'SOURCEFILE'}
|
| elif 'set_initial_path' not in ext.cython_directives:
|
| ext.cython_directives['set_initial_path'] = 'SOURCEFILE'
|
|
|
| sargs = setup_args.copy()
|
| sargs.update({
|
| "script_name": None,
|
| "script_args": args + script_args,
|
| })
|
|
|
| from distutils.dist import Distribution
|
| dist = Distribution(sargs)
|
| if not dist.ext_modules:
|
| dist.ext_modules = []
|
| dist.ext_modules.append(ext)
|
| if HAS_CYTHON:
|
| dist.cmdclass = {'build_ext': build_ext}
|
| build = dist.get_command_obj('build')
|
| build.build_base = pyxbuild_dir
|
|
|
| cfgfiles = dist.find_config_files()
|
| dist.parse_config_files(cfgfiles)
|
|
|
| try:
|
| ok = dist.parse_command_line()
|
| except DistutilsArgError:
|
| raise
|
|
|
| if DEBUG:
|
| print("options (after parsing command line):")
|
| dist.dump_option_dicts()
|
| assert ok
|
|
|
|
|
| try:
|
| obj_build_ext = dist.get_command_obj("build_ext")
|
| dist.run_commands()
|
| so_path = obj_build_ext.get_outputs()[0]
|
| if obj_build_ext.inplace:
|
|
|
|
|
|
|
| so_path = os.path.join(os.path.dirname(filename),
|
| os.path.basename(so_path))
|
| if reload_support:
|
| org_path = so_path
|
| timestamp = os.path.getmtime(org_path)
|
| global _reloads
|
| last_timestamp, last_path, count = _reloads.get(org_path, (None,None,0) )
|
| if last_timestamp == timestamp:
|
| so_path = last_path
|
| else:
|
| basename = os.path.basename(org_path)
|
| while count < 100:
|
| count += 1
|
| r_path = os.path.join(obj_build_ext.build_lib,
|
| basename + '.reload%s' % count)
|
| try:
|
| import shutil
|
| try:
|
|
|
|
|
|
|
|
|
|
|
|
|
| if os.path.isfile(r_path):
|
| os.unlink(r_path)
|
| except OSError:
|
| continue
|
| shutil.copy2(org_path, r_path)
|
| so_path = r_path
|
| except IOError:
|
| continue
|
| break
|
| else:
|
|
|
| raise ImportError("reload count for %s reached maximum" % org_path)
|
| _reloads[org_path]=(timestamp, so_path, count)
|
| return so_path
|
| except KeyboardInterrupt:
|
| sys.exit(1)
|
| except (IOError, os.error):
|
| exc = sys.exc_info()[1]
|
| error = grok_environment_error(exc)
|
|
|
| if DEBUG:
|
| sys.stderr.write(error + "\n")
|
| raise
|
|
|
|
|
| if __name__=="__main__":
|
| pyx_to_dll("dummy.pyx")
|
| from . import test
|
|
|