Mooncake/mooncake-wheel/setup.py

172 lines
6.4 KiB
Python

import sys
import platform
from setuptools import setup, Distribution
from wheel.bdist_wheel import bdist_wheel
# ---------------------------------------------------------------------------
# Platform guard
# ---------------------------------------------------------------------------
unsupported_platforms = ["win32", "darwin"] # Still blocking non-Linux builds
if sys.platform in unsupported_platforms:
sys.exit(
f"Error: mooncake does not support {platform.system()} at this time. "
"Please use a supported Linux distribution."
)
# ---------------------------------------------------------------------------
# helpers
# ---------------------------------------------------------------------------
try:
# packaging ≥20 provides a robust glibc detector used by pip/build
from packaging.tags import glibc_version_string
except ImportError:
glibc_version_string = None
def _detect_manylinux_tag() -> str:
"""
Return a PEP 600-style manylinux tag matching *this* build host (e.g. 'manylinux_2_31').
Falls back to 'manylinux_2_17' if detection fails for maximum compatibility.
"""
if glibc_version_string is not None:
ver = glibc_version_string()
else:
import subprocess
import shutil
# Try getconf first (POSIX standard, most reliable, no hardcoded libc name)
ver = None
if shutil.which("getconf"):
try:
result = subprocess.run(
["getconf", "GNU_LIBC_VERSION"],
capture_output=True,
text=True,
timeout=1,
)
if result.returncode == 0 and result.stdout.strip():
# Output format: "glibc X.Y" or "X.Y"
ver_str = result.stdout.strip()
ver = ver_str.split()[-1] if "glibc" in ver_str else ver_str
except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
pass
# Fallback: use ctypes with dynamic libc detection
if ver is None:
import ctypes
try:
# Try to find libc dynamically instead of hardcoding "libc.so.6"
libc = None
# First try the standard name (works for 99.9% of Linux systems)
for name in ["libc.so.6", "libc.so"]:
try:
libc = ctypes.CDLL(name)
break
except OSError:
continue
# If standard names don't work, try to find via ldconfig
if libc is None:
try:
result = subprocess.run(
["ldconfig", "-p"],
capture_output=True,
text=True,
timeout=1,
)
if result.returncode == 0:
for line in result.stdout.split("\n"):
if "libc.so" in line:
# Extract path from ldconfig output
# Format: "libc.so.6 (libc6,x86-64) => /lib/x86_64-linux-gnu/libc.so.6"
parts = line.split("=>")
if len(parts) == 2:
libc_path = parts[1].strip()
libc = ctypes.CDLL(libc_path)
break
except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
pass
if libc is not None:
# gnu_get_libc_version returns a const char* (C string)
# Set the return type to c_char_p to get the string properly
libc.gnu_get_libc_version.restype = ctypes.c_char_p
version_bytes = libc.gnu_get_libc_version()
ver = version_bytes.decode("ascii", "replace")
else:
raise OSError("libc not found")
except Exception:
ver = "2.17" # conservative baseline
major, minor, *_ = ver.split(".")
return f"manylinux_{major}_{minor}"
# ---------------------------------------------------------------------------
# wheel tag builders
# ---------------------------------------------------------------------------
def get_arch() -> str:
"""
CPU architecture component of the wheel tag.
"""
if sys.platform.startswith("linux"):
if platform.machine() == "x86_64":
return "x86_64"
if platform.machine() in ("arm64", "aarch64"):
return "aarch64"
elif sys.platform == "darwin":
# Return only the arch; macOS deployment target lives in get_system()
return "aarch64" if platform.machine() in ("arm64", "aarch64") else "x86_64"
elif sys.platform == "win32":
return "win_amd64"
raise ValueError(f"Unsupported platform: {sys.platform}")
def get_system() -> str:
"""
OS component of the wheel tag (PEP 425 / PEP 600 compliant).
"""
sys_name = platform.system()
if sys_name == "Windows":
return "win"
elif sys_name == "Darwin":
# Use macosx_{major}_{minor} layout (underscored) per PEP 425
major, minor, *_ = (platform.mac_ver()[0] or "11.0").split(".")
return f"macosx_{major}_{minor}"
elif sys_name == "Linux":
return _detect_manylinux_tag()
raise ValueError(f"Unsupported system: {sys_name}")
def get_platform() -> str:
"""Full `{system}_{arch}` tag used by bdist_wheel."""
return f"{get_system()}_{get_arch()}"
# ---------------------------------------------------------------------------
# dist / cmd hooks
# ---------------------------------------------------------------------------
class BinaryDistribution(Distribution):
def has_ext_modules(self):
return True
class CustomBdistWheel(bdist_wheel):
def finalize_options(self):
super().finalize_options()
self.root_is_pure = False
self.plat_name_supplied = True
self.plat_name = get_platform()
# ---------------------------------------------------------------------------
# setup()
# ---------------------------------------------------------------------------
setup(
distclass=BinaryDistribution,
cmdclass={"bdist_wheel": CustomBdistWheel},
)