bpo-26544: Fixed implementation of platform.libc_ver(). (GH-7684). (GH-8193) (GH-8196)
(cherry picked from commit 2a9b8babf0d09946ebebfdb2931cc0d3db5a1d3d).
(cherry picked from commit 7c43b801503c802ed6ea4b811f5bc73791249d94)
diff --git a/Lib/platform.py b/Lib/platform.py
index 55f2fa8..44a612b 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -140,9 +140,7 @@
'|'
'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)')
-def libc_ver(executable=sys.executable,lib='',version='',
-
- chunksize=2048):
+def libc_ver(executable=sys.executable,lib='',version='', chunksize=2048):
""" Tries to determine the libc version that the file executable
(which defaults to the Python interpreter) is linked against.
@@ -157,40 +155,42 @@
The file is read and scanned in chunks of chunksize bytes.
"""
+ from distutils.version import LooseVersion as V
if hasattr(os.path, 'realpath'):
# Python 2.2 introduced os.path.realpath(); it is used
# here to work around problems with Cygwin not being
# able to open symlinks for reading
executable = os.path.realpath(executable)
- f = open(executable,'rb')
- binary = f.read(chunksize)
- pos = 0
- while 1:
- m = _libc_search.search(binary,pos)
- if not m:
- binary = f.read(chunksize)
- if not binary:
- break
- pos = 0
- continue
- libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
- if libcinit and not lib:
- lib = 'libc'
- elif glibc:
- if lib != 'glibc':
- lib = 'glibc'
- version = glibcversion
- elif glibcversion > version:
- version = glibcversion
- elif so:
- if lib != 'glibc':
+ with open(executable, 'rb') as f:
+ binary = f.read(chunksize)
+ pos = 0
+ while pos < len(binary):
+ m = _libc_search.search(binary,pos)
+ if not m or m.end() == len(binary):
+ chunk = f.read(chunksize)
+ if chunk:
+ binary = binary[max(pos, len(binary) - 1000):] + chunk
+ pos = 0
+ continue
+ if not m:
+ break
+ libcinit,glibc,glibcversion,so,threads,soversion = m.groups()
+ if libcinit and not lib:
lib = 'libc'
- if soversion and soversion > version:
- version = soversion
- if threads and version[-len(threads):] != threads:
- version = version + threads
- pos = m.end()
- f.close()
+ elif glibc:
+ if lib != 'glibc':
+ lib = 'glibc'
+ version = glibcversion
+ elif V(glibcversion) > V(version):
+ version = glibcversion
+ elif so:
+ if lib != 'glibc':
+ lib = 'libc'
+ if soversion and (not version or V(soversion) > V(version)):
+ version = soversion
+ if threads and version[-len(threads):] != threads:
+ version = version + threads
+ pos = m.end()
return lib,version
def _dist_try_harder(distname,version,id):
@@ -451,6 +451,7 @@
else:
return popen(cmd,mode,bufsize)
+
def _norm_version(version, build=''):
""" Normalize the version and build strings and return a single