Skip to content
49 changes: 37 additions & 12 deletions 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 @@ -178,17 +178,43 @@ def _find_exe(exe, paths=None):
return exe


# A map keyed by get_platform() return values to values accepted by
Comment thread
jaraco marked this conversation as resolved.
# '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'

Always cross-compile from x86 to work with the lighter-weight MSVC
Comment thread
jaraco marked this conversation as resolved.
Outdated
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}'
Comment on lines +181 to +215

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaraco looks like this specific change may have broken cross-compilation (at least in some contexts). See investigation done in pypa/setuptools#4648 (comment)



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 +268,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())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems the bug is in line 276 where it's ignoring the plat_name parameter and instead calling get_platform() again. 👀

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're right, the following is enough of a change:

Suggested change
plat_spec = _get_vcvars_spec(get_host_platform(), get_platform())
plat_spec = _get_vcvars_spec(get_host_platform(), plat_name)


vc_env = _get_vc_env(plat_spec)
if not vc_env:
Expand Down