File size: 2,245 Bytes
7344bef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from __future__ import annotations

import ctypes
import os
import sys
from pathlib import Path

_PRELOADED_LIBSTDCXX: str | None = None


def _loaded_libstdcxx_paths() -> list[str]:
    if not sys.platform.startswith("linux"):
        return []
    maps_path = Path("/proc/self/maps")
    if not maps_path.is_file():
        return []

    paths: list[str] = []
    try:
        with maps_path.open("r", encoding="utf-8") as reader:
            for line in reader:
                if "libstdc++.so.6" not in line:
                    continue
                path = line.rsplit(None, 1)[-1]
                if path not in paths:
                    paths.append(path)
    except OSError:
        return []
    return paths


def _candidate_libstdcxx_paths() -> list[str]:
    prefixes = [sys.prefix, sys.exec_prefix, os.environ.get("CONDA_PREFIX")]
    paths: list[str] = []
    seen: set[str] = set()
    for prefix in prefixes:
        if not prefix:
            continue
        path = str(Path(prefix) / "lib" / "libstdc++.so.6")
        norm_path = os.path.normcase(os.path.abspath(path))
        if norm_path in seen or not os.path.isfile(path):
            continue
        seen.add(norm_path)
        paths.append(path)
    return paths


def _prepend_library_path(path: str) -> None:
    directory = os.path.dirname(path)
    if not directory:
        return
    current = os.environ.get("LD_LIBRARY_PATH", "")
    parts = [part for part in current.split(os.pathsep) if part]
    if directory in parts:
        return
    os.environ["LD_LIBRARY_PATH"] = os.pathsep.join([directory, *parts])


def preload_preferred_libstdcxx() -> str | None:
    global _PRELOADED_LIBSTDCXX
    if _PRELOADED_LIBSTDCXX is not None:
        return _PRELOADED_LIBSTDCXX
    if not sys.platform.startswith("linux"):
        return None

    loaded_paths = _loaded_libstdcxx_paths()
    if loaded_paths:
        return None

    for path in _candidate_libstdcxx_paths():
        try:
            mode = getattr(os, "RTLD_GLOBAL", 0) | getattr(os, "RTLD_NOW", 0)
            ctypes.CDLL(path, mode=mode)
        except OSError:
            continue
        _prepend_library_path(path)
        _PRELOADED_LIBSTDCXX = path
        return path
    return None