Skip to content

Commit

Permalink
Automatically set compiler flags to target PEP 384 Python limited API
Browse files Browse the repository at this point in the history
PEP 384 introduced a Python limited API that allows you to build one
wheel that targets all Python versions on a given platform.

Setuptools supports opting in to building wheels for the Python
limited API by adding the following lines to ``setup.cfg``:

    [bdist_wheel]
    py_limited_api = cp36  # replace with desired min Python version

However, there are two needed steps that Setuptools does not do
automatically:

1. Pass the `py_limited_api=True` keyword argument to each `Extension`
2. Set the `Py_LIMITED_API` preprocessor macro to the version hex
   value for the desired minimum Python version

This patch teaches `get_extension()` to do those two missing steps
automatically if the limited API is enabled in the ``setup.cfg`` file.
  • Loading branch information
lpsinger committed Feb 9, 2021
1 parent 51636f3 commit 3b744c9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
17 changes: 17 additions & 0 deletions docs/using.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,20 @@ To use this, you should modify your ``setup.py`` file to use
Note that if you use this, extension-helpers will also we create a
``packagename.compiler_version`` submodule that contain information about the
compilers used.

Python limited API
------------------

Your package may opt in to the :pep:`384` Python Limited API so that a single
binary wheel works with many different versions of Python on the same platform.
To opt in to the Python Limited API, add the following standard setuptools
option to your project's ``setup.cfg`` file::

[bdist_wheel]
py_limited_api = cp36

Here, ``36`` denotes API compatibility with Python >= 3.6. Replace with the
lowest major and minor version number that you wish to support.

The ``get_extensions()`` functions will automatically detect this option and
add the necessary compiler flags to build your extension modules.
46 changes: 45 additions & 1 deletion extension_helpers/_setup_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import os
import re
import sys
import shutil
import subprocess
Expand All @@ -15,12 +16,37 @@
from setuptools import find_packages
from setuptools.config import read_configuration

from ._distutils_helpers import get_compiler
from ._distutils_helpers import get_compiler, get_distutils_option
from ._utils import import_file, walk_skip_hidden

__all__ = ['get_extensions', 'pkg_config']


_PEP_384_WARNING = """\
Not targeting PEP 384 limited API. You can build one binary wheel for each \
platform to support all Python versions by adding the following to your \
project's setup.cfg file:
[bdist_wheel]
py_limited_api = cp36
Replace '36' with the lowest Python major and minor version that you wish to \
support.
"""

def _abi_to_version_info(abi):
match = re.fullmatch(r'^cp(\d)(\d)$', abi)
if match is None:
return None
else:
return int(match[1]), int(match[2])


def _version_info_to_version_hex(major=0, minor=0, micro=0,
releaselevel=0, serial=0):
return f'0x{major:0>2}{minor:0>2}{micro:0>2}{releaselevel:0>2}{serial:0>2}'


def get_extensions(srcdir='.'):
"""
Collect all extensions from Cython files and ``setup_package.py`` files.
Expand Down Expand Up @@ -85,6 +111,24 @@ def get_extensions(srcdir='.'):
[os.path.join(main_package_dir, '_compiler.c')])
ext_modules.append(ext)

use_limited_api = False
abi = get_distutils_option('py_limited_api', ['bdist_wheel'])
if abi:
version_info = _abi_to_version_info(abi)
if version_info:
use_limited_api = True

if use_limited_api:
log.info(
'Targeting PEP 384 limited API supporting Python >= %d.%d',
*version_info)
version_hex = _version_info_to_version_hex(*version_info)
for ext in ext_modules:
ext.py_limited_api = True
ext.define_macros.append(('Py_LIMITED_API', version_hex))
else:
log.warn(_PEP_384_WARNING)

return ext_modules


Expand Down

0 comments on commit 3b744c9

Please sign in to comment.