When trying to install a package with pip on Windows 10 (Python=3.11.13, pip=25.2, setuptools=80.9.0) via
pip install --no-binary :all: pycryptodome
I get apparently infamous error with not particularly insightful message:
Testing support for clang
Traceback (most recent call last):
File "G:\dev\AIPY\Anaconda\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 389, in <module>
main()
File "G:\dev\AIPY\Anaconda\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 373, in main
json_out["return_val"] = hook(**hook_input["kwargs"])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "G:\dev\AIPY\Anaconda\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py", line 143, in get_requires_for_build_wheel
return hook(config_settings)
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\build_meta.py", line 331, in get_requires_for_build_wheel
return self._get_build_requires(config_settings, requirements=[])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\build_meta.py", line 301, in _get_build_requires
self.run_setup()
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\build_meta.py", line 317, in run_setup
exec(code, locals())
File "<string>", line 497, in <module>
File "C:\Users\pcuser\AppData\Local\Temp\pip-install-jgu9gndw\pycryptodome_de2d839aee6b4295aed8e8f887f27c7f\compiler_opt.py", line 333, in set_compiler_options
clang = compiler_is_clang()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-install-jgu9gndw\pycryptodome_de2d839aee6b4295aed8e8f887f27c7f\compiler_opt.py", line 257, in compiler_is_clang
return test_compilation(source, msg="clang")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-install-jgu9gndw\pycryptodome_de2d839aee6b4295aed8e8f887f27c7f\compiler_opt.py", line 82, in test_compilation
objects = compiler.compile([fname], extra_postargs=extra_cc_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\_distutils\compilers\C\msvc.py", line 384, in compile
self.initialize()
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\_distutils\compilers\C\msvc.py", line 294, in initialize
vc_env = _get_vc_env(plat_spec)
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\pcuser\AppData\Local\Temp\pip-build-env-6vq0slrk\overlay\Lib\site-packages\setuptools\_distutils\compilers\C\msvc.py", line 155, in _get_vc_env
raise DistutilsPlatformError(
distutils.errors.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/
Given that I have recent MSVC Build Tools installed (same shell):
G:\dev\AIPY\Anaconda>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35217 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
the error message does not help at all. No helpful information in Google, similar SO questions, or from Gemini. So what is wrong and how do I fix it?
1 Answer 1
TL;DR
The most robust solution, perhaps, is the not very well documented variable DISTUTILS_USE_SDK=1. If set, it instructs setuptools to use activated (via vcvarsall.bat ) MSVC environment.
Note, see this SO answer regarding installing MS Build Tools, if not already installed.
Detailed Discussion
While the error message itself is not particularly helpful, the trace does provide some initial clues. Given the keywords in the trace, it is reasonable to assume that the associated code is looking for a compiler. Since my interest is in MSVC, the reference to the module
setuptools\_distutils\compilers\C\msvc.py
proved to be the right place to focus on. The stack specifically points to the _get_vc_env() routine, apparently tasked with locating MSVC tools.
The relevant module section:
def _find_vc2015():
try:
key = winreg.OpenKeyEx(
winreg.HKEY_LOCAL_MACHINE,
r"Software\Microsoft\VisualStudio\SxS\VC7",
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY,
)
except OSError:
log.debug("Visual C++ is not registered")
return None, None
best_version = 0
best_dir = None
with key:
for i in count():
try:
v, vc_dir, vt = winreg.EnumValue(key, i)
except OSError:
break
if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
try:
version = int(float(v))
except (ValueError, TypeError):
continue
if version >= 14 and version > best_version:
best_version, best_dir = version, vc_dir
return best_version, best_dir
def _find_vc2017():
"""Returns "15, path" based on the result of invoking vswhere.exe
If no install is found, returns "None, None"
The version is returned to avoid unnecessarily changing the function
result. It may be ignored when the path is not None.
If vswhere.exe is not available, by definition, VS 2017 is not
installed.
"""
root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
if not root:
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
return None, None # no suitable component found
PLAT_SPEC_TO_RUNTIME = {
'x86': 'x86',
'x86_amd64': 'x64',
'x86_arm': 'arm',
'x86_arm64': 'arm64',
}
def _find_vcvarsall(plat_spec):
# bpo-38597: Removed vcruntime return value
_, best_dir = _find_vc2017()
if not best_dir:
best_version, best_dir = _find_vc2015()
if not best_dir:
log.debug("No suitable Visual C++ version found")
return None, None
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
if not os.path.isfile(vcvarsall):
log.debug("%s cannot be found", vcvarsall)
return None, None
return vcvarsall, None
def _get_vc_env(plat_spec):
if os.getenv("DISTUTILS_USE_SDK"):
return {key.lower(): value for key, value in os.environ.items()}
vcvarsall, _ = _find_vcvarsall(plat_spec)
if not vcvarsall:
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/'
)
<IRRELEVANT PART>
return env
The _get_vc_env() routine calls _find_vcvarsall(), which, in turn, calls _find_vc2015() and _find_vc2017(). One of them tries to check a known registry key, the other - default paths. While being reasoable checks, MS Build Tools do not need to be registered at all or installed in the default location. A common use case is by invoking a standard shell setting script vcvarsall.bat, also referenced in this snippet. For this reason, it is striking that this code makes no attempt to check relevant environment variables or availablity of the necessary tools on the Path. In fact, I would argue that this missing check should be done first. The module is clearly deffective. As a temporary fix, I added vcvarsall.bat containing directory to Path in my shell "activation" script and the following lines
if not best_dir:
import shutil
best_dir = os.path.dirname(shutil.which("vcvarsall.bat"))
after _find_vc2015() call in _find_vcvarsall (in the snippet above), resolving the issue.
Comments
Explore related questions
See similar questions with these tags.
msvc.py", line 155, in _get_vc_envand here is source code - maybe this help you understand how it checks if you have installed compiler. You could try to find this file on your disk and add someprint()to see what values are in variables.