Path: blob/main/Tools/c-analyzer/distutils/_msvccompiler.py
12 views
"""distutils._msvccompiler12Contains MSVCCompiler, an implementation of the abstract CCompiler class3for Microsoft Visual Studio 2015.45The module is compatible with VS 2015 and later. You can find legacy support6for older versions in distutils.msvc9compiler and distutils.msvccompiler.7"""89# Written by Perry Stoll10# hacked by Robin Becker and Thomas Heller to do a better job of11# finding DevStudio (through the registry)12# ported to VS 2005 and VS 2008 by Christian Heimes13# ported to VS 2015 by Steve Dower1415import os16import subprocess17import winreg1819from distutils.errors import DistutilsPlatformError20from distutils.ccompiler import CCompiler21from distutils import log2223from itertools import count2425def _find_vc2015():26try:27key = winreg.OpenKeyEx(28winreg.HKEY_LOCAL_MACHINE,29r"Software\Microsoft\VisualStudio\SxS\VC7",30access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY31)32except OSError:33log.debug("Visual C++ is not registered")34return None, None3536best_version = 037best_dir = None38with key:39for i in count():40try:41v, vc_dir, vt = winreg.EnumValue(key, i)42except OSError:43break44if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):45try:46version = int(float(v))47except (ValueError, TypeError):48continue49if version >= 14 and version > best_version:50best_version, best_dir = version, vc_dir51return best_version, best_dir5253def _find_vc2017():54"""Returns "15, path" based on the result of invoking vswhere.exe55If no install is found, returns "None, None"5657The version is returned to avoid unnecessarily changing the function58result. It may be ignored when the path is not None.5960If vswhere.exe is not available, by definition, VS 2017 is not61installed.62"""63root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")64if not root:65return None, None6667try:68path = subprocess.check_output([69os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),70"-latest",71"-prerelease",72"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",73"-property", "installationPath",74"-products", "*",75], encoding="mbcs", errors="strict").strip()76except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):77return None, None7879path = os.path.join(path, "VC", "Auxiliary", "Build")80if os.path.isdir(path):81return 15, path8283return None, None8485PLAT_SPEC_TO_RUNTIME = {86'x86' : 'x86',87'x86_amd64' : 'x64',88'x86_arm' : 'arm',89'x86_arm64' : 'arm64'90}9192def _find_vcvarsall(plat_spec):93# bpo-38597: Removed vcruntime return value94_, best_dir = _find_vc2017()9596if not best_dir:97best_version, best_dir = _find_vc2015()9899if not best_dir:100log.debug("No suitable Visual C++ version found")101return None, None102103vcvarsall = os.path.join(best_dir, "vcvarsall.bat")104if not os.path.isfile(vcvarsall):105log.debug("%s cannot be found", vcvarsall)106return None, None107108return vcvarsall, None109110def _get_vc_env(plat_spec):111if os.getenv("DISTUTILS_USE_SDK"):112return {113key.lower(): value114for key, value in os.environ.items()115}116117vcvarsall, _ = _find_vcvarsall(plat_spec)118if not vcvarsall:119raise DistutilsPlatformError("Unable to find vcvarsall.bat")120121try:122out = subprocess.check_output(123'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),124stderr=subprocess.STDOUT,125).decode('utf-16le', errors='replace')126except subprocess.CalledProcessError as exc:127log.error(exc.output)128raise DistutilsPlatformError("Error executing {}"129.format(exc.cmd))130131env = {132key.lower(): value133for key, _, value in134(line.partition('=') for line in out.splitlines())135if key and value136}137138return env139140def _find_exe(exe, paths=None):141"""Return path to an MSVC executable program.142143Tries to find the program in several places: first, one of the144MSVC program search paths from the registry; next, the directories145in the PATH environment variable. If any of those work, return an146absolute path that is known to exist. If none of them work, just147return the original program name, 'exe'.148"""149if not paths:150paths = os.getenv('path').split(os.pathsep)151for p in paths:152fn = os.path.join(os.path.abspath(p), exe)153if os.path.isfile(fn):154return fn155return exe156157# A map keyed by get_platform() return values to values accepted by158# 'vcvarsall.bat'. Always cross-compile from x86 to work with the159# lighter-weight MSVC installs that do not include native 64-bit tools.160PLAT_TO_VCVARS = {161'win32' : 'x86',162'win-amd64' : 'x86_amd64',163'win-arm32' : 'x86_arm',164'win-arm64' : 'x86_arm64'165}166167class MSVCCompiler(CCompiler) :168"""Concrete class that implements an interface to Microsoft Visual C++,169as defined by the CCompiler abstract class."""170171compiler_type = 'msvc'172173# Just set this so CCompiler's constructor doesn't barf. We currently174# don't use the 'set_executables()' bureaucracy provided by CCompiler,175# as it really isn't necessary for this sort of single-compiler class.176# Would be nice to have a consistent interface with UnixCCompiler,177# though, so it's worth thinking about.178executables = {}179180# Private class data (need to distinguish C from C++ source for compiler)181_c_extensions = ['.c']182_cpp_extensions = ['.cc', '.cpp', '.cxx']183_rc_extensions = ['.rc']184_mc_extensions = ['.mc']185186# Needed for the filename generation methods provided by the187# base class, CCompiler.188src_extensions = (_c_extensions + _cpp_extensions +189_rc_extensions + _mc_extensions)190res_extension = '.res'191obj_extension = '.obj'192static_lib_extension = '.lib'193shared_lib_extension = '.dll'194static_lib_format = shared_lib_format = '%s%s'195exe_extension = '.exe'196197198def __init__(self, verbose=0, dry_run=0, force=0):199CCompiler.__init__ (self, verbose, dry_run, force)200# target platform (.plat_name is consistent with 'bdist')201self.plat_name = None202self.initialized = False203204205