Skip to content

Commit

Permalink
Merge pull request #4606 from pypa/distutils-58fe058e4
Browse files Browse the repository at this point in the history
Merge with distutils@58fe058e4
  • Loading branch information
jaraco authored Aug 27, 2024
2 parents 903604b + 30311bd commit 11a6b59
Show file tree
Hide file tree
Showing 23 changed files with 96 additions and 1,763 deletions.
1 change: 1 addition & 0 deletions newsfragments/4606.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Synced with pypa/distutils@58fe058e4, including consolidating Visual Studio 2017 support (#4600, pypa/distutils#289), removal of deprecated legacy MSVC compiler modules (pypa/distutils#287), suppressing of errors when the home directory is missing (pypa/distutils#278), removal of wininst binaries (pypa/distutils#282).
111 changes: 74 additions & 37 deletions setuptools/_distutils/_msvccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
LibError,
LinkError,
)
from .util import get_platform
from .util import get_host_platform, get_platform


def _find_vc2015():
Expand Down Expand Up @@ -79,32 +79,40 @@ def _find_vc2017():
if not root:
return None, None

try:
path = subprocess.check_output(
[
os.path.join(
root, "Microsoft Visual Studio", "Installer", "vswhere.exe"
),
"-latest",
"-prerelease",
"-requires",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"-property",
"installationPath",
"-products",
"*",
],
encoding="mbcs",
errors="strict",
).strip()
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
return None, None
variant = 'arm64' if get_platform() == 'win-arm64' else 'x86.x64'
suitable_components = (
f"Microsoft.VisualStudio.Component.VC.Tools.{variant}",
"Microsoft.VisualStudio.Workload.WDExpress",
)

for component in suitable_components:
# Workaround for `-requiresAny` (only available on VS 2017 > 15.6)
with contextlib.suppress(
subprocess.CalledProcessError, OSError, UnicodeDecodeError
):
path = (
subprocess.check_output([
os.path.join(
root, "Microsoft Visual Studio", "Installer", "vswhere.exe"
),
"-latest",
"-prerelease",
"-requires",
component,
"-property",
"installationPath",
"-products",
"*",
])
.decode(encoding="mbcs", errors="strict")
.strip()
)

path = os.path.join(path, "VC", "Auxiliary", "Build")
if os.path.isdir(path):
return 15, path
path = os.path.join(path, "VC", "Auxiliary", "Build")
if os.path.isdir(path):
return 15, path

return None, None
return None, None # no suitable component found


PLAT_SPEC_TO_RUNTIME = {
Expand Down Expand Up @@ -140,7 +148,11 @@ def _get_vc_env(plat_spec):

vcvarsall, _ = _find_vcvarsall(plat_spec)
if not vcvarsall:
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
raise DistutilsPlatformError(
'Microsoft Visual C++ 14.0 or greater is required. '
'Get it with "Microsoft C++ Build Tools": '
'https://visualstudio.microsoft.com/visual-cpp-build-tools/'
)

try:
out = subprocess.check_output(
Expand Down Expand Up @@ -178,17 +190,43 @@ def _find_exe(exe, paths=None):
return exe


# A map keyed by get_platform() return values to values accepted by
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
# lighter-weight MSVC installs that do not include native 64-bit tools.
PLAT_TO_VCVARS = {
_vcvars_names = {
'win32': 'x86',
'win-amd64': 'x86_amd64',
'win-arm32': 'x86_arm',
'win-arm64': 'x86_arm64',
'win-amd64': 'amd64',
'win-arm32': 'arm',
'win-arm64': 'arm64',
}


def _get_vcvars_spec(host_platform, platform):
"""
Given a host platform and platform, determine the spec for vcvarsall.
Uses the native MSVC host if the host platform would need expensive
emulation for x86.
>>> _get_vcvars_spec('win-arm64', 'win32')
'arm64_x86'
>>> _get_vcvars_spec('win-arm64', 'win-amd64')
'arm64_amd64'
Otherwise, always cross-compile from x86 to work with the
lighter-weight MSVC installs that do not include native 64-bit tools.
>>> _get_vcvars_spec('win32', 'win32')
'x86'
>>> _get_vcvars_spec('win-arm32', 'win-arm32')
'x86_arm'
>>> _get_vcvars_spec('win-amd64', 'win-arm64')
'x86_arm64'
"""
if host_platform != 'win-arm64':
host_platform = 'win32'
vc_hp = _vcvars_names[host_platform]
vc_plat = _vcvars_names[platform]
return vc_hp if vc_hp == vc_plat else f'{vc_hp}_{vc_plat}'


class MSVCCompiler(CCompiler):
"""Concrete class that implements an interface to Microsoft Visual C++,
as defined by the CCompiler abstract class."""
Expand Down Expand Up @@ -242,13 +280,12 @@ def initialize(self, plat_name=None):
if plat_name is None:
plat_name = get_platform()
# sanity check for platforms to prevent obscure errors later.
if plat_name not in PLAT_TO_VCVARS:
if plat_name not in _vcvars_names:
raise DistutilsPlatformError(
f"--plat-name must be one of {tuple(PLAT_TO_VCVARS)}"
f"--plat-name must be one of {tuple(_vcvars_names)}"
)

# Get the vcvarsall.bat spec for the requested platform.
plat_spec = PLAT_TO_VCVARS[plat_name]
plat_spec = _get_vcvars_spec(get_host_platform(), get_platform())

vc_env = _get_vc_env(plat_spec)
if not vc_env:
Expand Down
3 changes: 1 addition & 2 deletions setuptools/_distutils/archive_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,7 @@ def make_archive(
raise ValueError(f"unknown archive format '{format}'")

func = format_info[0]
for arg, val in format_info[1]:
kwargs[arg] = val
kwargs.update(format_info[1])

if format != 'zip':
kwargs['owner'] = owner
Expand Down
3 changes: 1 addition & 2 deletions setuptools/_distutils/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,7 @@ def swig_sources(self, sources, extension):

# Do not override commandline arguments
if not self.swig_opts:
for o in extension.swig_opts:
swig_cmd.append(o)
swig_cmd.extend(extension.swig_opts)

for source in swig_sources:
target = swig_targets[source]
Expand Down
2 changes: 1 addition & 1 deletion setuptools/_distutils/command/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def create_home_path(self):
if not self.user:
return
home = convert_path(os.path.expanduser("~"))
for _name, path in self.config_vars.items():
for path in self.config_vars.values():
if str(path).startswith(home) and not os.path.isdir(path):
self.debug_print(f"os.makedirs('{path}', 0o700)")
os.makedirs(path, 0o700)
Expand Down
6 changes: 3 additions & 3 deletions setuptools/_distutils/command/install_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ def finalize_options(self):
if not isinstance(self.optimize, int):
try:
self.optimize = int(self.optimize)
if self.optimize not in (0, 1, 2):
raise AssertionError
except (ValueError, AssertionError):
except ValueError:
pass
if self.optimize not in (0, 1, 2):
raise DistutilsOptionError("optimize must be 0, 1, or 2")

def run(self):
Expand Down
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-10.0.exe
Binary file not shown.
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-14.0.exe
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-6.0.exe
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-7.1.exe
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-8.0.exe
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-9.0-amd64.exe
Binary file not shown.
Binary file removed setuptools/_distutils/command/wininst-9.0.exe
Binary file not shown.
8 changes: 4 additions & 4 deletions setuptools/_distutils/cygwinccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,7 @@ def link(

# Generate .def file
contents = [f"LIBRARY {os.path.basename(output_filename)}", "EXPORTS"]
for sym in export_symbols:
contents.append(sym)
contents.extend(export_symbols)
self.execute(write_file, (def_file, contents), f"writing {def_file}")

# next add options for def-file
Expand Down Expand Up @@ -309,6 +308,9 @@ def check_config_h():
fn = sysconfig.get_config_h_filename()
try:
config_h = pathlib.Path(fn).read_text(encoding='utf-8')
except OSError as exc:
return (CONFIG_H_UNCERTAIN, f"couldn't read '{fn}': {exc.strerror}")
else:
substring = '__GNUC__'
if substring in config_h:
code = CONFIG_H_OK
Expand All @@ -317,8 +319,6 @@ def check_config_h():
code = CONFIG_H_NOTOK
mention_inflected = 'does not mention'
return code, f"{fn!r} {mention_inflected} {substring!r}"
except OSError as exc:
return (CONFIG_H_UNCERTAIN, f"couldn't read '{fn}': {exc.strerror}")


def is_cygwincc(cc):
Expand Down
25 changes: 7 additions & 18 deletions setuptools/_distutils/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,12 @@
import pathlib
import re
import sys
import warnings
from collections.abc import Iterable
from email import message_from_file

from ._vendor.packaging.utils import canonicalize_name, canonicalize_version

try:
import warnings
except ImportError:
warnings = None

from ._log import log
from ._vendor.packaging.utils import canonicalize_name, canonicalize_version
from .debug import DEBUG
from .errors import (
DistutilsArgError,
Expand Down Expand Up @@ -249,10 +244,7 @@ def __init__(self, attrs=None): # noqa: C901
attrs['license'] = attrs['licence']
del attrs['licence']
msg = "'licence' distribution option is deprecated; use 'license'"
if warnings is not None:
warnings.warn(msg)
else:
sys.stderr.write(msg + "\n")
warnings.warn(msg)

# Now work on the rest of the attributes. Any attribute that's
# not already defined is invalid!
Expand Down Expand Up @@ -354,7 +346,8 @@ def _gen_paths(self):
prefix = '.' * (os.name == 'posix')
filename = prefix + 'pydistutils.cfg'
if self.want_user_cfg:
yield pathlib.Path('~').expanduser() / filename
with contextlib.suppress(RuntimeError):
yield pathlib.Path('~').expanduser() / filename

# All platforms support local setup.cfg
yield pathlib.Path('setup.cfg')
Expand Down Expand Up @@ -741,9 +734,7 @@ def print_commands(self):
import distutils.command

std_commands = distutils.command.__all__
is_std = set()
for cmd in std_commands:
is_std.add(cmd)
is_std = set(std_commands)

extra_commands = [cmd for cmd in self.cmdclass.keys() if cmd not in is_std]

Expand All @@ -769,9 +760,7 @@ def get_command_list(self):
import distutils.command

std_commands = distutils.command.__all__
is_std = set()
for cmd in std_commands:
is_std.add(cmd)
is_std = set(std_commands)

extra_commands = [cmd for cmd in self.cmdclass.keys() if cmd not in is_std]

Expand Down
2 changes: 1 addition & 1 deletion setuptools/_distutils/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def __init__(
**kw, # To catch unknown keywords
):
if not isinstance(name, str):
raise AssertionError("'name' must be a string")
raise AssertionError("'name' must be a string") # noqa: TRY004
if not (
isinstance(sources, list)
and all(isinstance(v, (str, os.PathLike)) for v in sources)
Expand Down
3 changes: 2 additions & 1 deletion setuptools/_distutils/file_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,13 @@ def copy_file( # noqa: C901
if not (os.path.exists(dst) and os.path.samefile(src, dst)):
try:
os.link(src, dst)
return (dst, 1)
except OSError:
# If hard linking fails, fall back on copying file
# (some special filesystems don't support hard linking
# even under Unix, see issue #8876).
pass
else:
return (dst, 1)
elif link == 'sym':
if not (os.path.exists(dst) and os.path.samefile(src, dst)):
os.symlink(src, dst)
Expand Down
Loading

0 comments on commit 11a6b59

Please sign in to comment.