Tries to determine the libc version that the file executable (which defaults to the Python interpreter) is linked against. Returns a tuple of strings (lib,version) which default to the given parameters in case the lookup fails. Note that the function has intimate k
(executable=None, lib='', version='', chunksize=16384)
| 156 | |
| 157 | |
| 158 | def libc_ver(executable=None, lib='', version='', chunksize=16384): |
| 159 | |
| 160 | """ Tries to determine the libc version that the file executable |
| 161 | (which defaults to the Python interpreter) is linked against. |
| 162 | |
| 163 | Returns a tuple of strings (lib,version) which default to the |
| 164 | given parameters in case the lookup fails. |
| 165 | |
| 166 | Note that the function has intimate knowledge of how different |
| 167 | libc versions add symbols to the executable and thus is probably |
| 168 | only usable for executables compiled using gcc. |
| 169 | |
| 170 | The file is read and scanned in chunks of chunksize bytes. |
| 171 | |
| 172 | """ |
| 173 | if not executable: |
| 174 | if sys.platform == "emscripten": |
| 175 | # Emscripten's os.confstr reports that it is glibc, so special case |
| 176 | # it. |
| 177 | ver = ".".join(str(x) for x in sys._emscripten_info.emscripten_version) |
| 178 | return ("emscripten", ver) |
| 179 | try: |
| 180 | ver = os.confstr('CS_GNU_LIBC_VERSION') |
| 181 | # parse 'glibc 2.28' as ('glibc', '2.28') |
| 182 | parts = ver.split(maxsplit=1) |
| 183 | if len(parts) == 2: |
| 184 | return tuple(parts) |
| 185 | except (AttributeError, ValueError, OSError): |
| 186 | # os.confstr() or CS_GNU_LIBC_VERSION value not available |
| 187 | pass |
| 188 | |
| 189 | executable = sys.executable |
| 190 | |
| 191 | if not executable: |
| 192 | # sys.executable is not set. |
| 193 | return lib, version |
| 194 | |
| 195 | libc_search = re.compile(br""" |
| 196 | (__libc_init) |
| 197 | | (GLIBC_([0-9.]+)) |
| 198 | | (libc(_\w+)?\.so(?:\.(\d[0-9.]*))?) |
| 199 | | (musl-([0-9.]+)) |
| 200 | | ((?:libc\.|ld-)musl(?:-\w+)?.so(?:\.(\d[0-9.]*))?) |
| 201 | """, |
| 202 | re.ASCII | re.VERBOSE) |
| 203 | |
| 204 | V = _comparable_version |
| 205 | # We use os.path.realpath() |
| 206 | # here to work around problems with Cygwin not being |
| 207 | # able to open symlinks for reading |
| 208 | executable = os.path.realpath(executable) |
| 209 | ver = None |
| 210 | with open(executable, 'rb') as f: |
| 211 | binary = f.read(chunksize) |
| 212 | pos = 0 |
| 213 | while pos < len(binary): |
| 214 | if b'libc' in binary or b'GLIBC' in binary or b'musl' in binary: |
| 215 | m = libc_search.search(binary, pos) |
no test coverage detected
searching dependent graphs…