comparison planemo/lib/python3.7/site-packages/pip/_internal/utils/glibc.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 from __future__ import absolute_import
2
3 import os
4 import re
5 import warnings
6
7 from pip._internal.utils.typing import MYPY_CHECK_RUNNING
8
9 if MYPY_CHECK_RUNNING:
10 from typing import Optional, Tuple
11
12
13 def glibc_version_string():
14 # type: () -> Optional[str]
15 "Returns glibc version string, or None if not using glibc."
16 return glibc_version_string_confstr() or glibc_version_string_ctypes()
17
18
19 def glibc_version_string_confstr():
20 # type: () -> Optional[str]
21 "Primary implementation of glibc_version_string using os.confstr."
22 # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely
23 # to be broken or missing. This strategy is used in the standard library
24 # platform module:
25 # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183
26 try:
27 # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17":
28 _, version = os.confstr("CS_GNU_LIBC_VERSION").split()
29 except (AttributeError, OSError, ValueError):
30 # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)...
31 return None
32 return version
33
34
35 def glibc_version_string_ctypes():
36 # type: () -> Optional[str]
37 "Fallback implementation of glibc_version_string using ctypes."
38
39 try:
40 import ctypes
41 except ImportError:
42 return None
43
44 # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
45 # manpage says, "If filename is NULL, then the returned handle is for the
46 # main program". This way we can let the linker do the work to figure out
47 # which libc our process is actually using.
48 process_namespace = ctypes.CDLL(None)
49 try:
50 gnu_get_libc_version = process_namespace.gnu_get_libc_version
51 except AttributeError:
52 # Symbol doesn't exist -> therefore, we are not linked to
53 # glibc.
54 return None
55
56 # Call gnu_get_libc_version, which returns a string like "2.5"
57 gnu_get_libc_version.restype = ctypes.c_char_p
58 version_str = gnu_get_libc_version()
59 # py2 / py3 compatibility:
60 if not isinstance(version_str, str):
61 version_str = version_str.decode("ascii")
62
63 return version_str
64
65
66 # Separated out from have_compatible_glibc for easier unit testing
67 def check_glibc_version(version_str, required_major, minimum_minor):
68 # type: (str, int, int) -> bool
69 # Parse string and check against requested version.
70 #
71 # We use a regexp instead of str.split because we want to discard any
72 # random junk that might come after the minor version -- this might happen
73 # in patched/forked versions of glibc (e.g. Linaro's version of glibc
74 # uses version strings like "2.20-2014.11"). See gh-3588.
75 m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
76 if not m:
77 warnings.warn("Expected glibc version with 2 components major.minor,"
78 " got: %s" % version_str, RuntimeWarning)
79 return False
80 return (int(m.group("major")) == required_major and
81 int(m.group("minor")) >= minimum_minor)
82
83
84 def have_compatible_glibc(required_major, minimum_minor):
85 # type: (int, int) -> bool
86 version_str = glibc_version_string()
87 if version_str is None:
88 return False
89 return check_glibc_version(version_str, required_major, minimum_minor)
90
91
92 # platform.libc_ver regularly returns completely nonsensical glibc
93 # versions. E.g. on my computer, platform says:
94 #
95 # ~$ python2.7 -c 'import platform; print(platform.libc_ver())'
96 # ('glibc', '2.7')
97 # ~$ python3.5 -c 'import platform; print(platform.libc_ver())'
98 # ('glibc', '2.9')
99 #
100 # But the truth is:
101 #
102 # ~$ ldd --version
103 # ldd (Debian GLIBC 2.22-11) 2.22
104 #
105 # This is unfortunate, because it means that the linehaul data on libc
106 # versions that was generated by pip 8.1.2 and earlier is useless and
107 # misleading. Solution: instead of using platform, use our code that actually
108 # works.
109 def libc_ver():
110 # type: () -> Tuple[str, str]
111 """Try to determine the glibc version
112
113 Returns a tuple of strings (lib, version) which default to empty strings
114 in case the lookup fails.
115 """
116 glibc_version = glibc_version_string()
117 if glibc_version is None:
118 return ("", "")
119 else:
120 return ("glibc", glibc_version)