diff --git a/setuptools/_distutils/compat/__init__.py b/setuptools/_distutils/compat/__init__.py new file mode 100644 index 0000000000..b1ee3fe8b0 --- /dev/null +++ b/setuptools/_distutils/compat/__init__.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from .py38 import removeprefix + + +def consolidate_linker_args(args: list[str]) -> str: + """ + Ensure the return value is a string for backward compatibility. + + Retain until at least 2024-04-31. See pypa/distutils#246 + """ + + if not all(arg.startswith('-Wl,') for arg in args): + return args + return '-Wl,' + ','.join(removeprefix(arg, '-Wl,') for arg in args) diff --git a/setuptools/_distutils/compat/py38.py b/setuptools/_distutils/compat/py38.py new file mode 100644 index 0000000000..0af3814017 --- /dev/null +++ b/setuptools/_distutils/compat/py38.py @@ -0,0 +1,23 @@ +import sys + +if sys.version_info < (3, 9): + + def removesuffix(self, suffix): + # suffix='' should not call self[:-0]. + if suffix and self.endswith(suffix): + return self[: -len(suffix)] + else: + return self[:] + + def removeprefix(self, prefix): + if self.startswith(prefix): + return self[len(prefix) :] + else: + return self[:] +else: + + def removesuffix(self, suffix): + return self.removesuffix(suffix) + + def removeprefix(self, prefix): + return self.removeprefix(prefix) diff --git a/setuptools/_distutils/dir_util.py b/setuptools/_distutils/dir_util.py index 2021bed82e..370c6ffd49 100644 --- a/setuptools/_distutils/dir_util.py +++ b/setuptools/_distutils/dir_util.py @@ -94,9 +94,7 @@ def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0): 'dry_run' flags are as for 'mkpath()'. """ # First get the list of directories to create - need_dir = set() - for file in files: - need_dir.add(os.path.join(base_dir, os.path.dirname(file))) + need_dir = set(os.path.join(base_dir, os.path.dirname(file)) for file in files) # Now create them for dir in sorted(need_dir): diff --git a/setuptools/_distutils/dist.py b/setuptools/_distutils/dist.py index f29a34faba..668ce7eb0a 100644 --- a/setuptools/_distutils/dist.py +++ b/setuptools/_distutils/dist.py @@ -647,7 +647,7 @@ def _show_help( options = self.global_options parser.set_option_table(options) parser.print_help(self.common_usage + "\nGlobal options:") - print('') + print() if display_options: parser.set_option_table(self.display_options) @@ -655,7 +655,7 @@ def _show_help( "Information display options (just display " + "information, ignore any commands)" ) - print('') + print() for command in self.commands: if isinstance(command, type) and issubclass(command, Command): @@ -669,7 +669,7 @@ def _show_help( else: parser.set_option_table(klass.user_options) parser.print_help("Options for '%s' command:" % klass.__name__) - print('') + print() print(gen_usage(self.script_name)) @@ -686,7 +686,7 @@ def handle_display_options(self, option_order): # we ignore "foo bar"). if self.help_commands: self.print_commands() - print('') + print() print(gen_usage(self.script_name)) return 1 diff --git a/setuptools/_distutils/tests/test_msvc9compiler.py b/setuptools/_distutils/tests/test_msvc9compiler.py index 58e24f017a..6f6aabee4d 100644 --- a/setuptools/_distutils/tests/test_msvc9compiler.py +++ b/setuptools/_distutils/tests/test_msvc9compiler.py @@ -161,7 +161,7 @@ def test_remove_visual_c_ref(self): f = open(manifest) try: # removing trailing spaces - content = '\n'.join([line.rstrip() for line in f.readlines()]) + content = '\n'.join([line.rstrip() for line in f]) finally: f.close() diff --git a/setuptools/_distutils/tests/test_unixccompiler.py b/setuptools/_distutils/tests/test_unixccompiler.py index f17edf2f6b..6f05fa6989 100644 --- a/setuptools/_distutils/tests/test_unixccompiler.py +++ b/setuptools/_distutils/tests/test_unixccompiler.py @@ -4,6 +4,7 @@ import sys import unittest.mock as mock from distutils import sysconfig +from distutils.compat import consolidate_linker_args from distutils.errors import DistutilsPlatformError from distutils.unixccompiler import UnixCCompiler from distutils.util import _clear_cached_macosx_ver @@ -149,10 +150,10 @@ def gcv(v): return 'yes' sysconfig.get_config_var = gcv - assert self.cc.rpath_foo() == [ + assert self.cc.rpath_foo() == consolidate_linker_args([ '-Wl,--enable-new-dtags', '-Wl,-rpath,/foo', - ] + ]) def gcv(v): if v == 'CC': @@ -161,10 +162,10 @@ def gcv(v): return 'yes' sysconfig.get_config_var = gcv - assert self.cc.rpath_foo() == [ + assert self.cc.rpath_foo() == consolidate_linker_args([ '-Wl,--enable-new-dtags', '-Wl,-rpath,/foo', - ] + ]) # GCC non-GNULD sys.platform = 'bar' @@ -189,10 +190,10 @@ def gcv(v): return 'yes' sysconfig.get_config_var = gcv - assert self.cc.rpath_foo() == [ + assert self.cc.rpath_foo() == consolidate_linker_args([ '-Wl,--enable-new-dtags', '-Wl,-rpath,/foo', - ] + ]) # non-GCC GNULD sys.platform = 'bar' @@ -204,10 +205,10 @@ def gcv(v): return 'yes' sysconfig.get_config_var = gcv - assert self.cc.rpath_foo() == [ + assert self.cc.rpath_foo() == consolidate_linker_args([ '-Wl,--enable-new-dtags', '-Wl,-rpath,/foo', - ] + ]) # non-GCC non-GNULD sys.platform = 'bar' diff --git a/setuptools/_distutils/unixccompiler.py b/setuptools/_distutils/unixccompiler.py index a1fe2b57a2..0248bde87b 100644 --- a/setuptools/_distutils/unixccompiler.py +++ b/setuptools/_distutils/unixccompiler.py @@ -13,6 +13,8 @@ * link shared library handled by 'cc -shared' """ +from __future__ import annotations + import itertools import os import re @@ -20,6 +22,7 @@ import sys from . import sysconfig +from .compat import consolidate_linker_args from ._log import log from ._macos_compat import compiler_fixup from ._modified import newer @@ -281,7 +284,7 @@ def _is_gcc(self): compiler = os.path.basename(shlex.split(cc_var)[0]) return "gcc" in compiler or "g++" in compiler - def runtime_library_dir_option(self, dir): + def runtime_library_dir_option(self, dir: str) -> str | list[str]: # XXX Hackish, at the very least. See Python bug #445902: # https://bugs.python.org/issue445902 # Linkers on different platforms need different options to @@ -313,11 +316,11 @@ def runtime_library_dir_option(self, dir): # For all compilers, `-Wl` is the presumed way to pass a # compiler option to the linker if sysconfig.get_config_var("GNULD") == "yes": - return [ + return consolidate_linker_args([ # Force RUNPATH instead of RPATH "-Wl,--enable-new-dtags", "-Wl,-rpath," + dir, - ] + ]) else: return "-Wl,-R" + dir @@ -389,10 +392,7 @@ def find_library_file(self, dirs, lib, debug=0): roots = map(self._library_root, dirs) - searched = ( - os.path.join(root, lib_name) - for root, lib_name in itertools.product(roots, lib_names) - ) + searched = itertools.starmap(os.path.join, itertools.product(roots, lib_names)) found = filter(os.path.exists, searched)