| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 | """PEP 656 support.This module implements logic to detect if the currently running Python islinked against musl, and what musl version is used."""import functoolsimport reimport subprocessimport sysfrom typing import Iterator, NamedTuple, Optionalfrom ._elffile import ELFFileclass _MuslVersion(NamedTuple):    major: int    minor: intdef _parse_musl_version(output: str) -> Optional[_MuslVersion]:    lines = [n for n in (n.strip() for n in output.splitlines()) if n]    if len(lines) < 2 or lines[0][:4] != "musl":        return None    m = re.match(r"Version (\d+)\.(\d+)", lines[1])    if not m:        return None    return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2)))@functools.lru_cache()def _get_musl_version(executable: str) -> Optional[_MuslVersion]:    """Detect currently-running musl runtime version.    This is done by checking the specified executable's dynamic linking    information, and invoking the loader to parse its output for a version    string. If the loader is musl, the output would be something like::        musl libc (x86_64)        Version 1.2.2        Dynamic Program Loader    """    try:        with open(executable, "rb") as f:            ld = ELFFile(f).interpreter    except (OSError, TypeError, ValueError):        return None    if ld is None or "musl" not in ld:        return None    proc = subprocess.run([ld], stderr=subprocess.PIPE, universal_newlines=True)    return _parse_musl_version(proc.stderr)def platform_tags(arch: str) -> Iterator[str]:    """Generate musllinux tags compatible to the current platform.    :param arch: Should be the part of platform tag after the ``linux_``        prefix, e.g. ``x86_64``. The ``linux_`` prefix is assumed as a        prerequisite for the current platform to be musllinux-compatible.    :returns: An iterator of compatible musllinux tags.    """    sys_musl = _get_musl_version(sys.executable)    if sys_musl is None:  # Python not dynamically linked against musl.        return    for minor in range(sys_musl.minor, -1, -1):        yield f"musllinux_{sys_musl.major}_{minor}_{arch}"if __name__ == "__main__":  # pragma: no cover    import sysconfig    plat = sysconfig.get_platform()    assert plat.startswith("linux-"), "not linux"    print("plat:", plat)    print("musl:", _get_musl_version(sys.executable))    print("tags:", end=" ")    for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])):        print(t, end="\n      ")
 |