Python’s sysconfig module exposes the build-time configuration and installation directory layout for the running interpreter. import sysconfig. get_path: sysconfig.get_path("stdlib") → absolute path; schemes: "stdlib", "purelib", "platlib", "scripts", "data", "include", "platinclude". get_paths: sysconfig.get_paths() → dict of all paths for the default scheme. get_config_var: sysconfig.get_config_var("EXT_SUFFIX") → ".cpython-312-x86_64-linux-gnu.so" (extension suffix); "SOABI", "LDFLAGS", "CC", "py_version_short", "prefix". get_config_vars: sysconfig.get_config_vars() → full dict of all Makefile/pyconfig.h variables. get_python_version: sysconfig.get_python_version() → "3.12". get_platform: sysconfig.get_platform() → "linux-x86_64" (wheel platform tag). get_scheme_names: sysconfig.get_scheme_names() → list of scheme names ("posix_prefix", "nt", "venv", etc.). get_default_scheme: sysconfig.get_default_scheme() → name of active scheme. is_python_build: sysconfig.is_python_build() → True if running in-place from source tree. parse_config_h: sysconfig.parse_config_h(fileobj) → dict from a pyconfig.h-style file. Claude Code generates environment sniffers, extension build helpers, install path resolvers, and cross-platform wheel taggers.
CLAUDE.md for sysconfig
## sysconfig Stack
- Stdlib: import sysconfig
- Path: sysconfig.get_path("stdlib") # absolute install path
- All: sysconfig.get_paths() # dict of all paths
- Var: sysconfig.get_config_var("EXT_SUFFIX") # .cpython-312-...so
- Vars: sysconfig.get_config_vars() # all Makefile vars
- Ver: sysconfig.get_python_version() # "3.12"
- Plat: sysconfig.get_platform() # "linux-x86_64"
sysconfig Build Configuration Pipeline
# app/sysconfigutil.py — paths, vars, platform, extension, venv, cross-compile
from __future__ import annotations
import os
import sys
import sysconfig
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
# ─────────────────────────────────────────────────────────────────────────────
# 1. Path resolution helpers
# ─────────────────────────────────────────────────────────────────────────────
# Standard path keys provided by every scheme
PATH_KEYS = ("stdlib", "purelib", "platlib", "scripts", "data", "include", "platinclude")
def get_path(key: str, scheme: str | None = None) -> Path:
"""
Return an installation path as a Path object.
key: "stdlib", "purelib", "platlib", "scripts", "data", "include", "platinclude"
scheme: None = default scheme; or e.g. "posix_prefix", "nt", "venv"
Example:
scripts_dir = get_path("scripts")
site_packages = get_path("purelib")
"""
kw: dict[str, Any] = {}
if scheme:
kw["scheme"] = scheme
return Path(sysconfig.get_path(key, **kw))
def get_all_paths(scheme: str | None = None) -> dict[str, Path]:
"""
Return all installation paths for the given scheme (default = active scheme).
Example:
for name, path in get_all_paths().items():
print(f" {name:12s}: {path}")
"""
kw: dict[str, Any] = {}
if scheme:
kw["scheme"] = scheme
return {k: Path(v) for k, v in sysconfig.get_paths(**kw).items()}
def site_packages() -> Path:
"""Return the site-packages directory for the current interpreter."""
return get_path("purelib")
def scripts_dir() -> Path:
"""Return the directory where console_scripts entry-point scripts are installed."""
return get_path("scripts")
def stdlib_dir() -> Path:
"""Return the standard library directory."""
return get_path("stdlib")
# ─────────────────────────────────────────────────────────────────────────────
# 2. Build configuration variables
# ─────────────────────────────────────────────────────────────────────────────
def get_var(name: str) -> Any:
"""
Return a single build config variable, or None if not defined.
Example:
ext_suffix = get_var("EXT_SUFFIX") # ".cpython-312-x86_64-linux-gnu.so"
cc = get_var("CC") # "gcc"
"""
return sysconfig.get_config_var(name)
def get_vars(prefix: str = "") -> dict[str, Any]:
"""
Return all build config variables, optionally filtered by name prefix.
Example:
ld_vars = get_vars("LD") # all LDFLAGS-like vars
"""
all_vars = sysconfig.get_config_vars()
if prefix:
return {k: v for k, v in all_vars.items() if k.startswith(prefix)}
return dict(all_vars)
def extension_suffix() -> str:
"""
Return the file extension for compiled C extensions on this platform.
Example:
suf = extension_suffix() # ".cpython-312-x86_64-linux-gnu.so"
"""
return get_var("EXT_SUFFIX") or ".so"
def soabi() -> str | None:
"""Return the SOABI tag (e.g. 'cpython-312-x86_64-linux-gnu') or None."""
return get_var("SOABI")
# ─────────────────────────────────────────────────────────────────────────────
# 3. Platform and version tags
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class PythonEnvironment:
version: str # "3.12"
platform: str # "linux-x86_64"
scheme: str # "posix_prefix"
prefix: str # sys.prefix
exec_prefix: str # sys.exec_prefix
in_venv: bool
is_build: bool
ext_suffix: str
soabi: str | None
paths: dict[str, str] = field(default_factory=dict)
def __str__(self) -> str:
venv_tag = " [venv]" if self.in_venv else ""
build_tag = " [build-dir]" if self.is_build else ""
return (
f"Python {self.version} on {self.platform}{venv_tag}{build_tag}\n"
f" scheme: {self.scheme}\n"
f" prefix: {self.prefix}\n"
f" ext_suffix: {self.ext_suffix}\n"
f" site-pkgs: {self.paths.get('purelib', '?')}"
)
def describe_environment() -> PythonEnvironment:
"""
Snapshot the full Python environment configuration.
Example:
env = describe_environment()
print(env)
"""
in_venv = (
hasattr(sys, "real_prefix") or # virtualenv
(sys.base_prefix != sys.prefix) # venv / conda
)
return PythonEnvironment(
version=sysconfig.get_python_version(),
platform=sysconfig.get_platform(),
scheme=sysconfig.get_default_scheme(),
prefix=sys.prefix,
exec_prefix=sys.exec_prefix,
in_venv=in_venv,
is_build=sysconfig.is_python_build(),
ext_suffix=extension_suffix(),
soabi=soabi(),
paths={k: str(v) for k, v in get_all_paths().items()},
)
def wheel_tag() -> str:
"""
Build a minimal wheel compatibility tag string for the current platform.
Format: cpXY-cpXY-<platform> or py3-none-any for pure Python.
Example:
tag = wheel_tag() # "cp312-cp312-linux_x86_64"
"""
ver = sysconfig.get_python_version().replace(".", "")
plat = sysconfig.get_platform().replace("-", "_").replace(".", "_")
soabi_tag = soabi()
if soabi_tag:
return f"cp{ver}-{soabi_tag.replace('-', '_')}-{plat}"
return f"py3-none-{plat}"
# ─────────────────────────────────────────────────────────────────────────────
# 4. Scheme browser
# ─────────────────────────────────────────────────────────────────────────────
def list_schemes() -> list[str]:
"""
Return all known installation scheme names.
Example:
for scheme in list_schemes():
print(scheme, get_path("purelib", scheme=scheme))
"""
return sorted(sysconfig.get_scheme_names())
def compare_schemes(key: str = "purelib") -> dict[str, str]:
"""
Compare the value of a path key across all schemes.
Example:
for scheme, path in compare_schemes("scripts").items():
print(f" {scheme:20s}: {path}")
"""
result: dict[str, str] = {}
for scheme in list_schemes():
try:
result[scheme] = str(get_path(key, scheme=scheme))
except KeyError:
pass
return result
# ─────────────────────────────────────────────────────────────────────────────
# 5. Extension build helper
# ─────────────────────────────────────────────────────────────────────────────
@dataclass
class ExtensionBuildInfo:
"""
Collects flags and paths needed to compile a C extension against this Python.
"""
include_dirs: list[str]
library_dirs: list[str]
libraries: list[str]
extra_compile: list[str]
extra_link: list[str]
ext_suffix: str
def cflags(self) -> list[str]:
flags = [f"-I{d}" for d in self.include_dirs]
flags += self.extra_compile
return flags
def ldflags(self) -> list[str]:
flags = [f"-L{d}" for d in self.library_dirs]
flags += [f"-l{lib}" for lib in self.libraries]
flags += self.extra_link
return flags
def __str__(self) -> str:
return (
f"ext_suffix: {self.ext_suffix}\n"
f"include: {' '.join(self.include_dirs)}\n"
f"cflags: {' '.join(self.cflags())}\n"
f"ldflags: {' '.join(self.ldflags())}"
)
def extension_build_info() -> ExtensionBuildInfo:
"""
Return compiler/linker info for building a C extension against this Python.
Example:
info = extension_build_info()
print(info)
subprocess.run(["gcc", *info.cflags(), "-shared", "-fPIC",
"myext.c", "-o", f"myext{info.ext_suffix}"])
"""
include_dir = get_var("INCLUDEPY") or ""
platinclude = str(get_path("platinclude"))
inc_dirs = list({d for d in [include_dir, platinclude] if d and Path(d).exists()})
lib_dir = get_var("LIBDIR") or ""
lib_dirs = [lib_dir] if lib_dir and Path(lib_dir).exists() else []
ldflags_str = get_var("LDFLAGS") or ""
cflags_str = get_var("PY_CFLAGS") or ""
return ExtensionBuildInfo(
include_dirs=inc_dirs,
library_dirs=lib_dirs,
libraries=[],
extra_compile=[f for f in cflags_str.split() if f],
extra_link=[f for f in ldflags_str.split() if f],
ext_suffix=extension_suffix(),
)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== sysconfig demo ===")
# ── get_path / get_all_paths ───────────────────────────────────────────────
print("\n--- installation paths ---")
for name, path in get_all_paths().items():
print(f" {name:12s}: {path}")
# ── build variables ────────────────────────────────────────────────────────
print("\n--- key build variables ---")
for var in ["EXT_SUFFIX", "SOABI", "py_version_short", "CC", "prefix"]:
print(f" {var:20s}: {get_var(var)!r}")
# ── describe_environment ───────────────────────────────────────────────────
print("\n--- describe_environment ---")
env = describe_environment()
print(env)
# ── wheel_tag ──────────────────────────────────────────────────────────────
print(f"\n--- wheel_tag: {wheel_tag()!r} ---")
# ── scheme comparison ──────────────────────────────────────────────────────
print("\n--- purelib across schemes (sample) ---")
schemes = compare_schemes("purelib")
for scheme, path in list(schemes.items())[:4]:
print(f" {scheme:20s}: {path}")
# ── extension build info ───────────────────────────────────────────────────
print("\n--- extension_build_info ---")
info = extension_build_info()
print(info)
# ── list_schemes ───────────────────────────────────────────────────────────
print(f"\n--- available schemes: {list_schemes()} ---")
print("\n=== done ===")
For the sys / site alternative — sys.prefix, sys.exec_prefix, sys.path, and sys.version_info expose runtime install locations and the module search path; site.getsitepackages() and site.getusersitepackages() return the site-packages directories directly — use sys and site when you need fast read-only access to the interpreter prefix and site-packages paths at runtime without querying the full build configuration; use sysconfig when you need precise, scheme-aware path resolution for packaging tools (setup.py, pip, build backends) or when you need build variables like EXT_SUFFIX, compiler flags, or the SOABI tag for C extension compilation. For the distutils.sysconfig alternative — distutils.sysconfig (deprecated since 3.10, removed in 3.12) was the original build configuration module and exposed similar variables via get_python_inc(), get_python_lib(), and get_config_var() — use sysconfig (the stdlib replacement) for all new code; the sysconfig module was designed as a clean, scheme-aware replacement and is the authoritative source for build-time variables and install paths in Python 3.2+. The Claude Skills 360 bundle includes sysconfig skill sets covering get_path()/get_all_paths()/site_packages()/scripts_dir()/stdlib_dir() path resolvers, get_var()/get_vars()/extension_suffix()/soabi() build variable readers, PythonEnvironment dataclass with describe_environment()/wheel_tag(), list_schemes()/compare_schemes() scheme browser, and ExtensionBuildInfo with extension_build_info() C extension compiler helper. Start with the free tier to try build configuration patterns and sysconfig pipeline code generation.