diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b6b757db..5f104963 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -114,6 +114,7 @@ jobs: python${{ matrix.python }}-tox, gcc-core, gcc-g++, + zlib-devel, ncompress git - name: Run tests diff --git a/distutils/command/check.py b/distutils/command/check.py index 58b3f949..2eb72b45 100644 --- a/distutils/command/check.py +++ b/distutils/command/check.py @@ -144,7 +144,7 @@ def _check_rst_data(self, data): document.note_source(source_path, -1) try: parser.parse(data, document) - except AttributeError as e: + except (AttributeError, TypeError) as e: reporter.messages.append(( -1, f'Could not finish the parsing: {e}.', diff --git a/distutils/compat/py38.py b/distutils/compat/py38.py index 2d442111..03ec73ef 100644 --- a/distutils/compat/py38.py +++ b/distutils/compat/py38.py @@ -14,6 +14,7 @@ def removeprefix(self, prefix): return self[len(prefix) :] else: return self[:] + else: def removesuffix(self, suffix): diff --git a/distutils/tests/test_build_ext.py b/distutils/tests/test_build_ext.py index 6c4c4ba8..f88d216c 100644 --- a/distutils/tests/test_build_ext.py +++ b/distutils/tests/test_build_ext.py @@ -1,13 +1,16 @@ import contextlib +import glob import importlib -import os +import os.path import platform import re import shutil import site +import subprocess import sys import tempfile import textwrap +import time from distutils import sysconfig from distutils.command.build_ext import build_ext from distutils.core import Distribution @@ -55,6 +58,9 @@ def user_site_dir(request): site.USER_BASE = orig_user_base build_ext.USER_BASE = orig_user_base + if sys.platform == 'cygwin': + time.sleep(1) + @contextlib.contextmanager def safe_extension_import(name, path): @@ -90,11 +96,35 @@ class TestBuildExt(TempdirManager): def build_ext(self, *args, **kwargs): return build_ext(*args, **kwargs) - def test_build_ext(self): + @pytest.mark.parametrize("copy_so", [False]) + def test_build_ext(self, copy_so): missing_compiler_executable() copy_xxmodule_c(self.tmp_dir) xx_c = os.path.join(self.tmp_dir, 'xxmodule.c') xx_ext = Extension('xx', [xx_c]) + if sys.platform != "win32": + if not copy_so: + xx_ext = Extension( + 'xx', + [xx_c], + library_dirs=['/usr/lib'], + libraries=['z'], + runtime_library_dirs=['/usr/lib'], + ) + elif sys.platform == 'linux': + libz_so = { + os.path.realpath(name) for name in glob.iglob('/usr/lib*/libz.so*') + } + libz_so = sorted(libz_so, key=lambda lib_path: len(lib_path)) + shutil.copyfile(libz_so[-1], '/tmp/libxx_z.so') + + xx_ext = Extension( + 'xx', + [xx_c], + library_dirs=['/tmp'], + libraries=['xx_z'], + runtime_library_dirs=['/tmp'], + ) dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]}) dist.package_dir = self.tmp_dir cmd = self.build_ext(dist) @@ -113,10 +143,13 @@ def test_build_ext(self): sys.stdout = old_stdout with safe_extension_import('xx', self.tmp_dir): - self._test_xx() + self._test_xx(copy_so) + + if sys.platform == 'linux' and copy_so: + os.unlink('/tmp/libxx_z.so') @staticmethod - def _test_xx(): + def _test_xx(copy_so): import xx for attr in ('error', 'foo', 'new', 'roj'): @@ -131,6 +164,28 @@ def _test_xx(): assert isinstance(xx.Null(), xx.Null) assert isinstance(xx.Str(), xx.Str) + if sys.platform == 'linux': + so_headers = subprocess.check_output( + ["readelf", "-d", xx.__file__], universal_newlines=True + ) + import pprint + + pprint.pprint(so_headers) + rpaths = [ + rpath + for line in so_headers.split("\n") + if "RPATH" in line or "RUNPATH" in line + for rpath in line.split()[2][1:-1].split(":") + ] + if not copy_so: + pprint.pprint(rpaths) + # Linked against a library in /usr/lib{,64} + assert "/usr/lib" not in rpaths and "/usr/lib64" not in rpaths + else: + # Linked against a library in /tmp + assert "/tmp" in rpaths + # The import is the real test here + def test_solaris_enable_shared(self): dist = Distribution({'name': 'xx'}) cmd = self.build_ext(dist) diff --git a/distutils/unixccompiler.py b/distutils/unixccompiler.py index 7e68596b..b04359a5 100644 --- a/distutils/unixccompiler.py +++ b/distutils/unixccompiler.py @@ -148,6 +148,20 @@ class UnixCCompiler(CCompiler): dylib_lib_extension = ".dll" dylib_lib_format = "cyg%s%s" + def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): + """Remove standard library path from rpath""" + libraries, library_dirs, runtime_library_dirs = super()._fix_lib_args( + libraries, library_dirs, runtime_library_dirs + ) + libdir = sysconfig.get_config_var('LIBDIR') + if ( + runtime_library_dirs + and libdir.startswith("/usr/lib") + and (libdir in runtime_library_dirs) + ): + runtime_library_dirs.remove(libdir) + return libraries, library_dirs, runtime_library_dirs + def preprocess( self, source,