blob: 8bd0a9bf13d1731c6c1a337cf31b6416ca608a62 [file]
from __future__ import annotations
import os
import re
import sys
DIR = os.path.abspath(os.path.dirname(__file__))
# shlex/sysconfig are imported lazily below to keep `import pybind11` light
# This is the conditional used for os.path being posixpath
if "posix" in sys.builtin_module_names:
def _quote(s: str) -> str:
import shlex
return shlex.quote(s)
elif "nt" in sys.builtin_module_names:
# See https://github.com/mesonbuild/meson/blob/db22551ed9d2dd7889abea01cc1c7bba02bf1c75/mesonbuild/utils/universal.py#L1092-L1121
# and the original documents:
# https://docs.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments and
# https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
_UNSAFE = re.compile("[ \t\n\r]")
def _quote(s: str) -> str:
if s and not _UNSAFE.search(s):
return s
# Paths cannot contain a '"' on Windows, so we don't need to worry
# about nuanced counting here.
return f'"{s}\\"' if s.endswith("\\") else f'"{s}"'
else:
def _quote(s: str) -> str:
return s
def _config(name: str) -> str:
"""A stripped sysconfig variable, or "" if unset."""
import sysconfig
return str(sysconfig.get_config_var(name) or "").strip()
def get_include(user: bool = False) -> str: # noqa: ARG001
"""
Return the path to the pybind11 include directory. The historical "user"
argument is unused, and may be removed.
"""
installed_path = os.path.join(DIR, "include")
source_path = os.path.join(os.path.dirname(DIR), "include")
return installed_path if os.path.exists(installed_path) else source_path
def get_cmake_dir() -> str:
"""
Return the path to the pybind11 CMake module directory.
"""
cmake_installed_path = os.path.join(DIR, "share", "cmake", "pybind11")
if os.path.exists(cmake_installed_path):
return cmake_installed_path
msg = "pybind11 not installed, installation required to access the CMake files"
raise ImportError(msg)
def get_pkgconfig_dir() -> str:
"""
Return the path to the pybind11 pkgconfig directory.
"""
pkgconfig_installed_path = os.path.join(DIR, "share", "pkgconfig")
if os.path.exists(pkgconfig_installed_path):
return pkgconfig_installed_path
msg = "pybind11 not installed, installation required to access the pkgconfig files"
raise ImportError(msg)
def get_include_dirs() -> list[str]:
"""
Return the unique include directories for Python and pybind11.
"""
import sysconfig
dirs = [
sysconfig.get_path("include"),
sysconfig.get_path("platinclude"),
get_include(),
]
# Make unique but preserve order
unique_dirs = []
for d in dirs:
if d and d not in unique_dirs:
unique_dirs.append(d)
return unique_dirs
def get_cflags() -> str:
"""
Return the compile flags for building a simple extension with a
Unix-style command-line compiler (GCC/Clang). Based on python-config.
"""
flags = [_quote(f"-I{d}") for d in get_include_dirs()]
# CFLAGS is a pre-composed multi-flag string, passed through as-is (like
# python-config does)
if cflags := _config("CFLAGS"):
flags.append(cflags)
flags.append("-std=c++17")
return " ".join(flags)
def get_ldflags(embed: bool = False) -> str:
"""
Return the link flags for building a simple extension (or, with
embed=True, an embedding program) with a Unix-style command-line
compiler (GCC/Clang). Based on python-config.
"""
# LDFLAGS/LIBS/SYSLIBS are pre-composed multi-flag strings, passed
# through as-is (like python-config does)
flags = [ldflags] if (ldflags := _config("LDFLAGS")) else []
if embed:
if libdir := _config("LIBDIR"):
flags.append(_quote(f"-L{libdir}"))
if not _config("Py_ENABLE_SHARED") and (libpl := _config("LIBPL")):
flags.append(_quote(f"-L{libpl}"))
abiflags = getattr(sys, "abiflags", "") or ""
flags.append(f"-lpython{_config('VERSION')}{abiflags}")
if libs := _config("LIBS"):
flags.append(libs)
if syslibs := _config("SYSLIBS"):
flags.append(syslibs)
elif sys.platform.startswith("darwin"):
flags += ["-undefined", "dynamic_lookup", "-shared"]
elif os.name == "posix":
# Linux and other Unix platforms (FreeBSD, Solaris, AIX, ...)
flags += ["-fPIC", "-shared"]
return " ".join(flags)