Skip to content

Commit

Permalink
Custom get_native_tags() based on PyPA packaging
Browse files Browse the repository at this point in the history
  • Loading branch information
tttapa committed Aug 18, 2022
1 parent fdf1602 commit ee4e24e
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 8 deletions.
24 changes: 16 additions & 8 deletions src/py_build_cmake/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,12 @@ def create_wheel(self, wheel_directory, tmp_build_dir, cfg, dist_name,
libdir = 'purelib' if pure else 'platlib'
paths = {'prefix': str(tmp_build_dir), libdir: str(tmp_build_dir)}
whl.dirname = wheel_directory
tags = None
if cfg.cross:
tags = self.get_cross_tags(cfg.cross)
if pure:
tags = {'pyver': ['py3']}
elif cfg.cross:
tags = self.get_cross_tags(cfg.cross)
else:
tags = self.get_native_tags()
wheel_path = whl.build(paths, tags=tags, wheel_version=(1, 0))
whl_name = os.path.relpath(wheel_path, wheel_directory)
return whl_name
Expand Down Expand Up @@ -532,18 +533,25 @@ def get_cross_tags(crosscfg):
'arch': [crosscfg['arch']],
}

@staticmethod
def get_native_tags():
from .tags import get_python_tag, get_abi_tag, get_platform_tag
return {
'pyver': [get_python_tag()],
'abi': [get_abi_tag()],
'arch': [get_platform_tag()],
}

@staticmethod
def get_build_config_name(cross_cfg):
"""Get a string representing the Python version, ABI and architecture,
used to name the build folder so builds for different versions don't
interfere."""
if cross_cfg:
return '-'.join(
map(lambda x: x[0],
_BuildBackend.get_cross_tags(cross_cfg).values()))
tags = _BuildBackend.get_cross_tags(cross_cfg)
else:
from distlib.wheel import IMPVER, ABI, ARCH
return '-'.join([IMPVER, ABI, ARCH])
tags = _BuildBackend.get_native_tags()
return '-'.join(map(lambda x: x[0], tags.values()))

def needs_cross_native_build(self, cfg):
return cfg.cross and 'copy_from_native_build' in cfg.cross
Expand Down
83 changes: 83 additions & 0 deletions src/py_build_cmake/tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
distlib.wheel doesn't always return the correct tags, and packaging.tags
returns all tags supported by the interpreter, not the tags that should be used
for the generated wheels. Therefore the only option here is to write our own
(kind of hacky) functions based on packaging.tags.
"""

from typing import Dict
import sys
import sysconfig
from importlib.machinery import EXTENSION_SUFFIXES
from distlib.util import get_platform as get_platform_dashes

_INTERPRETER_SHORT_NAMES: Dict[str, str] = {
"python": "py",
"cpython": "cp",
"pypy": "pp",
"ironpython": "ip",
"jython": "jy",
}


def _normalize_string(s: str) -> str:
return s.replace(".", "_").replace("-", "_")


def get_platform_tag() -> str:
return _normalize_string(get_platform_dashes())


def get_interpreter_name() -> str:
name = sys.implementation.name
return _INTERPRETER_SHORT_NAMES.get(name) or name


def get_interpreter_version() -> str:
return "".join(map(str, sys.version_info[:2]))


def get_cpython_interpreter() -> str:
return f"cp{get_interpreter_version()}"


def get_cpython_abi() -> str:
"""
Get the ABI string for CPython, e.g. cp37m.
https://github.com/pypa/packaging/blob/917612f5774571a99902b5fe04d06099b9e8b667/packaging/tags.py#L135
"""
py_version = sys.version_info[:2]
debug = pymalloc = ""
with_debug = sysconfig.get_config_var("Py_DEBUG")
has_refcount = hasattr(sys, "gettotalrefcount")
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
# extension modules is the best option.
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
if with_debug or (with_debug is None and (has_refcount or has_ext)):
debug = "d"
if py_version < (3, 8):
with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC")
if with_pymalloc or with_pymalloc is None:
pymalloc = "m"
return f"{get_cpython_interpreter()}{debug}{pymalloc}"


def get_generic_interpreter() -> str:
return f"{get_interpreter_name()}{get_interpreter_version()}"


def get_generic_abi() -> str:
abi = sysconfig.get_config_var("SOABI") or "none"
return _normalize_string(abi)


def get_python_tag() -> str:
if get_interpreter_name() == "cp": return get_cpython_interpreter()
else: return get_generic_interpreter()


def get_abi_tag() -> str:
if get_interpreter_name() == "cp": return get_cpython_abi()
else: return get_generic_abi()

0 comments on commit ee4e24e

Please sign in to comment.