[pypy-commit] cffi default: Trying a different hack: stop patching SO and EXT_SUFFIX in
arigo
pypy.commits at gmail.com
Sat Jan 16 05:13:45 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r2592:9be92594ef14
Date: 2016-01-16 11:13 +0100
http://bitbucket.org/cffi/cffi/changeset/9be92594ef14/
Log: Trying a different hack: stop patching SO and EXT_SUFFIX in
sysconfigdata, and instead patch directly a method in
distutils.command.build_ext. Motivation: Windows, where the previous
solution makes it add the wrong 'init...' in exports_symbols
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -21,14 +21,12 @@
allsources.append(os.path.normpath(src))
return Extension(name=modname, sources=allsources, **kwds)
-def compile(tmpdir, ext, compiler_verbose=0, target_extension=None,
- embedding=False):
+def compile(tmpdir, ext, compiler_verbose=0):
"""Compile a C extension module using distutils."""
saved_environ = os.environ.copy()
try:
- outputfilename = _build(tmpdir, ext, compiler_verbose,
- target_extension, embedding)
+ outputfilename = _build(tmpdir, ext, compiler_verbose)
outputfilename = os.path.abspath(outputfilename)
finally:
# workaround for a distutils bugs where some env vars can
@@ -38,32 +36,7 @@
os.environ[key] = value
return outputfilename
-def _save_val(name):
- import distutils.sysconfig
- config_vars = distutils.sysconfig.get_config_vars()
- return config_vars.get(name, Ellipsis)
-
-def _restore_val(name, value):
- import distutils.sysconfig
- config_vars = distutils.sysconfig.get_config_vars()
- config_vars[name] = value
- if value is Ellipsis:
- del config_vars[name]
-
-def _win32_hack_for_embedding():
- from distutils.msvc9compiler import MSVCCompiler
- if not hasattr(MSVCCompiler, '_remove_visual_c_ref_CFFI_BAK'):
- MSVCCompiler._remove_visual_c_ref_CFFI_BAK = \
- MSVCCompiler._remove_visual_c_ref
- MSVCCompiler._remove_visual_c_ref = lambda self,manifest_file: manifest_file
-
-def _win32_unhack_for_embedding():
- from distutils.msvc9compiler import MSVCCompiler
- MSVCCompiler._remove_visual_c_ref = \
- MSVCCompiler._remove_visual_c_ref_CFFI_BAK
-
-def _build(tmpdir, ext, compiler_verbose=0, target_extension=None,
- embedding=False):
+def _build(tmpdir, ext, compiler_verbose=0):
# XXX compact but horrible :-(
from distutils.core import Distribution
import distutils.errors, distutils.log
@@ -76,25 +49,14 @@
options['build_temp'] = ('ffiplatform', tmpdir)
#
try:
- if sys.platform == 'win32' and embedding:
- _win32_hack_for_embedding()
old_level = distutils.log.set_threshold(0) or 0
- old_SO = _save_val('SO')
- old_EXT_SUFFIX = _save_val('EXT_SUFFIX')
try:
- if target_extension is not None:
- _restore_val('SO', target_extension)
- _restore_val('EXT_SUFFIX', target_extension)
distutils.log.set_verbosity(compiler_verbose)
dist.run_command('build_ext')
cmd_obj = dist.get_command_obj('build_ext')
[soname] = cmd_obj.get_outputs()
finally:
distutils.log.set_threshold(old_level)
- _restore_val('SO', old_SO)
- _restore_val('EXT_SUFFIX', old_EXT_SUFFIX)
- if sys.platform == 'win32' and embedding:
- _win32_unhack_for_embedding()
except (distutils.errors.CompileError,
distutils.errors.LinkError) as e:
raise VerificationError('%s: %s' % (e.__class__.__name__, e))
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -1357,6 +1357,40 @@
parts[-1] += extension
return os.path.join(outputdir, *parts), parts
+
+# Aaargh. Distutils is not tested at all for the purpose of compiling
+# DLLs that are not extension modules. Here are some hacks to work
+# around that, in the _patch_for_*() functions...
+
+def _patch_meth(patchlist, cls, name, new_meth):
+ patchlist.append((cls, name, getattr(cls, name)))
+ setattr(cls, name, new_meth)
+
+def _unpatch_meths(patchlist):
+ for cls, name, old_meth in reversed(patchlist):
+ setattr(cls, name, old_meth)
+
+def _patch_for_embedding_win32(patchlist):
+ from distutils.msvc9compiler import MSVCCompiler
+ # we must not remove the manifest when building for embedding!
+ _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
+ lambda self, manifest_file: manifest_file)
+
+def _patch_for_target(patchlist, target):
+ from distutils.command.build_ext import build_ext
+ # if 'target' is different from '*', we need to patch some internal
+ # method to just return this 'target' value, instead of having it
+ # built from module_name
+ if target.endswith('.*'):
+ target = target[:-2]
+ if sys.platform == 'win32':
+ target += '.dll'
+ else:
+ target += '.so'
+ _patch_meth(patchlist, build_ext, 'get_ext_filename',
+ lambda self, ext_name: target)
+
+
def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
c_file=None, source_extension='.c', extradir=None,
compiler_verbose=1, target=None, **kwds):
@@ -1382,36 +1416,22 @@
target = '%s.*' % module_name
else:
target = '*'
- if target == '*':
- target_module_name = module_name
- target_extension = None # use default
- else:
- if target.endswith('.*'):
- target = target[:-2]
- if sys.platform == 'win32':
- target += '.dll'
- else:
- target += '.so'
- # split along the first '.' (not the last one, otherwise the
- # preceeding dots are interpreted as splitting package names)
- index = target.find('.')
- if index < 0:
- raise ValueError("target argument %r should be a file name "
- "containing a '.'" % (target,))
- target_module_name = target[:index]
- target_extension = target[index:]
#
- ext = ffiplatform.get_extension(ext_c_file, target_module_name, **kwds)
+ ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
updated = make_c_source(ffi, module_name, preamble, c_file)
if call_c_compiler:
+ patchlist = []
cwd = os.getcwd()
try:
+ if embedding and sys.platform == 'win32':
+ _patch_for_embedding_win32(patchlist)
+ if target != '*':
+ _patch_for_target(patchlist, target)
os.chdir(tmpdir)
- outputfilename = ffiplatform.compile('.', ext, compiler_verbose,
- target_extension,
- embedding=embedding)
+ outputfilename = ffiplatform.compile('.', ext, compiler_verbose)
finally:
os.chdir(cwd)
+ _unpatch_meths(patchlist)
return outputfilename
else:
return ext, updated
diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py
--- a/testing/cffi1/test_zdist.py
+++ b/testing/cffi1/test_zdist.py
@@ -219,23 +219,6 @@
x = ffi.compile(target="foo.bar.*")
if sys.platform != 'win32':
sofile = self.check_produced_files({
- 'foo.bar.SO': None,
- 'mod_name_in_package': {'mymod.c': None,
- 'mymod.o': None}})
- assert os.path.isabs(x) and os.path.samefile(x, sofile)
- else:
- self.check_produced_files({
- 'foo.bar.SO': None,
- 'mod_name_in_package': {'mymod.c': None},
- 'Release': '?'})
-
- @chdir_to_tmp
- def test_api_compile_explicit_target_2(self):
- ffi = cffi.FFI()
- ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
- x = ffi.compile(target=os.path.join("mod_name_in_package", "foo.bar.*"))
- if sys.platform != 'win32':
- sofile = self.check_produced_files({
'mod_name_in_package': {'foo.bar.SO': None,
'mymod.c': None,
'mymod.o': None}})
@@ -253,15 +236,16 @@
x = ffi.compile(target="foo.bar.baz")
if sys.platform != 'win32':
self.check_produced_files({
- 'foo.bar.baz': None,
- 'mod_name_in_package': {'mymod.c': None,
+ 'mod_name_in_package': {'foo.bar.baz': None,
+ 'mymod.c': None,
'mymod.o': None}})
- sofile = os.path.join(str(self.udir), 'foo.bar.baz')
+ sofile = os.path.join(str(self.udir),
+ 'mod_name_in_package', 'foo.bar.baz')
assert os.path.isabs(x) and os.path.samefile(x, sofile)
else:
self.check_produced_files({
- 'foo.bar.baz': None,
- 'mod_name_in_package': {'mymod.c': None},
+ 'mod_name_in_package': {'foo.bar.baz': None,
+ 'mymod.c': None},
'Release': '?'})
@chdir_to_tmp
More information about the pypy-commit
mailing list