summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Holth <dholth@fastmail.fm>2016-08-20 20:10:48 -0400
committerDaniel Holth <dholth@fastmail.fm>2016-08-20 20:10:48 -0400
commit0b0668bebdfc59ce5ebebf4518ba5d1ca53bade3 (patch)
tree1e2503333e45f4a27a9db75c17b153394d1c6036
parent2ac4af16ad29b5e0a54acd734d001e3038f0b235 (diff)
parentec6b7536d9c7714b4a000ace322ebeefe5a7f9b9 (diff)
downloadwheel-0b0668bebdfc59ce5ebebf4518ba5d1ca53bade3.tar.gz
merge
-rw-r--r--docs/index.rst18
-rw-r--r--wheel/bdist_wheel.py25
-rw-r--r--wheel/pep425tags.py11
-rw-r--r--wheel/test/extension.dist/extension.c2
-rw-r--r--wheel/test/extension.dist/setup.cfg2
-rw-r--r--wheel/test/extension.dist/setup.py20
6 files changed, 70 insertions, 8 deletions
diff --git a/docs/index.rst b/docs/index.rst
index 5b1b157..f1dbce6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -111,9 +111,21 @@ used to specify the Python version tag to use more precisely::
equates to the tag "py2.py3".
--python-tag XXX Specifies the precise python version tag to use for
a pure-python wheel.
-
-Neither of these two flags have any effect when used on a project that includes
-C extension code.
+ --py-limited-api {cp32|cp33|cp34|...}
+ Specifies Python Py_LIMITED_API compatibility with
+ the version of CPython passed and later versions.
+ The wheel will be tagged cpNN.abi3.{arch} on CPython 3.
+ This flag does not affect Python 2 builds or alternate
+ Python implementations.
+
+ To conform to the limited API, all your C
+ extensions must use only functions from the limited
+ API, pass Extension(py_limited_api=True) and e.g.
+ #define Py_LIMITED_API=0x03020000 depending on
+ the exact minimun Python you wish to support.
+
+The --universal and --python-tag flags have no effect when used on a
+project that includes C extension code.
The default for a pure Python project (if no explicit flags are given) is "pyN"
where N is the major version of the Python interpreter used to build the wheel.
diff --git a/wheel/bdist_wheel.py b/wheel/bdist_wheel.py
index d716163..edbba05 100644
--- a/wheel/bdist_wheel.py
+++ b/wheel/bdist_wheel.py
@@ -12,6 +12,7 @@ import warnings
import shutil
import json
import sys
+import re
try:
import sysconfig
@@ -40,6 +41,8 @@ from .metadata import pkginfo_to_dict
from . import pep425tags, metadata
from . import __version__ as wheel_version
+PY_LIMITED_API_PATTERN = r'cp3\d'
+
def safer_name(name):
return safe_name(name).replace('-', '_')
@@ -77,6 +80,9 @@ class bdist_wheel(Command):
('python-tag=', None,
"Python implementation compatibility tag"
" (default: py%s)" % get_impl_ver()[0]),
+ ('py-limited-api=', None,
+ "Python tag (cp32|cp33|cpNN) for abi3 wheel tag"
+ " (default: false)"),
]
boolean_options = ['keep-temp', 'skip-build', 'relative', 'universal']
@@ -98,6 +104,7 @@ class bdist_wheel(Command):
self.group = None
self.universal = False
self.python_tag = 'py' + get_impl_ver()[0]
+ self.py_limited_api = False
self.plat_name_supplied = False
def finalize_options(self):
@@ -116,6 +123,9 @@ class bdist_wheel(Command):
self.root_is_pure = not (self.distribution.has_ext_modules()
or self.distribution.has_c_libraries())
+ if self.py_limited_api and not re.match(PY_LIMITED_API_PATTERN, self.py_limited_api):
+ raise ValueError("py-limited-api must match '%s'" % PY_LIMITED_API_PATTERN)
+
# Support legacy [wheel] section for setting universal
wheel = self.distribution.get_option_dict('wheel')
if 'universal' in wheel:
@@ -153,13 +163,20 @@ class bdist_wheel(Command):
else:
impl_name = get_abbr_impl()
impl_ver = get_impl_ver()
- # PEP 3149
- abi_tag = str(get_abi_tag()).lower()
- tag = (impl_name + impl_ver, abi_tag, plat_name)
+ impl = impl_name + impl_ver
+ # We don't work on CPython 3.1, 3.0.
+ if self.py_limited_api and (impl_name + impl_ver).startswith('cp3'):
+ impl = self.py_limited_api
+ abi_tag = 'abi3'
+ else:
+ abi_tag = str(get_abi_tag()).lower()
+ tag = (impl, abi_tag, plat_name)
supported_tags = pep425tags.get_supported(
supplied_platform=plat_name if self.plat_name_supplied else None)
# XXX switch to this alternate implementation for non-pure:
- assert tag == supported_tags[0], "%s != %s" % (tag, supported_tags[0])
+ if not self.py_limited_api:
+ assert tag == supported_tags[0], "%s != %s" % (tag, supported_tags[0])
+ assert tag in supported_tags, "would build wheel with unsupported tag %s" % tag
return tag
def get_archive_basename(self):
diff --git a/wheel/pep425tags.py b/wheel/pep425tags.py
index 5ac5d0d..49a1367 100644
--- a/wheel/pep425tags.py
+++ b/wheel/pep425tags.py
@@ -152,7 +152,16 @@ def get_supported(versions=None, supplied_platform=None):
for abi in abis:
for arch in platforms:
supported.append(('%s%s' % (impl, versions[0]), abi, arch))
-
+
+ # abi3 modules compatible with older version of Python
+ for version in versions[1:]:
+ # abi3 was introduced in Python 3.2
+ if version in ('31', '30'):
+ break
+ for abi in abi3s: # empty set if not Python 3
+ for arch in platforms:
+ supported.append(("%s%s" % (impl, version), abi, arch))
+
# No abi / arch, but requires our implementation:
for i, version in enumerate(versions):
supported.append(('%s%s' % (impl, version), 'none', 'any'))
diff --git a/wheel/test/extension.dist/extension.c b/wheel/test/extension.dist/extension.c
new file mode 100644
index 0000000..a37c3fa
--- /dev/null
+++ b/wheel/test/extension.dist/extension.c
@@ -0,0 +1,2 @@
+#define Py_LIMITED_API 0x03020000
+#include <Python.h>
diff --git a/wheel/test/extension.dist/setup.cfg b/wheel/test/extension.dist/setup.cfg
new file mode 100644
index 0000000..9f6ff39
--- /dev/null
+++ b/wheel/test/extension.dist/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+py_limited_api=cp32
diff --git a/wheel/test/extension.dist/setup.py b/wheel/test/extension.dist/setup.py
new file mode 100644
index 0000000..7a66845
--- /dev/null
+++ b/wheel/test/extension.dist/setup.py
@@ -0,0 +1,20 @@
+from setuptools import setup, Extension
+
+try:
+ unicode
+ def u8(s):
+ return s.decode('unicode-escape').encode('utf-8')
+except NameError:
+ def u8(s):
+ return s.encode('utf-8')
+
+setup(name='extension.dist',
+ version='0.1',
+ description=u8('A testing distribution \N{SNOWMAN}'),
+ ext_modules=[
+ Extension(name='extension',
+ sources=['extension.c'],
+ py_limited_api=True)
+ ],
+ )
+