from __future__ import annotations
import os
import platform as host
import shutil
from pathlib import Path
from setuptools import Distribution, setup
from setuptools.command.bdist_wheel import bdist_wheel
from setuptools.command.build_py import build_py
CDYLIB_NAMES = ("pith_pdf.dll", "libpith_pdf.so", "libpith_pdf.dylib")
class BinaryDistribution(Distribution):
def has_ext_modules(self) -> bool: return True
def native_platform_tag(platform: str, machine: str) -> str:
if not (platform.startswith("macosx_") and platform.endswith("_universal2")):
return platform
arch = {"arm64": "arm64", "aarch64": "arm64", "x86_64": "x86_64", "amd64": "x86_64"}.get(machine.lower())
if arch is None:
raise RuntimeError(f"pith-pdf: cannot narrow {platform} for host architecture {machine!r}")
return platform[: -len("universal2")] + arch
class bdist_wheel_py3_none(bdist_wheel):
def get_tag(self): _python, _abi, platform = super().get_tag()
return "py3", "none", native_platform_tag(platform, host.machine())
class build_py_with_cdylib(build_py):
def run(self) -> None:
super().run()
repo_root = Path(__file__).resolve().parent.parent.parent
env_dir = os.environ.get("PITH_CDYLIB_DIR")
candidates = [Path(env_dir)] if env_dir else []
if not env_dir or not Path(env_dir).is_absolute():
candidates.append(repo_root / (env_dir or "target/release"))
candidates.append(repo_root / "target" / "release")
pkg_dir = Path(self.build_lib) / "pith_pdf"
copied = 0
for candidate in candidates:
for name in CDYLIB_NAMES:
src = candidate / name
if src.is_file():
self.mkpath(str(pkg_dir))
shutil.copy2(src, pkg_dir / name)
copied += 1
if copied:
break
if copied == 0:
raise SystemExit(
f"no cdylib (any of {', '.join(CDYLIB_NAMES)}) found in "
f"{', '.join(str(c) for c in candidates)}; run `cargo build --release` first"
)
setup(
cmdclass={"build_py": build_py_with_cdylib, "bdist_wheel": bdist_wheel_py3_none},
distclass=BinaryDistribution,
)