b'|'
br'(libc(_\w+)?\.so(?:\.(\d[0-9.]*))?)', re.ASCII)
-def libc_ver(executable=sys.executable, lib='', version='', chunksize=16384):
+def libc_ver(executable=None, lib='', version='', chunksize=16384):
""" Tries to determine the libc version that the file executable
(which defaults to the Python interpreter) is linked against.
The file is read and scanned in chunks of chunksize bytes.
"""
+ if executable is None:
+ try:
+ ver = os.confstr('CS_GNU_LIBC_VERSION')
+ # parse 'glibc 2.28' as ('glibc', '2.28')
+ parts = ver.split(maxsplit=1)
+ if len(parts) == 2:
+ return tuple(parts)
+ except (AttributeError, ValueError, OSError):
+ # os.confstr() or CS_GNU_LIBC_VERSION value not available
+ pass
+
+ executable = sys.executable
+
V = _comparable_version
if hasattr(os.path, 'realpath'):
# Python 2.2 introduced os.path.realpath(); it is used
import subprocess
import sys
import sysconfig
+import tempfile
import unittest
+from unittest import mock
from test import support
self.assertEqual(sts, 0)
def test_libc_ver(self):
+ # check that libc_ver(executable) doesn't raise an exception
if os.path.isdir(sys.executable) and \
os.path.exists(sys.executable+'.exe'):
# Cygwin horror
executable = sys.executable + '.exe'
else:
executable = sys.executable
- res = platform.libc_ver(executable)
-
- self.addCleanup(support.unlink, support.TESTFN)
- with open(support.TESTFN, 'wb') as f:
- f.write(b'x'*(16384-10))
+ platform.libc_ver(executable)
+
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+
+ with mock.patch('os.confstr', create=True, return_value='mock 1.0'):
+ # test os.confstr() code path
+ self.assertEqual(platform.libc_ver(), ('mock', '1.0'))
+
+ # test the different regular expressions
+ for data, expected in (
+ (b'__libc_init', ('libc', '')),
+ (b'GLIBC_2.9', ('glibc', '2.9')),
+ (b'libc.so.1.2.5', ('libc', '1.2.5')),
+ (b'libc_pthread.so.1.2.5', ('libc', '1.2.5_pthread')),
+ (b'', ('', '')),
+ ):
+ with open(filename, 'wb') as fp:
+ fp.write(b'[xxx%sxxx]' % data)
+ fp.flush()
+
+ # os.confstr() must not be used if executable is set
+ self.assertEqual(platform.libc_ver(executable=filename),
+ expected)
+
+ # binary containing multiple versions: get the most recent,
+ # make sure that 1.9 is seen as older than 1.23.4
+ chunksize = 16384
+ with open(filename, 'wb') as f:
+ # test match at chunk boundary
+ f.write(b'x'*(chunksize - 10))
f.write(b'GLIBC_1.23.4\0GLIBC_1.9\0GLIBC_1.21\0')
- self.assertEqual(platform.libc_ver(support.TESTFN),
+ self.assertEqual(platform.libc_ver(filename, chunksize=chunksize),
('glibc', '1.23.4'))
@support.cpython_only