From 051eef99e60418a5d714cd441d8ceecca7995b29 Mon Sep 17 00:00:00 2001 From: Devashish Lal Date: Sat, 31 May 2025 23:09:37 -0700 Subject: [PATCH 1/2] improve python lib detection On windows the vars in sysconfig return None so as a fallback we try to enumerate possible library candidates in the installation base to see if we can find the library Signed-off-by: Devashish Lal --- src/scikit_build_core/builder/sysconfig.py | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/scikit_build_core/builder/sysconfig.py b/src/scikit_build_core/builder/sysconfig.py index 78168186..c76f57f5 100644 --- a/src/scikit_build_core/builder/sysconfig.py +++ b/src/scikit_build_core/builder/sysconfig.py @@ -1,6 +1,7 @@ from __future__ import annotations import configparser +import itertools import os import sys import sysconfig @@ -44,6 +45,84 @@ def __dir__() -> list[str]: return __all__ +# Adapted from scikit-build by removing few checks that have already been earlier +# https://github.com/scikit-build/scikit-build/blob/master/skbuild/cmaker.py#L514 +def _try_to_find_python_library() -> Path | None: + candidate_lib_prefixes = ["", "lib"] + candidate_suffixes = [""] + candidate_implementations = ["python"] + if hasattr(sys, "pypy_version_info"): + candidate_implementations = ["pypy-c", "pypy3-c", "pypy"] + candidate_suffixes.append("-c") + + candidate_extensions = [".lib", ".so", ".a"] + # On pypy + MacOS, the variable WITH_DYLD is not set. It would + # actually be possible to determine the python library there using + # LDLIBRARY + LIBDIR. As a simple fix, we check if the LDLIBRARY + # ends with .dylib and add it to the candidate matrix in this case. + with_ld = sysconfig.get_config_var("WITH_DYLD") + ld_lib = sysconfig.get_config_var("LDLIBRARY") + if with_ld or (ld_lib and ld_lib.endswith(".dylib")): + candidate_extensions.insert(0, ".dylib") + + # Check the specific version first, e.g ["312", "3", ""] + candidate_versions = [ + f"{sys.version_info.major}{sys.version_info.minor}", + f"{sys.version_info.major}", + "", + ] + + abiflags = getattr(sys, "abiflags", "") + candidate_abiflags = [abiflags] + if abiflags: + candidate_abiflags.append("") + + candidate_libdirs = [] + + # Look at install base if available + install_base = sysconfig.get_config_var("installed_base") + if install_base: + candidate_libdirs.append(Path.resolve(Path(install_base) / "libs")) + + # Look at libdist if available + libdest = sysconfig.get_config_var("LIBDEST") + if libdest: + candidate_libdirs.append(Path.resolve(Path(install_base) / ".." / "libs")) + + # Check multiarch + candidate_multiarc_libdirs = [] + multiarch: str | None = sysconfig.get_config_var("MULTIARCH") + masd: str | None = sysconfig.get_config_var("multiarchsubdir") + for libdir in candidate_libdirs: + if multiarch and masd: + if masd.startswith(os.sep): + masd = masd[len(os.sep) :] + libdir_masd = libdir / masd + candidate_multiarc_libdirs.append(libdir_masd) + + candidates = ( + libdir / f"{pre}{impl}{ver}{abi}{suf}{ext}" + for (libdir, pre, impl, ext, ver, abi, suf) in itertools.product( + candidate_libdirs + candidate_multiarc_libdirs, + candidate_lib_prefixes, + candidate_implementations, + candidate_extensions, + candidate_versions, + candidate_abiflags, + candidate_suffixes, + ) + ) + + python_library = None + + for candidate in candidates: + if Path.exists(candidate): + python_library = candidate + break + + return python_library + + def get_python_library(env: Mapping[str, str], *, abi3: bool = False) -> Path | None: # When cross-compiling, check DIST_EXTRA_CONFIG first config_file = env.get("DIST_EXTRA_CONFIG", None) @@ -108,6 +187,10 @@ def get_python_library(env: Mapping[str, str], *, abi3: bool = False) -> Path | if libpath.is_file(): return libpath + lib_path: Path | None = _try_to_find_python_library() + if lib_path: + return lib_path + log_func( "Can't find a Python library, got libdir={}, ldlibrary={}, multiarch={}, masd={}", libdir, From 6c290c25a5ac1f3443a29e93c7626d231f584435 Mon Sep 17 00:00:00 2001 From: Devashish Lal Date: Mon, 2 Jun 2025 00:06:57 -0700 Subject: [PATCH 2/2] fixed python3.lib not being added for sabi incase of sabi abi3=True is passed to get library which looks for the .lib without minor version Signed-off-by: Devashish Lal --- src/scikit_build_core/builder/sysconfig.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/scikit_build_core/builder/sysconfig.py b/src/scikit_build_core/builder/sysconfig.py index c76f57f5..ac055103 100644 --- a/src/scikit_build_core/builder/sysconfig.py +++ b/src/scikit_build_core/builder/sysconfig.py @@ -47,7 +47,7 @@ def __dir__() -> list[str]: # Adapted from scikit-build by removing few checks that have already been earlier # https://github.com/scikit-build/scikit-build/blob/master/skbuild/cmaker.py#L514 -def _try_to_find_python_library() -> Path | None: +def _try_to_find_python_library(*, abi3: bool = False) -> Path | None: candidate_lib_prefixes = ["", "lib"] candidate_suffixes = [""] candidate_implementations = ["python"] @@ -72,6 +72,10 @@ def _try_to_find_python_library() -> Path | None: "", ] + # Don't consider minor version if abi3 + if abi3: + candidate_versions.pop(0) + abiflags = getattr(sys, "abiflags", "") candidate_abiflags = [abiflags] if abiflags: @@ -187,7 +191,7 @@ def get_python_library(env: Mapping[str, str], *, abi3: bool = False) -> Path | if libpath.is_file(): return libpath - lib_path: Path | None = _try_to_find_python_library() + lib_path: Path | None = _try_to_find_python_library(abi3=abi3) if lib_path: return lib_path