Commit 6ae38d05 authored by Jason R. Coombs's avatar Jason R. Coombs Committed by GitHub

Merge pull request #718 from dholth/master

use abi3 extension if Extension().is_abi3
parents 7c32dac1 fc6050ad
......@@ -44,6 +44,14 @@ v25.1.3
* #714 and #704: Revert fix as it breaks other components
downstream that can't handle unicode. See #709, #710,
and #712.
* Add Extension(py_limited_api=True). When set to a truthy value,
that extension gets a filename apropriate for code using Py_LIMITED_API.
When used correctly this allows a single compiled extension to work on
all future versions of CPython 3.
The py_limited_api argument only controls the filename. To be
compatible with multiple versions of Python 3, the C extension
will also need to set -DPy_LIMITED_API=... and be modified to use
only the functions in the limited API.
v25.1.2
-------
......
......@@ -59,6 +59,14 @@ elif os.name != 'nt':
if_dl = lambda s: s if have_rtld else ''
def get_abi3_suffix():
"""Return the file extension for an abi3-compliant Extension()"""
import imp
for suffix, _, _ in (s for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION):
if '.abi3' in suffix: # Unix
return suffix
elif suffix == '.pyd': # Windows
return suffix
class build_ext(_build_ext):
......@@ -96,6 +104,13 @@ class build_ext(_build_ext):
filename = _build_ext.get_ext_filename(self, fullname)
if fullname in self.ext_map:
ext = self.ext_map[fullname]
if (sys.version_info[0] != 2
and getattr(ext, 'py_limited_api')
and get_abi3_suffix()):
from distutils.sysconfig import get_config_var
so_ext = get_config_var('SO')
filename = filename[:-len(so_ext)]
filename = filename + get_abi3_suffix()
if isinstance(ext, Library):
fn, ext = os.path.splitext(filename)
return self.shlib_compiler.library_filename(fn, libtype)
......
......@@ -36,6 +36,10 @@ have_pyrex = _have_cython
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
def __init__(self, name, sources, py_limited_api=False, **kw):
self.py_limited_api = py_limited_api
_Extension.__init__(self, name, sources, **kw)
def _convert_pyx_sources_to_lang(self):
"""
Replace sources with .pyx extensions to sources with the target
......
import sys
import distutils.command.build_ext as orig
from setuptools.command.build_ext import build_ext
from distutils.sysconfig import get_config_var
from setuptools.command.build_ext import build_ext, get_abi3_suffix
from setuptools.dist import Distribution
from setuptools.extension import Extension
class TestBuildExt:
......@@ -18,3 +20,24 @@ class TestBuildExt:
res = cmd.get_ext_filename('foo')
wanted = orig.build_ext.get_ext_filename(cmd, 'foo')
assert res == wanted
def test_abi3_filename(self):
"""
Filename needs to be loadable by several versions
of Python 3 if 'is_abi3' is truthy on Extension()
"""
print(get_abi3_suffix())
extension = Extension('spam.eggs', ['eggs.c'], py_limited_api=True)
dist = Distribution(dict(ext_modules=[extension]))
cmd = build_ext(dist)
cmd.finalize_options()
assert 'spam.eggs' in cmd.ext_map
res = cmd.get_ext_filename('spam.eggs')
if sys.version_info[0] == 2 or not get_abi3_suffix():
assert res.endswith(get_config_var('SO'))
elif sys.platform == 'win32':
assert res.endswith('eggs.pyd')
else:
assert 'abi3' in res
\ No newline at end of file
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