Commit 68811fa9 authored by Stefan Behnel's avatar Stefan Behnel

support in-place building for pyximport

parent a4e6c41f
......@@ -21,7 +21,8 @@ DEBUG = 0
_reloads={}
def pyx_to_dll(filename, ext = None, force_rebuild = 0,
build_in_temp=False, pyxbuild_dir=None, setup_args={}, reload_support=False):
build_in_temp=False, pyxbuild_dir=None, setup_args={},
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)
......@@ -82,10 +83,16 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0,
try:
dist.run_commands()
obj_build_ext = dist.get_command_obj("build_ext")
orig_inplace = obj_build_ext.inplace
if inplace:
obj_build_ext.inplace = True
try:
dist.run_commands()
finally:
obj_build_ext.inplace = orig_inplace
so_path = obj_build_ext.get_outputs()[0]
if obj_build_ext.inplace:
if orig_inplace or inplace:
# Python distutils get_outputs()[ returns a wrong so_path
# when --inplace ; see http://bugs.python.org/issue5977
# workaround:
......
......@@ -160,7 +160,7 @@ def handle_dependencies(pyxfilename):
if testing:
_test_files.append(file)
def build_module(name, pyxfilename, pyxbuild_dir=None):
def build_module(name, pyxfilename, pyxbuild_dir=None, inplace=False):
assert os.path.exists(pyxfilename), (
"Path does not exist: %s" % pyxfilename)
handle_dependencies(pyxfilename)
......@@ -176,6 +176,7 @@ def build_module(name, pyxfilename, pyxbuild_dir=None):
build_in_temp=build_in_temp,
pyxbuild_dir=pyxbuild_dir,
setup_args=sargs,
inplace=inplace,
reload_support=pyxargs.reload_support)
assert os.path.exists(so_path), "Cannot find: %s" % so_path
......@@ -190,13 +191,13 @@ def build_module(name, pyxfilename, pyxbuild_dir=None):
return so_path
def load_module(name, pyxfilename, pyxbuild_dir=None, is_package=False):
def load_module(name, pyxfilename, pyxbuild_dir=None, is_package=False, build_inplace=False):
try:
if is_package:
module_name = name + '.__init__'
else:
module_name = name
so_path = build_module(module_name, pyxfilename, pyxbuild_dir)
so_path = build_module(module_name, pyxfilename, pyxbuild_dir, inplace=build_inplace)
mod = imp.load_dynamic(name, so_path)
assert mod.__file__ == so_path, (mod.__file__, so_path)
except Exception:
......@@ -217,9 +218,10 @@ def load_module(name, pyxfilename, pyxbuild_dir=None, is_package=False):
class PyxImporter(object):
"""A meta-path importer for .pyx files.
"""
def __init__(self, extension=PYX_EXT, pyxbuild_dir=None):
def __init__(self, extension=PYX_EXT, pyxbuild_dir=None, inplace=False):
self.extension = extension
self.pyxbuild_dir = pyxbuild_dir
self.inplace = inplace
def find_module(self, fullname, package_path=None):
if fullname in sys.modules and not pyxargs.reload_support:
......@@ -232,10 +234,12 @@ class PyxImporter(object):
if os.path.isfile(pkg_file):
return PyxLoader(fullname, pathname,
init_path=pkg_file,
pyxbuild_dir=self.pyxbuild_dir)
pyxbuild_dir=self.pyxbuild_dir,
inplace=self.inplace)
if pathname and pathname.endswith(self.extension):
return PyxLoader(fullname, pathname,
pyxbuild_dir=self.pyxbuild_dir)
pyxbuild_dir=self.pyxbuild_dir,
inplace=self.inplace)
if ty != imp.C_EXTENSION: # only when an extension, check if we have a .pyx next!
return None
......@@ -243,7 +247,8 @@ class PyxImporter(object):
pyxpath = os.path.splitext(pathname)[0]+self.extension
if os.path.isfile(pyxpath):
return PyxLoader(fullname, pyxpath,
pyxbuild_dir=self.pyxbuild_dir)
pyxbuild_dir=self.pyxbuild_dir,
inplace=self.inplace)
# .so/.pyd's on PATH should not be remote from .pyx's
# think no need to implement PyxArgs.importer_search_remote here?
......@@ -277,7 +282,8 @@ class PyxImporter(object):
path = os.getcwd()
if is_file(path+sep+pyx_module_name):
return PyxLoader(fullname, join_path(path, pyx_module_name),
pyxbuild_dir=self.pyxbuild_dir)
pyxbuild_dir=self.pyxbuild_dir,
inplace=self.inplace)
# not found, normal package, not a .pyx file, none of our business
_debug("%s not found" % fullname)
......@@ -286,9 +292,9 @@ class PyxImporter(object):
class PyImporter(PyxImporter):
"""A meta-path importer for normal .py files.
"""
def __init__(self, pyxbuild_dir=None):
def __init__(self, pyxbuild_dir=None, inplace=False):
self.super = super(PyImporter, self)
self.super.__init__(extension='.py', pyxbuild_dir=pyxbuild_dir)
self.super.__init__(extension='.py', pyxbuild_dir=pyxbuild_dir, inplace=inplace)
self.uncompilable_modules = {}
self.blocked_modules = ['Cython', 'distutils.extension',
'distutils.sysconfig']
......@@ -326,7 +332,8 @@ class PyImporter(PyxImporter):
real_name = fullname
_debug("importer found path %s for module %s", path, real_name)
build_module(real_name, path,
pyxbuild_dir=self.pyxbuild_dir)
pyxbuild_dir=self.pyxbuild_dir,
inplace=self.inplace)
except Exception, e:
if DEBUG_IMPORT:
import traceback
......@@ -343,11 +350,12 @@ class PyImporter(PyxImporter):
return importer
class PyxLoader(object):
def __init__(self, fullname, path, init_path=None, pyxbuild_dir=None):
def __init__(self, fullname, path, init_path=None, pyxbuild_dir=None, inplace=False):
_debug("PyxLoader created for loading %s from %s (init path: %s)", fullname, path, init_path)
self.fullname = fullname
self.path, self.init_path = path, init_path
self.pyxbuild_dir = pyxbuild_dir
self.inplace=inplace
def load_module(self, fullname):
assert self.fullname == fullname, (
......@@ -357,12 +365,14 @@ class PyxLoader(object):
# package
#print "PACKAGE", fullname
module = load_module(fullname, self.init_path,
self.pyxbuild_dir, is_package=True)
self.pyxbuild_dir, is_package=True,
build_inplace=self.inplace)
module.__path__ = [self.path]
else:
#print "MODULE", fullname
module = load_module(fullname, self.path,
self.pyxbuild_dir)
self.pyxbuild_dir,
build_inplace=self.inplace)
return module
......@@ -388,7 +398,7 @@ def _have_importers():
def install(pyximport=True, pyimport=False, build_dir=None, build_in_temp=True,
setup_args={}, reload_support=False,
load_py_module_on_import_failure=False):
load_py_module_on_import_failure=False, inplace=False):
"""Main entry point. Call this to install the .pyx import hook in
your meta-path for a single Python process. If you want it to be
installed whenever you use Python, add it to your sitecustomize
......@@ -426,6 +436,8 @@ def install(pyximport=True, pyimport=False, build_dir=None, build_in_temp=True,
the second import will rerun these modifications in whatever state
the system was left after the import of the compiled module
failed.
``inplace``: Install the compiled module next to the source file.
"""
if not build_dir:
build_dir = os.path.expanduser('~/.pyxbld')
......@@ -442,11 +454,13 @@ def install(pyximport=True, pyimport=False, build_dir=None, build_in_temp=True,
py_importer, pyx_importer = None, None
if pyimport and not has_py_importer:
py_importer = PyImporter(pyxbuild_dir=build_dir)
py_importer = PyImporter(pyxbuild_dir=build_dir, inplace=inplace)
# make sure we import Cython before we install the import hook
import pyxbuild, Cython.Compiler.Main, Cython.Compiler.Pipeline, Cython.Compiler.Optimize
sys.meta_path.insert(0, py_importer)
if pyximport and not has_pyx_importer:
pyx_importer = PyxImporter(pyxbuild_dir=build_dir)
pyx_importer = PyxImporter(pyxbuild_dir=build_dir, inplace=inplace)
sys.meta_path.append(pyx_importer)
return py_importer, pyx_importer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment