cpython: b2ee6206fa5e (original) (raw)
copy from Lib/distutils/msvccompiler.py copy to Lib/distutils/_msvccompiler.py --- a/Lib/distutils/msvccompiler.py +++ b/Lib/distutils/_msvccompiler.py @@ -1,201 +1,120 @@ -"""distutils.msvccompiler +"""distutils._msvccompiler Contains MSVCCompiler, an implementation of the abstract CCompiler class -for the Microsoft Visual Studio. +for Microsoft Visual Studio 2015. + +The module is compatible with VS 2015 and later. You can find legacy support +for older versions in distutils.msvc9compiler and distutils.msvccompiler. """
Written by Perry Stoll
hacked by Robin Becker and Thomas Heller to do a better job of
finding DevStudio (through the registry)
- -import sys, os -from distutils.errors import [](#l1.22)
DistutilsExecError, DistutilsPlatformError, \[](#l1.23)
CompileError, LibError, LinkError[](#l1.24)
-from distutils.ccompiler import [](#l1.25)
CCompiler, gen_preprocess_options, gen_lib_options[](#l1.26)
-from distutils import log +# ported to VS 2005 and VS 2008 by Christian Heimes +# ported to VS 2015 by Steve Dower -_can_read_reg = False -try:
- RegOpenKeyEx = winreg.OpenKeyEx
- RegEnumKey = winreg.EnumKey
- RegEnumValue = winreg.EnumValue
- RegError = winreg.error
+import os +import subprocess +import re -except ImportError:
- try:
import win32api[](#l1.48)
import win32con[](#l1.49)
_can_read_reg = True[](#l1.50)
hkey_mod = win32con[](#l1.51)
+from distutils.errors import DistutilsExecError, DistutilsPlatformError, [](#l1.52)
CompileError, LibError, LinkError[](#l1.53)
+from distutils.ccompiler import CCompiler, gen_lib_options +from distutils import log +from distutils.util import get_platform
RegOpenKeyEx = win32api.RegOpenKeyEx[](#l1.58)
RegEnumKey = win32api.RegEnumKey[](#l1.59)
RegEnumValue = win32api.RegEnumValue[](#l1.60)
RegError = win32api.error[](#l1.61)
- except ImportError:
log.info("Warning: Can't read registry to find the "[](#l1.63)
"necessary compiler setting\n"[](#l1.64)
"Make sure that Python modules winreg, "[](#l1.65)
"win32api or win32con are installed.")[](#l1.66)
pass[](#l1.67)
- HKEYS = (hkey_mod.HKEY_USERS,
hkey_mod.HKEY_CURRENT_USER,[](#l1.71)
hkey_mod.HKEY_LOCAL_MACHINE,[](#l1.72)
hkey_mod.HKEY_CLASSES_ROOT)[](#l1.73)
+import winreg +from itertools import count -def read_keys(base, key):
- """Return list of registry keys."""
- try:
handle = RegOpenKeyEx(base, key)[](#l1.80)
- except RegError:
return None[](#l1.82)
- L = []
- i = 0
- while True:
try:[](#l1.86)
k = RegEnumKey(handle, i)[](#l1.87)
except RegError:[](#l1.88)
break[](#l1.89)
L.append(k)[](#l1.90)
i += 1[](#l1.91)
- return L
- -def read_values(base, key):
- with winreg.OpenKeyEx(
winreg.HKEY_LOCAL_MACHINE,[](#l1.98)
r"Software\Microsoft\VisualStudio\SxS\VC7",[](#l1.99)
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY[](#l1.100)
- ) as key:
if not key:[](#l1.102)
log.debug("Visual C++ is not registered")[](#l1.103)
return None[](#l1.104)
- All names are converted to lowercase.
- """
- try:
handle = RegOpenKeyEx(base, key)[](#l1.109)
- except RegError:
return None[](#l1.111)
- d = {}
- i = 0
- while True:
try:[](#l1.115)
name, value, type = RegEnumValue(handle, i)[](#l1.116)
except RegError:[](#l1.117)
break[](#l1.118)
name = name.lower()[](#l1.119)
d[convert_mbcs(name)] = convert_mbcs(value)[](#l1.120)
i += 1[](#l1.121)
- return d
best_version = 0[](#l1.123)
best_dir = None[](#l1.124)
for i in count():[](#l1.125)
try:[](#l1.126)
v, vc_dir, vt = winreg.EnumValue(key, i)[](#l1.127)
except OSError:[](#l1.128)
break[](#l1.129)
if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):[](#l1.130)
try:[](#l1.131)
version = int(float(v))[](#l1.132)
except (ValueError, TypeError):[](#l1.133)
continue[](#l1.134)
if version >= 14 and version > best_version:[](#l1.135)
best_version, best_dir = version, vc_dir[](#l1.136)
if not best_version:[](#l1.137)
log.debug("No suitable Visual C++ version found")[](#l1.138)
return None[](#l1.139)
- dec = getattr(s, "decode", None)
- if dec is not None:
try:[](#l1.144)
s = dec("mbcs")[](#l1.145)
except UnicodeError:[](#l1.146)
pass[](#l1.147)
- return s
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")[](#l1.149)
if not os.path.isfile(vcvarsall):[](#l1.150)
log.debug("%s cannot be found", vcvarsall)[](#l1.151)
return None[](#l1.152)
return vcvarsall[](#l1.154)
- if os.getenv("DISTUTILS_USE_SDK"):
return {[](#l1.162)
key.lower(): value[](#l1.163)
for key, value in os.environ.items()[](#l1.164)
}[](#l1.165)
- def set_macro(self, macro, path, key):
for base in HKEYS:[](#l1.168)
d = read_values(base, path)[](#l1.169)
if d:[](#l1.170)
self.macros["$(%s)" % macro] = d[key][](#l1.171)
break[](#l1.172)
- vcvarsall = _find_vcvarsall()
- if not vcvarsall:
raise DistutilsPlatformError("Unable to find vcvarsall.bat")[](#l1.175)
- def load_macros(self, version):
vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version[](#l1.178)
self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")[](#l1.179)
self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")[](#l1.180)
net = r"Software\Microsoft\.NETFramework"[](#l1.181)
self.set_macro("FrameworkDir", net, "installroot")[](#l1.182)
try:[](#l1.183)
if version > 7.0:[](#l1.184)
self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")[](#l1.185)
else:[](#l1.186)
self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")[](#l1.187)
except KeyError as exc: #[](#l1.188)
raise DistutilsPlatformError([](#l1.189)
"""Python was built with Visual Studio 2003;[](#l1.190)
-extensions must be built with a compiler than can generate compatible binaries. -Visual Studio 2003 was not found on this system. If you have Cygwin installed, -you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") -
p = r"Software\Microsoft\NET Framework Setup\Product"[](#l1.195)
for base in HKEYS:[](#l1.196)
try:[](#l1.197)
h = RegOpenKeyEx(base, p)[](#l1.198)
except RegError:[](#l1.199)
continue[](#l1.200)
key = RegEnumKey(h, 0)[](#l1.201)
d = read_values(base, r"%s\%s" % (p, key))[](#l1.202)
self.macros["$(FrameworkVersion)"] = d["version"][](#l1.203)
- def sub(self, s):
for k, v in self.macros.items():[](#l1.206)
s = s.replace(k, v)[](#l1.207)
return s[](#l1.208)
- try:
out = subprocess.check_output([](#l1.213)
'"{}" {} && set'.format(vcvarsall, plat_spec),[](#l1.214)
shell=True,[](#l1.215)
stderr=subprocess.STDOUT,[](#l1.216)
universal_newlines=True,[](#l1.217)
)[](#l1.218)
- except subprocess.CalledProcessError as exc:
log.error(exc.output)[](#l1.220)
raise DistutilsPlatformError("Error executing {}"[](#l1.221)
.format(exc.cmd))[](#l1.222)
- For Python 2.3 and up, the version number is included in
- sys.version. For earlier versions, assume the compiler is MSVC 6.
- """
- prefix = "MSC v."
- i = sys.version.find(prefix)
- if i == -1:
return 6[](#l1.230)
- i = i + len(prefix)
- s, rest = sys.version[i:].split(" ", 1)
- majorVersion = int(s[:-2]) - 6
- if majorVersion >= 13:
# v13 was skipped and should be v14[](#l1.235)
majorVersion += 1[](#l1.236)
- minorVersion = int(s[2:3]) / 10.0
I don't think paths are affected by minor version in version 6
- if majorVersion == 6:
minorVersion = 0[](#l1.240)
- if majorVersion >= 6:
return majorVersion + minorVersion[](#l1.242)
else we don't know what version of the compiler this is
- return None
- return {
key.lower(): value[](#l1.246)
for key, _, value in[](#l1.247)
(line.partition('=') for line in out.splitlines())[](#l1.248)
if key and value[](#l1.249)
- }
-def get_build_architecture():
+def _find_exe(exe, paths=None):
- Tries to find the program in several places: first, one of the
- MSVC program search paths from the registry; next, the directories
- in the PATH environment variable. If any of those work, return an
- absolute path that is known to exist. If none of them work, just
- return the original program name, 'exe'. """ -
- prefix = " bit ("
- i = sys.version.find(prefix)
- if i == -1:
return "Intel"[](#l1.268)
- j = sys.version.find(")", i)
- return sys.version[i+len(prefix):j]
- if not paths:
paths = os.getenv('path').split(os.pathsep)[](#l1.272)
- for p in paths:
fn = os.path.join(os.path.abspath(p), exe)[](#l1.274)
if os.path.isfile(fn):[](#l1.275)
return fn[](#l1.276)
- return exe
-def normalize_and_reduce_paths(paths):
- The current order of paths is maintained.
- """
Paths are normalized so things like: /a and /a/ aren't both preserved.
- reduced_paths = []
- for p in paths:
np = os.path.normpath(p)[](#l1.287)
# XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.[](#l1.288)
if np not in reduced_paths:[](#l1.289)
reduced_paths.append(np)[](#l1.290)
- return reduced_paths
- +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targetting amd64.) +PLAT_TO_VCVARS = {
+} class MSVCCompiler(CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, @@ -227,83 +146,75 @@ class MSVCCompiler(CCompiler) : static_lib_format = shared_lib_format = '%s%s' exe_extension = '.exe' + def init(self, verbose=0, dry_run=0, force=0): CCompiler.init (self, verbose, dry_run, force)
self.__version = get_build_version()[](#l1.310)
self.__arch = get_build_architecture()[](#l1.311)
if self.__arch == "Intel":[](#l1.312)
# x86[](#l1.313)
if self.__version >= 7:[](#l1.314)
self.__root = r"Software\Microsoft\VisualStudio"[](#l1.315)
self.__macros = MacroExpander(self.__version)[](#l1.316)
else:[](#l1.317)
self.__root = r"Software\Microsoft\Devstudio"[](#l1.318)
self.__product = "Visual Studio version %s" % self.__version[](#l1.319)
else:[](#l1.320)
# Win64. Assume this was built with the platform SDK[](#l1.321)
self.__product = "Microsoft SDK compiler %s" % (self.__version + 6)[](#l1.322)
# target platform (.plat_name is consistent with 'bdist')[](#l1.324)
self.plat_name = None[](#l1.325) self.initialized = False[](#l1.326)
- def initialize(self):
self.__paths = [][](#l1.329)
if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):[](#l1.330)
# Assume that the SDK set up everything alright; don't try to be[](#l1.331)
# smarter[](#l1.332)
self.cc = "cl.exe"[](#l1.333)
self.linker = "link.exe"[](#l1.334)
self.lib = "lib.exe"[](#l1.335)
self.rc = "rc.exe"[](#l1.336)
self.mc = "mc.exe"[](#l1.337)
else:[](#l1.338)
self.__paths = self.get_msvc_paths("path")[](#l1.339)
- def initialize(self, plat_name=None):
# multi-init means we would need to check platform same each time...[](#l1.341)
assert not self.initialized, "don't init multiple times"[](#l1.342)
if plat_name is None:[](#l1.343)
plat_name = get_platform()[](#l1.344)
# sanity check for platforms to prevent obscure errors later.[](#l1.345)
if plat_name not in PLAT_TO_VCVARS:[](#l1.346)
raise DistutilsPlatformError("--plat-name must be one of {}"[](#l1.347)
.format(tuple(PLAT_TO_VCVARS)))[](#l1.348)
if len(self.__paths) == 0:[](#l1.350)
raise DistutilsPlatformError("Python was built with %s, "[](#l1.351)
"and extensions need to be built with the same "[](#l1.352)
"version of the compiler, but it isn't installed."[](#l1.353)
% self.__product)[](#l1.354)
# On x86, 'vcvarsall.bat amd64' creates an env that doesn't work;[](#l1.355)
# to cross compile, you use 'x86_amd64'.[](#l1.356)
# On AMD64, 'vcvarsall.bat amd64' is a native build env; to cross[](#l1.357)
# compile use 'x86' (ie, it runs the x86 compiler directly)[](#l1.358)
if plat_name == get_platform() or plat_name == 'win32':[](#l1.359)
# native build or cross-compile to win32[](#l1.360)
plat_spec = PLAT_TO_VCVARS[plat_name][](#l1.361)
else:[](#l1.362)
# cross compile from win32 -> some 64bit[](#l1.363)
plat_spec = '{}_{}'.format([](#l1.364)
PLAT_TO_VCVARS[get_platform()],[](#l1.365)
PLAT_TO_VCVARS[plat_name][](#l1.366)
)[](#l1.367)
self.cc = self.find_exe("cl.exe")[](#l1.369)
self.linker = self.find_exe("link.exe")[](#l1.370)
self.lib = self.find_exe("lib.exe")[](#l1.371)
self.rc = self.find_exe("rc.exe") # resource compiler[](#l1.372)
self.mc = self.find_exe("mc.exe") # message compiler[](#l1.373)
self.set_path_env_var('lib')[](#l1.374)
self.set_path_env_var('include')[](#l1.375)
vc_env = _get_vc_env(plat_spec)[](#l1.376)
if not vc_env:[](#l1.377)
raise DistutilsPlatformError("Unable to find a compatible "[](#l1.378)
"Visual Studio installation.")[](#l1.379)
# extend the MSVC path with the current path[](#l1.381)
try:[](#l1.382)
for p in os.environ['path'].split(';'):[](#l1.383)
self.__paths.append(p)[](#l1.384)
except KeyError:[](#l1.385)
pass[](#l1.386)
self.__paths = normalize_and_reduce_paths(self.__paths)[](#l1.387)
os.environ['path'] = ";".join(self.__paths)[](#l1.388)
paths = vc_env.get('path', '').split(os.pathsep)[](#l1.389)
self.cc = _find_exe("cl.exe", paths)[](#l1.390)
self.linker = _find_exe("link.exe", paths)[](#l1.391)
self.lib = _find_exe("lib.exe", paths)[](#l1.392)
self.rc = _find_exe("rc.exe", paths) # resource compiler[](#l1.393)
self.mc = _find_exe("mc.exe", paths) # message compiler[](#l1.394)
self.mt = _find_exe("mt.exe", paths) # message compiler[](#l1.395)
for dir in vc_env.get('include', '').split(os.pathsep):[](#l1.397)
if dir:[](#l1.398)
self.add_include_dir(dir)[](#l1.399)
for dir in vc_env.get('lib', '').split(os.pathsep):[](#l1.401)
if dir:[](#l1.402)
self.add_library_dir(dir)[](#l1.403)
self.preprocess_options = None
if self.__arch == "Intel":[](#l1.406)
self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,[](#l1.407)
'/DNDEBUG'][](#l1.408)
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',[](#l1.409)
'/Z7', '/D_DEBUG'][](#l1.410)
else:[](#l1.411)
# Win64[](#l1.412)
self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,[](#l1.413)
'/DNDEBUG'][](#l1.414)
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',[](#l1.415)
'/Z7', '/D_DEBUG'][](#l1.416)
self.compile_options = [[](#l1.417)
'/nologo', '/Ox', '/MD', '/W3', '/GL', '/DNDEBUG'[](#l1.418)
][](#l1.419)
self.compile_options_debug = [[](#l1.420)
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'[](#l1.421)
][](#l1.422)
self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'][](#l1.424)
if self.__version >= 7:[](#l1.425)
self.ldflags_shared_debug = [[](#l1.426)
'/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'[](#l1.427)
][](#l1.428)
else:[](#l1.429)
self.ldflags_shared_debug = [[](#l1.430)
'/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'[](#l1.431)
][](#l1.432)
self.ldflags_static = [ '/nologo'][](#l1.433)
self.ldflags_shared = [[](#l1.434)
'/nologo', '/DLL', '/INCREMENTAL:NO'[](#l1.435)
][](#l1.436)
self.ldflags_shared_debug = [[](#l1.437)
'/nologo', '/DLL', '/INCREMENTAL:no', '/DEBUG:FULL'[](#l1.438)
][](#l1.439)
self.ldflags_static = [[](#l1.440)
'/nologo'[](#l1.441)
][](#l1.442)
self.initialized = True @@ -313,31 +224,31 @@ class MSVCCompiler(CCompiler) : source_filenames, strip_dir=0, output_dir=''):
# Copied from ccompiler.py, extended to return .res as 'object'-file[](#l1.450)
# for .rc input file[](#l1.451)
if output_dir is None: output_dir = ''[](#l1.452)
obj_names = [][](#l1.453)
for src_name in source_filenames:[](#l1.454)
(base, ext) = os.path.splitext (src_name)[](#l1.455)
base = os.path.splitdrive(base)[1] # Chop off the drive[](#l1.456)
base = base[os.path.isabs(base):] # If abs, chop off leading /[](#l1.457)
if ext not in self.src_extensions:[](#l1.458)
ext_map = {ext: self.obj_extension for ext in self.src_extensions}[](#l1.459)
ext_map.update((ext, self.res_extension)[](#l1.460)
for ext in self._rc_extensions + self._mc_extensions)[](#l1.461)
def make_out_path(p):[](#l1.463)
base, ext = os.path.splitext(p)[](#l1.464)
if strip_dir:[](#l1.465)
base = os.path.basename(base)[](#l1.466)
else:[](#l1.467)
_, base = os.path.splitdrive(base)[](#l1.468)
if base.startswith((os.path.sep, os.path.altsep)):[](#l1.469)
base = base[1:][](#l1.470)
try:[](#l1.471)
return base + ext_map[ext][](#l1.472)
except LookupError:[](#l1.473) # Better to raise an exception instead of silently continuing[](#l1.474) # and later complain about sources and targets having[](#l1.475) # different lengths[](#l1.476)
raise CompileError ("Don't know how to compile %s" % src_name)[](#l1.477)
if strip_dir:[](#l1.478)
base = os.path.basename (base)[](#l1.479)
if ext in self._rc_extensions:[](#l1.480)
obj_names.append (os.path.join (output_dir,[](#l1.481)
base + self.res_extension))[](#l1.482)
elif ext in self._mc_extensions:[](#l1.483)
obj_names.append (os.path.join (output_dir,[](#l1.484)
base + self.res_extension))[](#l1.485)
else:[](#l1.486)
obj_names.append (os.path.join (output_dir,[](#l1.487)
base + self.obj_extension))[](#l1.488)
return obj_names[](#l1.489)
raise CompileError("Don't know how to compile {}".format(p))[](#l1.490)
output_dir = output_dir or ''[](#l1.492)
return [[](#l1.493)
os.path.join(output_dir, make_out_path(src_name))[](#l1.494)
for src_name in source_filenames[](#l1.495)
][](#l1.496)
def compile(self, sources, @@ -351,12 +262,15 @@ class MSVCCompiler(CCompiler) : macros, objects, extra_postargs, pp_opts, build = compile_info compile_opts = extra_preargs or []
compile_opts.append ('/c')[](#l1.504)
compile_opts.append('/c')[](#l1.505) if debug:[](#l1.506) compile_opts.extend(self.compile_options_debug)[](#l1.507) else:[](#l1.508) compile_opts.extend(self.compile_options)[](#l1.509)
add_cpp_opts = False[](#l1.512)
+ for obj in objects: try: src, ext = build[obj] @@ -372,13 +286,13 @@ class MSVCCompiler(CCompiler) : input_opt = "/Tc" + src elif ext in self._cpp_extensions: input_opt = "/Tp" + src
add_cpp_opts = True[](#l1.521) elif ext in self._rc_extensions:[](#l1.522) # compile .RC to .RES file[](#l1.523) input_opt = src[](#l1.524) output_opt = "/fo" + obj[](#l1.525) try:[](#l1.526)
self.spawn([self.rc] + pp_opts +[](#l1.527)
[output_opt] + [input_opt])[](#l1.528)
self.spawn([self.rc] + pp_opts + [output_opt, input_opt])[](#l1.529) except DistutilsExecError as msg:[](#l1.530) raise CompileError(msg)[](#l1.531) continue[](#l1.532)
@@ -398,27 +312,29 @@ class MSVCCompiler(CCompiler) : rc_dir = os.path.dirname(obj) try: # first compile .MC to .RC and .H file
self.spawn([self.mc] +[](#l1.537)
['-h', h_dir, '-r', rc_dir] + [src])[](#l1.538)
base, _ = os.path.splitext (os.path.basename (src))[](#l1.539)
rc_file = os.path.join (rc_dir, base + '.rc')[](#l1.540)
self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])[](#l1.541)
base, _ = os.path.splitext(os.path.basename (src))[](#l1.542)
rc_file = os.path.join(rc_dir, base + '.rc')[](#l1.543) # then compile .RC to .RES file[](#l1.544)
self.spawn([self.rc] +[](#l1.545)
["/fo" + obj] + [rc_file])[](#l1.546)
self.spawn([self.rc, "/fo" + obj, rc_file])[](#l1.547)
except DistutilsExecError as msg: raise CompileError(msg) continue else: # how to handle this file?
raise CompileError("Don't know how to compile %s to %s"[](#l1.554)
% (src, obj))[](#l1.555)
raise CompileError("Don't know how to compile {} to {}"[](#l1.556)
.format(src, obj))[](#l1.557)
output_opt = "/Fo" + obj[](#l1.559)
args = [self.cc] + compile_opts + pp_opts[](#l1.560)
if add_cpp_opts:[](#l1.561)
args.append('/EHsc')[](#l1.562)
args.append(input_opt)[](#l1.563)
args.append("/Fo" + obj)[](#l1.564)
args.extend(extra_postargs)[](#l1.565)
self.spawn([self.cc] + compile_opts + pp_opts +[](#l1.568)
[input_opt, output_opt] +[](#l1.569)
extra_postargs)[](#l1.570)
self.spawn(args)[](#l1.571) except DistutilsExecError as msg:[](#l1.572) raise CompileError(msg)[](#l1.573)
@@ -434,7 +350,7 @@ class MSVCCompiler(CCompiler) : if not self.initialized: self.initialize()
(objects, output_dir) = self._fix_object_args(objects, output_dir)[](#l1.579)
objects, output_dir = self._fix_object_args(objects, output_dir)[](#l1.580) output_filename = self.library_filename(output_libname,[](#l1.581) output_dir=output_dir)[](#l1.582)
@@ -467,14 +383,14 @@ class MSVCCompiler(CCompiler) : if not self.initialized: self.initialize()
(objects, output_dir) = self._fix_object_args(objects, output_dir)[](#l1.588)
objects, output_dir = self._fix_object_args(objects, output_dir)[](#l1.589) fixed_args = self._fix_lib_args(libraries, library_dirs,[](#l1.590) runtime_library_dirs)[](#l1.591)
(libraries, library_dirs, runtime_library_dirs) = fixed_args[](#l1.592)
libraries, library_dirs, runtime_library_dirs = fixed_args[](#l1.593)
self.warn ("I don't know what to do with 'runtime_library_dirs': "[](#l1.596)
+ str (runtime_library_dirs))[](#l1.597)
self.warn("I don't know what to do with 'runtime_library_dirs': "[](#l1.598)
+ str(runtime_library_dirs))[](#l1.599)
lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, @@ -483,16 +399,10 @@ class MSVCCompiler(CCompiler) : output_filename = os.path.join(output_dir, output_filename) if self._need_link(objects, output_filename):
ldflags = (self.ldflags_shared_debug if debug[](#l1.607)
else self.ldflags_shared)[](#l1.608) if target_desc == CCompiler.EXECUTABLE:[](#l1.609)
if debug:[](#l1.610)
ldflags = self.ldflags_shared_debug[1:][](#l1.611)
else:[](#l1.612)
ldflags = self.ldflags_shared[1:][](#l1.613)
else:[](#l1.614)
if debug:[](#l1.615)
ldflags = self.ldflags_shared_debug[](#l1.616)
else:[](#l1.617)
ldflags = self.ldflags_shared[](#l1.618)
ldflags = ldflags[1:][](#l1.619)
export_opts = [] for sym in (export_symbols or []): @@ -506,14 +416,17 @@ class MSVCCompiler(CCompiler) : # needed! Make sure they are generated in the temporary build # directory. Since they have different names for debug and release # builds, they can go into the same directory.
build_temp = os.path.dirname(objects[0])[](#l1.627) if export_symbols is not None:[](#l1.628) (dll_name, dll_ext) = os.path.splitext([](#l1.629) os.path.basename(output_filename))[](#l1.630) implib_file = os.path.join([](#l1.631)
os.path.dirname(objects[0]),[](#l1.632)
build_temp,[](#l1.633) self.library_filename(dll_name))[](#l1.634) ld_args.append ('/IMPLIB:' + implib_file)[](#l1.635)
self.manifest_setup_ldargs(output_filename, build_temp, ld_args)[](#l1.637)
+ if extra_preargs: ld_args[:0] = extra_preargs if extra_postargs: @@ -525,9 +438,97 @@ class MSVCCompiler(CCompiler) : except DistutilsExecError as msg: raise LinkError(msg)
# embed the manifest[](#l1.646)
# XXX - this is somewhat fragile - if mt.exe fails, distutils[](#l1.647)
# will still consider the DLL up-to-date, but it will not have a[](#l1.648)
# manifest. Maybe we should link to a temp file? OTOH, that[](#l1.649)
# implies a build environment error that shouldn't go undetected.[](#l1.650)
mfinfo = self.manifest_get_embed_info(target_desc, ld_args)[](#l1.651)
if mfinfo is not None:[](#l1.652)
mffilename, mfid = mfinfo[](#l1.653)
out_arg = '-outputresource:{};{}'.format(output_filename, mfid)[](#l1.654)
try:[](#l1.655)
self.spawn([self.mt, '-nologo', '-manifest',[](#l1.656)
mffilename, out_arg])[](#l1.657)
except DistutilsExecError as msg:[](#l1.658)
raise LinkError(msg)[](#l1.659) else:[](#l1.660) log.debug("skipping %s (up-to-date)", output_filename)[](#l1.661)
- def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
# If we need a manifest at all, an embedded manifest is recommended.[](#l1.664)
# See MSDN article titled[](#l1.665)
# "How to: Embed a Manifest Inside a C/C++ Application"[](#l1.666)
# (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)[](#l1.667)
# Ask the linker to generate the manifest in the temp dir, so[](#l1.668)
# we can check it, and possibly embed it, later.[](#l1.669)
temp_manifest = os.path.join([](#l1.670)
build_temp,[](#l1.671)
os.path.basename(output_filename) + ".manifest")[](#l1.672)
ld_args.append('/MANIFESTFILE:' + temp_manifest)[](#l1.673)
- def manifest_get_embed_info(self, target_desc, ld_args):
# If a manifest should be embedded, return a tuple of[](#l1.676)
# (manifest_filename, resource_id). Returns None if no manifest[](#l1.677)
# should be embedded. See http://bugs.python.org/issue7833 for why[](#l1.678)
# we want to avoid any manifest for extension modules if we can)[](#l1.679)
for arg in ld_args:[](#l1.680)
if arg.startswith("/MANIFESTFILE:"):[](#l1.681)
temp_manifest = arg.split(":", 1)[1][](#l1.682)
break[](#l1.683)
else:[](#l1.684)
# no /MANIFESTFILE so nothing to do.[](#l1.685)
return None[](#l1.686)
if target_desc == CCompiler.EXECUTABLE:[](#l1.687)
# by default, executables always get the manifest with the[](#l1.688)
# CRT referenced.[](#l1.689)
mfid = 1[](#l1.690)
else:[](#l1.691)
# Extension modules try and avoid any manifest if possible.[](#l1.692)
mfid = 2[](#l1.693)
temp_manifest = self._remove_visual_c_ref(temp_manifest)[](#l1.694)
if temp_manifest is None:[](#l1.695)
return None[](#l1.696)
return temp_manifest, mfid[](#l1.697)
- def _remove_visual_c_ref(self, manifest_file):
try:[](#l1.700)
# Remove references to the Visual C runtime, so they will[](#l1.701)
# fall through to the Visual C dependency of Python.exe.[](#l1.702)
# This way, when installed for a restricted user (e.g.[](#l1.703)
# runtimes are not in WinSxS folder, but in Python's own[](#l1.704)
# folder), the runtimes do not need to be in every folder[](#l1.705)
# with .pyd's.[](#l1.706)
# Returns either the filename of the modified manifest or[](#l1.707)
# None if no manifest should be embedded.[](#l1.708)
manifest_f = open(manifest_file)[](#l1.709)
try:[](#l1.710)
manifest_buf = manifest_f.read()[](#l1.711)
finally:[](#l1.712)
manifest_f.close()[](#l1.713)
pattern = re.compile([](#l1.714)
r"""<assemblyIdentity.*?name=("|')Microsoft\."""\[](#l1.715)
r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",[](#l1.716)
re.DOTALL)[](#l1.717)
manifest_buf = re.sub(pattern, "", manifest_buf)[](#l1.718)
pattern = "<dependentAssembly>\s*</dependentAssembly>"[](#l1.719)
manifest_buf = re.sub(pattern, "", manifest_buf)[](#l1.720)
# Now see if any other assemblies are referenced - if not, we[](#l1.721)
# don't want a manifest embedded.[](#l1.722)
pattern = re.compile([](#l1.723)
r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""[](#l1.724)
r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)[](#l1.725)
if re.search(pattern, manifest_buf) is None:[](#l1.726)
return None[](#l1.727)
manifest_f = open(manifest_file, 'w')[](#l1.729)
try:[](#l1.730)
manifest_f.write(manifest_buf)[](#l1.731)
return manifest_file[](#l1.732)
finally:[](#l1.733)
manifest_f.close()[](#l1.734)
except OSError:[](#l1.735)
pass[](#l1.736)
# -- Miscellaneous methods ----------------------------------------- # These are all used by the 'gen_lib_options() function, in @@ -538,12 +539,11 @@ class MSVCCompiler(CCompiler) : def runtime_library_dir_option(self, dir): raise DistutilsPlatformError(
"don't know how to set runtime library search path for MSVC++")[](#l1.744)
"don't know how to set runtime library search path for MSVC")[](#l1.745)
def library_option(self, lib): return self.library_filename(lib) - def find_library_file(self, dirs, lib, debug=0): # Prefer a debugging library if found (and requested), but deal # with it if we don't have one. @@ -553,91 +553,9 @@ class MSVCCompiler(CCompiler) : try_names = [lib] for dir in dirs: for name in try_names:
libfile = os.path.join(dir, self.library_filename (name))[](#l1.758)
if os.path.exists(libfile):[](#l1.759)
libfile = os.path.join(dir, self.library_filename(name))[](#l1.760)
if os.path.isfile(libfile):[](#l1.761) return libfile[](#l1.762) else:[](#l1.763) # Oops, didn't find it in *any* of 'dirs'[](#l1.764) return None[](#l1.765)
Tries to find the program in several places: first, one of the[](#l1.772)
MSVC program search paths from the registry; next, the directories[](#l1.773)
in the PATH environment variable. If any of those work, return an[](#l1.774)
absolute path that is known to exist. If none of them work, just[](#l1.775)
return the original program name, 'exe'.[](#l1.776)
"""[](#l1.777)
for p in self.__paths:[](#l1.778)
fn = os.path.join(os.path.abspath(p), exe)[](#l1.779)
if os.path.isfile(fn):[](#l1.780)
return fn[](#l1.781)
# didn't find it; try existing path[](#l1.783)
for p in os.environ['Path'].split(';'):[](#l1.784)
fn = os.path.join(os.path.abspath(p),exe)[](#l1.785)
if os.path.isfile(fn):[](#l1.786)
return fn[](#l1.787)
return exe[](#l1.789)
- def get_msvc_paths(self, path, platform='x86'):
"""Get a list of devstudio directories (include, lib or path).[](#l1.792)
Return a list of strings. The list will be empty if unable to[](#l1.794)
access the registry or appropriate registry keys not found.[](#l1.795)
"""[](#l1.796)
if not _can_read_reg:[](#l1.797)
return [][](#l1.798)
path = path + " dirs"[](#l1.800)
if self.__version >= 7:[](#l1.801)
key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"[](#l1.802)
% (self.__root, self.__version))[](#l1.803)
else:[](#l1.804)
key = (r"%s\6.0\Build System\Components\Platforms"[](#l1.805)
r"\Win32 (%s)\Directories" % (self.__root, platform))[](#l1.806)
for base in HKEYS:[](#l1.808)
d = read_values(base, key)[](#l1.809)
if d:[](#l1.810)
if self.__version >= 7:[](#l1.811)
return self.__macros.sub(d[path]).split(";")[](#l1.812)
else:[](#l1.813)
return d[path].split(";")[](#l1.814)
# MSVC 6 seems to create the registry entries we need only when[](#l1.815)
# the GUI is run.[](#l1.816)
if self.__version == 6:[](#l1.817)
for base in HKEYS:[](#l1.818)
if read_values(base, r"%s\6.0" % self.__root) is not None:[](#l1.819)
self.warn("It seems you have Visual Studio 6 installed, "[](#l1.820)
"but the expected registry settings are not present.\n"[](#l1.821)
"You must at least run the Visual Studio GUI once "[](#l1.822)
"so that these entries are created.")[](#l1.823)
break[](#l1.824)
return [][](#l1.825)
- def set_path_env_var(self, name):
"""Set environment variable 'name' to an MSVC path type value.[](#l1.828)
This is equivalent to a SET command prior to execution of spawned[](#l1.830)
commands.[](#l1.831)
"""[](#l1.832)
if name == "lib":[](#l1.834)
p = self.get_msvc_paths("library")[](#l1.835)
else:[](#l1.836)
p = self.get_msvc_paths(name)[](#l1.837)
if p:[](#l1.838)
os.environ[name] = ';'.join(p)[](#l1.839)
- - -if get_build_version() >= 8.0:
- log.debug("Importing new compiler from distutils.msvc9compiler")
- OldMSVCCompiler = MSVCCompiler
- from distutils.msvc9compiler import MSVCCompiler
get_build_architecture not really relevant now we support cross-compile
- from distutils.msvc9compiler import MacroExpander
--- a/Lib/distutils/ccompiler.py +++ b/Lib/distutils/ccompiler.py @@ -959,7 +959,7 @@ def get_default_compiler(osname=None, pl
is assumed to be in the 'distutils' package.)
compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', "standard UNIX-style compiler"),
'msvc': ('msvccompiler', 'MSVCCompiler',[](#l2.7)
'msvc': ('_msvccompiler', 'MSVCCompiler',[](#l2.8) "Microsoft Visual C++"),[](#l2.9) 'cygwin': ('cygwinccompiler', 'CygwinCCompiler',[](#l2.10) "Cygwin port of GNU C Compiler for Win32"),[](#l2.11)
--- a/Lib/distutils/command/bdist_wininst.py +++ b/Lib/distutils/command/bdist_wininst.py @@ -303,7 +303,6 @@ class bdist_wininst(Command): return installer_name def get_exe_bytes(self):
from distutils.msvccompiler import get_build_version[](#l3.7) # If a target-version other than the current version has been[](#l3.8) # specified, then using the MSVC version from *this* build is no good.[](#l3.9) # Without actually finding and executing the target version and parsing[](#l3.10)
@@ -313,20 +312,28 @@ class bdist_wininst(Command): # We can then execute this program to obtain any info we need, such # as the real sys.version string for the build. cur_version = get_python_version()
if self.target_version and self.target_version != cur_version:[](#l3.15)
# If the target version is *later* than us, then we assume they[](#l3.16)
# use what we use[](#l3.17)
# string compares seem wrong, but are what sysconfig.py itself uses[](#l3.18)
if self.target_version > cur_version:[](#l3.19)
bv = get_build_version()[](#l3.20)
# If the target version is *later* than us, then we assume they[](#l3.22)
# use what we use[](#l3.23)
# string compares seem wrong, but are what sysconfig.py itself uses[](#l3.24)
if self.target_version and self.target_version < cur_version:[](#l3.25)
if self.target_version < "2.4":[](#l3.26)
bv = 6.0[](#l3.27)
elif self.target_version == "2.4":[](#l3.28)
bv = 7.1[](#l3.29)
elif self.target_version == "2.5":[](#l3.30)
bv = 8.0[](#l3.31)
elif self.target_version <= "3.2":[](#l3.32)
bv = 9.0[](#l3.33)
elif self.target_version <= "3.4":[](#l3.34)
bv = 10.0[](#l3.35) else:[](#l3.36)
if self.target_version < "2.4":[](#l3.37)
bv = 6.0[](#l3.38)
else:[](#l3.39)
bv = 7.1[](#l3.40)
bv = 14.0[](#l3.41) else:[](#l3.42) # for current version - use authoritative check.[](#l3.43)
bv = get_build_version()[](#l3.44)
from msvcrt import CRT_ASSEMBLY_VERSION[](#l3.45)
bv = float('.'.join(CRT_ASSEMBLY_VERSION.split('.', 2)[:2]))[](#l3.46)
+ # wininst-x.y.exe is in the same directory as this file directory = os.path.dirname(file)
--- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -19,10 +19,6 @@ from distutils import log from site import USER_BASE -if os.name == 'nt':
An extension name is just a dot-separated list of Python NAMEs (ie.
the same as a fully-qualified module name).
extension_name_re = re.compile [](#l4.13) @@ -206,27 +202,17 @@ class build_ext(Command): _sys_home = getattr(sys, '_home', None) if _sys_home: self.library_dirs.append(_sys_home)
if MSVC_VERSION >= 9:[](#l4.18)
# Use the .lib files for the correct architecture[](#l4.19)
if self.plat_name == 'win32':[](#l4.20)
suffix = 'win32'[](#l4.21)
else:[](#l4.22)
# win-amd64 or win-ia64[](#l4.23)
suffix = self.plat_name[4:][](#l4.24)
new_lib = os.path.join(sys.exec_prefix, 'PCbuild')[](#l4.25)
if suffix:[](#l4.26)
new_lib = os.path.join(new_lib, suffix)[](#l4.27)
self.library_dirs.append(new_lib)[](#l4.28)
elif MSVC_VERSION == 8:[](#l4.30)
self.library_dirs.append(os.path.join(sys.exec_prefix,[](#l4.31)
'PC', 'VS8.0'))[](#l4.32)
elif MSVC_VERSION == 7:[](#l4.33)
self.library_dirs.append(os.path.join(sys.exec_prefix,[](#l4.34)
'PC', 'VS7.1'))[](#l4.35)
# Use the .lib files for the correct architecture[](#l4.36)
if self.plat_name == 'win32':[](#l4.37)
suffix = 'win32'[](#l4.38) else:[](#l4.39)
self.library_dirs.append(os.path.join(sys.exec_prefix,[](#l4.40)
'PC', 'VC6'))[](#l4.41)
# win-amd64 or win-ia64[](#l4.42)
suffix = self.plat_name[4:][](#l4.43)
new_lib = os.path.join(sys.exec_prefix, 'PCbuild')[](#l4.44)
if suffix:[](#l4.45)
new_lib = os.path.join(new_lib, suffix)[](#l4.46)
self.library_dirs.append(new_lib)[](#l4.47)
# for extensions under Cygwin and AtheOS Python's library directory must be # appended to library_dirs @@ -716,7 +702,7 @@ class build_ext(Command): # to need it mentioned explicitly, though, so that's what we do. # Append '_d' to the python import library on debug builds. if sys.platform == "win32":
from distutils.msvccompiler import MSVCCompiler[](#l4.55)
from distutils._msvccompiler import MSVCCompiler[](#l4.56) if not isinstance(self.compiler, MSVCCompiler):[](#l4.57) template = "python%d%d"[](#l4.58) if self.debug:[](#l4.59)
copy from Lib/distutils/tests/test_msvc9compiler.py copy to Lib/distutils/tests/test_msvccompiler.py --- a/Lib/distutils/tests/test_msvc9compiler.py +++ b/Lib/distutils/tests/test_msvccompiler.py @@ -1,4 +1,4 @@ -"""Tests for distutils.msvc9compiler.""" +"""Tests for distutils._msvccompiler.""" import sys import unittest import os @@ -90,56 +90,32 @@ from test.support import run_unittest """ -if sys.platform=="win32":
- from distutils.msvccompiler import get_build_version
- if get_build_version()>=8.0:
SKIP_MESSAGE = None[](#l5.18)
- else:
SKIP_MESSAGE = "These tests are only for MSVC8.0 or above"[](#l5.20)
+SKIP_MESSAGE = (None if sys.platform == "win32" else
"These tests are only for win32")[](#l5.24)
@unittest.skipUnless(SKIP_MESSAGE is None, SKIP_MESSAGE) -class msvc9compilerTestCase(support.TempdirManager, +class msvccompilerTestCase(support.TempdirManager, unittest.TestCase): def test_no_compiler(self): # makes sure query_vcvarsall raises # a DistutilsPlatformError if the compiler # is not found
from distutils.msvc9compiler import query_vcvarsall[](#l5.35)
def _find_vcvarsall(version):[](#l5.36)
from distutils._msvccompiler import _get_vc_env[](#l5.37)
def _find_vcvarsall():[](#l5.38) return None[](#l5.39)
from distutils import msvc9compiler[](#l5.41)
old_find_vcvarsall = msvc9compiler.find_vcvarsall[](#l5.42)
msvc9compiler.find_vcvarsall = _find_vcvarsall[](#l5.43)
import distutils._msvccompiler as _msvccompiler[](#l5.44)
old_find_vcvarsall = _msvccompiler._find_vcvarsall[](#l5.45)
_msvccompiler._find_vcvarsall = _find_vcvarsall[](#l5.46) try:[](#l5.47)
self.assertRaises(DistutilsPlatformError, query_vcvarsall,[](#l5.48)
self.assertRaises(DistutilsPlatformError, _get_vc_env,[](#l5.49) 'wont find this version')[](#l5.50) finally:[](#l5.51)
msvc9compiler.find_vcvarsall = old_find_vcvarsall[](#l5.52)
- def test_reg_class(self):
from distutils.msvc9compiler import Reg[](#l5.55)
self.assertRaises(KeyError, Reg.get_value, 'xxx', 'xxx')[](#l5.56)
# looking for values that should exist on all[](#l5.58)
# windows registeries versions.[](#l5.59)
path = r'Control Panel\Desktop'[](#l5.60)
v = Reg.get_value(path, 'dragfullwindows')[](#l5.61)
self.assertIn(v, ('0', '1', '2'))[](#l5.62)
import winreg[](#l5.64)
HKCU = winreg.HKEY_CURRENT_USER[](#l5.65)
keys = Reg.read_keys(HKCU, 'xxxx')[](#l5.66)
self.assertEqual(keys, None)[](#l5.67)
keys = Reg.read_keys(HKCU, r'Control Panel')[](#l5.69)
self.assertIn('Desktop', keys)[](#l5.70)
_msvccompiler._find_vcvarsall = old_find_vcvarsall[](#l5.71)
def test_remove_visual_c_ref(self):
from distutils.msvc9compiler import MSVCCompiler[](#l5.74)
from distutils._msvccompiler import MSVCCompiler[](#l5.75) tempdir = self.mkdtemp()[](#l5.76) manifest = os.path.join(tempdir, 'manifest')[](#l5.77) f = open(manifest, 'w')[](#l5.78)
@@ -163,7 +139,7 @@ class msvc9compilerTestCase(support.Temp self.assertEqual(content, _CLEANED_MANIFEST) def test_remove_entire_manifest(self):
from distutils.msvc9compiler import MSVCCompiler[](#l5.83)
from distutils._msvccompiler import MSVCCompiler[](#l5.84) tempdir = self.mkdtemp()[](#l5.85) manifest = os.path.join(tempdir, 'manifest')[](#l5.86) f = open(manifest, 'w')[](#l5.87)
@@ -178,7 +154,7 @@ class msvc9compilerTestCase(support.Temp def test_suite():
if name == "main": run_unittest(test_suite())
--- a/Lib/test/test_sundry.py +++ b/Lib/test/test_sundry.py @@ -22,8 +22,6 @@ class TestUntestedModules(unittest.TestC import distutils.ccompiler import distutils.cygwinccompiler import distutils.filelist
if sys.platform.startswith('win'):[](#l6.7)
import distutils.msvccompiler[](#l6.8) import distutils.text_file[](#l6.9) import distutils.unixccompiler[](#l6.10)