blob: 30b3b4739851bad041e94c4285e7fec82c7038f6 [file] [log] [blame]
Steve Dowerfd3664b2015-05-23 09:02:50 -07001"""distutils._msvccompiler
2
3Contains MSVCCompiler, an implementation of the abstract CCompiler class
4for Microsoft Visual Studio 2015.
5
6The module is compatible with VS 2015 and later. You can find legacy support
7for older versions in distutils.msvc9compiler and distutils.msvccompiler.
8"""
9
10# Written by Perry Stoll
11# hacked by Robin Becker and Thomas Heller to do a better job of
12# finding DevStudio (through the registry)
13# ported to VS 2005 and VS 2008 by Christian Heimes
14# ported to VS 2015 by Steve Dower
15
16import os
Steve Dowerfcbe1df2015-09-08 21:39:01 -070017import shutil
18import stat
Steve Dowerfd3664b2015-05-23 09:02:50 -070019import subprocess
Steve Dower05f01d82017-09-07 11:49:23 -070020import winreg
Steve Dowerfd3664b2015-05-23 09:02:50 -070021
22from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
23 CompileError, LibError, LinkError
24from distutils.ccompiler import CCompiler, gen_lib_options
25from distutils import log
26from distutils.util import get_platform
27
Steve Dowerfd3664b2015-05-23 09:02:50 -070028from itertools import count
29
Steve Dower05f01d82017-09-07 11:49:23 -070030def _find_vc2015():
Steve Dowerf0ccf022015-10-05 10:35:00 -070031 try:
32 key = winreg.OpenKeyEx(
33 winreg.HKEY_LOCAL_MACHINE,
34 r"Software\Microsoft\VisualStudio\SxS\VC7",
35 access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
36 )
37 except OSError:
38 log.debug("Visual C++ is not registered")
39 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070040
Steve Dower05f01d82017-09-07 11:49:23 -070041 best_version = 0
42 best_dir = None
Steve Dowerf0ccf022015-10-05 10:35:00 -070043 with key:
Steve Dowerfd3664b2015-05-23 09:02:50 -070044 for i in count():
45 try:
46 v, vc_dir, vt = winreg.EnumValue(key, i)
47 except OSError:
48 break
49 if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
50 try:
51 version = int(float(v))
52 except (ValueError, TypeError):
53 continue
54 if version >= 14 and version > best_version:
55 best_version, best_dir = version, vc_dir
Steve Dower05f01d82017-09-07 11:49:23 -070056 return best_version, best_dir
Steve Dowerfd3664b2015-05-23 09:02:50 -070057
Steve Dower05f01d82017-09-07 11:49:23 -070058def _find_vc2017():
Steve Dower2507e292018-01-19 09:09:36 +110059 import _distutils_findvs
Steve Dower05f01d82017-09-07 11:49:23 -070060 import threading
Steve Dowerfd3664b2015-05-23 09:02:50 -070061
Steve Dower05f01d82017-09-07 11:49:23 -070062 best_version = 0, # tuple for full version comparisons
63 best_dir = None
64
65 # We need to call findall() on its own thread because it will
66 # initialize COM.
67 all_packages = []
68 def _getall():
Steve Dower2507e292018-01-19 09:09:36 +110069 all_packages.extend(_distutils_findvs.findall())
Steve Dower05f01d82017-09-07 11:49:23 -070070 t = threading.Thread(target=_getall)
71 t.start()
72 t.join()
73
74 for name, version_str, path, packages in all_packages:
75 if 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' in packages:
76 vc_dir = os.path.join(path, 'VC', 'Auxiliary', 'Build')
77 if not os.path.isdir(vc_dir):
78 continue
79 try:
80 version = tuple(int(i) for i in version_str.split('.'))
81 except (ValueError, TypeError):
82 continue
83 if version > best_version:
84 best_version, best_dir = version, vc_dir
85 try:
86 best_version = best_version[0]
87 except IndexError:
88 best_version = None
89 return best_version, best_dir
90
91def _find_vcvarsall(plat_spec):
92 best_version, best_dir = _find_vc2017()
93 vcruntime = None
94 vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
95 if best_version:
96 vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
97 "Microsoft.VC141.CRT", "vcruntime140.dll")
98 try:
99 import glob
100 vcruntime = glob.glob(vcredist, recursive=True)[-1]
101 except (ImportError, OSError, LookupError):
102 vcruntime = None
103
104 if not best_version:
105 best_version, best_dir = _find_vc2015()
106 if best_version:
107 vcruntime = os.path.join(best_dir, 'redist', vcruntime_plat,
108 "Microsoft.VC140.CRT", "vcruntime140.dll")
109
110 if not best_version:
111 log.debug("No suitable Visual C++ version found")
112 return None, None
113
114 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
115 if not os.path.isfile(vcvarsall):
116 log.debug("%s cannot be found", vcvarsall)
117 return None, None
118
119 if not vcruntime or not os.path.isfile(vcruntime):
120 log.debug("%s cannot be found", vcruntime)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700121 vcruntime = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700122
Steve Dower05f01d82017-09-07 11:49:23 -0700123 return vcvarsall, vcruntime
Steve Dowerfd3664b2015-05-23 09:02:50 -0700124
125def _get_vc_env(plat_spec):
126 if os.getenv("DISTUTILS_USE_SDK"):
127 return {
128 key.lower(): value
129 for key, value in os.environ.items()
130 }
131
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700132 vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700133 if not vcvarsall:
134 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
135
136 try:
137 out = subprocess.check_output(
Steve Dower08bb8a42016-06-17 09:32:38 -0700138 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
Steve Dowerfd3664b2015-05-23 09:02:50 -0700139 stderr=subprocess.STDOUT,
Steve Dower08bb8a42016-06-17 09:32:38 -0700140 ).decode('utf-16le', errors='replace')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700141 except subprocess.CalledProcessError as exc:
142 log.error(exc.output)
143 raise DistutilsPlatformError("Error executing {}"
144 .format(exc.cmd))
145
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700146 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700147 key.lower(): value
148 for key, _, value in
149 (line.partition('=') for line in out.splitlines())
150 if key and value
151 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700152
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700153 if vcruntime:
154 env['py_vcruntime_redist'] = vcruntime
155 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700156
157def _find_exe(exe, paths=None):
158 """Return path to an MSVC executable program.
159
160 Tries to find the program in several places: first, one of the
161 MSVC program search paths from the registry; next, the directories
162 in the PATH environment variable. If any of those work, return an
163 absolute path that is known to exist. If none of them work, just
164 return the original program name, 'exe'.
165 """
166 if not paths:
167 paths = os.getenv('path').split(os.pathsep)
168 for p in paths:
169 fn = os.path.join(os.path.abspath(p), exe)
170 if os.path.isfile(fn):
171 return fn
172 return exe
173
174# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800175# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
176# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700177PLAT_TO_VCVARS = {
178 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800179 'win-amd64' : 'x86_amd64',
Steve Dowerfd3664b2015-05-23 09:02:50 -0700180}
181
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700182# A set containing the DLLs that are guaranteed to be available for
183# all micro versions of this Python version. Known extension
184# dependencies that are not in this set will be copied to the output
185# path.
186_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
187
Steve Dowerfd3664b2015-05-23 09:02:50 -0700188class MSVCCompiler(CCompiler) :
189 """Concrete class that implements an interface to Microsoft Visual C++,
190 as defined by the CCompiler abstract class."""
191
192 compiler_type = 'msvc'
193
194 # Just set this so CCompiler's constructor doesn't barf. We currently
195 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
196 # as it really isn't necessary for this sort of single-compiler class.
197 # Would be nice to have a consistent interface with UnixCCompiler,
198 # though, so it's worth thinking about.
199 executables = {}
200
201 # Private class data (need to distinguish C from C++ source for compiler)
202 _c_extensions = ['.c']
203 _cpp_extensions = ['.cc', '.cpp', '.cxx']
204 _rc_extensions = ['.rc']
205 _mc_extensions = ['.mc']
206
207 # Needed for the filename generation methods provided by the
208 # base class, CCompiler.
209 src_extensions = (_c_extensions + _cpp_extensions +
210 _rc_extensions + _mc_extensions)
211 res_extension = '.res'
212 obj_extension = '.obj'
213 static_lib_extension = '.lib'
214 shared_lib_extension = '.dll'
215 static_lib_format = shared_lib_format = '%s%s'
216 exe_extension = '.exe'
217
218
219 def __init__(self, verbose=0, dry_run=0, force=0):
220 CCompiler.__init__ (self, verbose, dry_run, force)
221 # target platform (.plat_name is consistent with 'bdist')
222 self.plat_name = None
223 self.initialized = False
224
225 def initialize(self, plat_name=None):
226 # multi-init means we would need to check platform same each time...
227 assert not self.initialized, "don't init multiple times"
228 if plat_name is None:
229 plat_name = get_platform()
230 # sanity check for platforms to prevent obscure errors later.
231 if plat_name not in PLAT_TO_VCVARS:
232 raise DistutilsPlatformError("--plat-name must be one of {}"
233 .format(tuple(PLAT_TO_VCVARS)))
234
Steve Dower1d329412016-01-16 12:39:10 -0800235 # Get the vcvarsall.bat spec for the requested platform.
236 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700237
238 vc_env = _get_vc_env(plat_spec)
239 if not vc_env:
240 raise DistutilsPlatformError("Unable to find a compatible "
241 "Visual Studio installation.")
242
Steve Dower31202ea2015-08-05 11:39:19 -0700243 self._paths = vc_env.get('path', '')
244 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700245 self.cc = _find_exe("cl.exe", paths)
246 self.linker = _find_exe("link.exe", paths)
247 self.lib = _find_exe("lib.exe", paths)
248 self.rc = _find_exe("rc.exe", paths) # resource compiler
249 self.mc = _find_exe("mc.exe", paths) # message compiler
250 self.mt = _find_exe("mt.exe", paths) # message compiler
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700251 self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700252
253 for dir in vc_env.get('include', '').split(os.pathsep):
254 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700255 self.add_include_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700256
257 for dir in vc_env.get('lib', '').split(os.pathsep):
258 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700259 self.add_library_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700260
261 self.preprocess_options = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700262 # If vcruntime_redist is available, link against it dynamically. Otherwise,
263 # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
Steve Dower31202ea2015-08-05 11:39:19 -0700264 # later to dynamically link to ucrtbase but not vcruntime.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700265 self.compile_options = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700266 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700267 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700268 self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
Larry Hastings52e40cd2015-09-09 06:54:57 -0700269
Steve Dowerfd3664b2015-05-23 09:02:50 -0700270 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700271 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700272 ]
273
Steve Dower31202ea2015-08-05 11:39:19 -0700274 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700275 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700276 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700277 if not self._vcruntime_redist:
278 ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
279
Steve Dower31202ea2015-08-05 11:39:19 -0700280 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700281 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700282 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700283
284 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
285 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
286 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
287 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
288 self.ldflags_static = [*ldflags]
289 self.ldflags_static_debug = [*ldflags_debug]
290
291 self._ldflags = {
292 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
293 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
294 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
295 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
296 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
297 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
298 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
299 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
300 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
301 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700302
303 self.initialized = True
304
305 # -- Worker methods ------------------------------------------------
306
307 def object_filenames(self,
308 source_filenames,
309 strip_dir=0,
310 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700311 ext_map = {
312 **{ext: self.obj_extension for ext in self.src_extensions},
313 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
314 }
315
316 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700317
318 def make_out_path(p):
319 base, ext = os.path.splitext(p)
320 if strip_dir:
321 base = os.path.basename(base)
322 else:
323 _, base = os.path.splitdrive(base)
324 if base.startswith((os.path.sep, os.path.altsep)):
325 base = base[1:]
326 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700327 # XXX: This may produce absurdly long paths. We should check
328 # the length of the result and trim base until we fit within
329 # 260 characters.
330 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700331 except LookupError:
332 # Better to raise an exception instead of silently continuing
333 # and later complain about sources and targets having
334 # different lengths
335 raise CompileError("Don't know how to compile {}".format(p))
336
Steve Dower31202ea2015-08-05 11:39:19 -0700337 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700338
339
340 def compile(self, sources,
341 output_dir=None, macros=None, include_dirs=None, debug=0,
342 extra_preargs=None, extra_postargs=None, depends=None):
343
344 if not self.initialized:
345 self.initialize()
346 compile_info = self._setup_compile(output_dir, macros, include_dirs,
347 sources, depends, extra_postargs)
348 macros, objects, extra_postargs, pp_opts, build = compile_info
349
350 compile_opts = extra_preargs or []
351 compile_opts.append('/c')
352 if debug:
353 compile_opts.extend(self.compile_options_debug)
354 else:
355 compile_opts.extend(self.compile_options)
356
357
358 add_cpp_opts = False
359
360 for obj in objects:
361 try:
362 src, ext = build[obj]
363 except KeyError:
364 continue
365 if debug:
366 # pass the full pathname to MSVC in debug mode,
367 # this allows the debugger to find the source file
368 # without asking the user to browse for it
369 src = os.path.abspath(src)
370
371 if ext in self._c_extensions:
372 input_opt = "/Tc" + src
373 elif ext in self._cpp_extensions:
374 input_opt = "/Tp" + src
375 add_cpp_opts = True
376 elif ext in self._rc_extensions:
377 # compile .RC to .RES file
378 input_opt = src
379 output_opt = "/fo" + obj
380 try:
381 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
382 except DistutilsExecError as msg:
383 raise CompileError(msg)
384 continue
385 elif ext in self._mc_extensions:
386 # Compile .MC to .RC file to .RES file.
387 # * '-h dir' specifies the directory for the
388 # generated include file
389 # * '-r dir' specifies the target directory of the
390 # generated RC file and the binary message resource
391 # it includes
392 #
393 # For now (since there are no options to change this),
394 # we use the source-directory for the include file and
395 # the build directory for the RC file and message
396 # resources. This works at least for win32all.
397 h_dir = os.path.dirname(src)
398 rc_dir = os.path.dirname(obj)
399 try:
400 # first compile .MC to .RC and .H file
401 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
402 base, _ = os.path.splitext(os.path.basename (src))
403 rc_file = os.path.join(rc_dir, base + '.rc')
404 # then compile .RC to .RES file
405 self.spawn([self.rc, "/fo" + obj, rc_file])
406
407 except DistutilsExecError as msg:
408 raise CompileError(msg)
409 continue
410 else:
411 # how to handle this file?
412 raise CompileError("Don't know how to compile {} to {}"
413 .format(src, obj))
414
415 args = [self.cc] + compile_opts + pp_opts
416 if add_cpp_opts:
417 args.append('/EHsc')
418 args.append(input_opt)
419 args.append("/Fo" + obj)
420 args.extend(extra_postargs)
421
422 try:
423 self.spawn(args)
424 except DistutilsExecError as msg:
425 raise CompileError(msg)
426
427 return objects
428
429
430 def create_static_lib(self,
431 objects,
432 output_libname,
433 output_dir=None,
434 debug=0,
435 target_lang=None):
436
437 if not self.initialized:
438 self.initialize()
439 objects, output_dir = self._fix_object_args(objects, output_dir)
440 output_filename = self.library_filename(output_libname,
441 output_dir=output_dir)
442
443 if self._need_link(objects, output_filename):
444 lib_args = objects + ['/OUT:' + output_filename]
445 if debug:
446 pass # XXX what goes here?
447 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700448 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700449 self.spawn([self.lib] + lib_args)
450 except DistutilsExecError as msg:
451 raise LibError(msg)
452 else:
453 log.debug("skipping %s (up-to-date)", output_filename)
454
455
456 def link(self,
457 target_desc,
458 objects,
459 output_filename,
460 output_dir=None,
461 libraries=None,
462 library_dirs=None,
463 runtime_library_dirs=None,
464 export_symbols=None,
465 debug=0,
466 extra_preargs=None,
467 extra_postargs=None,
468 build_temp=None,
469 target_lang=None):
470
471 if not self.initialized:
472 self.initialize()
473 objects, output_dir = self._fix_object_args(objects, output_dir)
474 fixed_args = self._fix_lib_args(libraries, library_dirs,
475 runtime_library_dirs)
476 libraries, library_dirs, runtime_library_dirs = fixed_args
477
478 if runtime_library_dirs:
479 self.warn("I don't know what to do with 'runtime_library_dirs': "
480 + str(runtime_library_dirs))
481
482 lib_opts = gen_lib_options(self,
483 library_dirs, runtime_library_dirs,
484 libraries)
485 if output_dir is not None:
486 output_filename = os.path.join(output_dir, output_filename)
487
488 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700489 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700490
Steve Dower31202ea2015-08-05 11:39:19 -0700491 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700492
493 ld_args = (ldflags + lib_opts + export_opts +
494 objects + ['/OUT:' + output_filename])
495
496 # The MSVC linker generates .lib and .exp files, which cannot be
497 # suppressed by any linker switches. The .lib files may even be
498 # needed! Make sure they are generated in the temporary build
499 # directory. Since they have different names for debug and release
500 # builds, they can go into the same directory.
501 build_temp = os.path.dirname(objects[0])
502 if export_symbols is not None:
503 (dll_name, dll_ext) = os.path.splitext(
504 os.path.basename(output_filename))
505 implib_file = os.path.join(
506 build_temp,
507 self.library_filename(dll_name))
508 ld_args.append ('/IMPLIB:' + implib_file)
509
Steve Dowerfd3664b2015-05-23 09:02:50 -0700510 if extra_preargs:
511 ld_args[:0] = extra_preargs
512 if extra_postargs:
513 ld_args.extend(extra_postargs)
514
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700515 output_dir = os.path.dirname(os.path.abspath(output_filename))
516 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700517 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700518 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700519 self.spawn([self.linker] + ld_args)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700520 self._copy_vcruntime(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700521 except DistutilsExecError as msg:
522 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700523 else:
524 log.debug("skipping %s (up-to-date)", output_filename)
525
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700526 def _copy_vcruntime(self, output_dir):
527 vcruntime = self._vcruntime_redist
528 if not vcruntime or not os.path.isfile(vcruntime):
529 return
530
531 if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
532 return
533
534 log.debug('Copying "%s"', vcruntime)
535 vcruntime = shutil.copy(vcruntime, output_dir)
536 os.chmod(vcruntime, stat.S_IWRITE)
537
Steve Dower31202ea2015-08-05 11:39:19 -0700538 def spawn(self, cmd):
539 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700540 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700541 os.environ['path'] = self._paths
542 return super().spawn(cmd)
543 finally:
544 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700545
546 # -- Miscellaneous methods -----------------------------------------
547 # These are all used by the 'gen_lib_options() function, in
548 # ccompiler.py.
549
550 def library_dir_option(self, dir):
551 return "/LIBPATH:" + dir
552
553 def runtime_library_dir_option(self, dir):
554 raise DistutilsPlatformError(
555 "don't know how to set runtime library search path for MSVC")
556
557 def library_option(self, lib):
558 return self.library_filename(lib)
559
560 def find_library_file(self, dirs, lib, debug=0):
561 # Prefer a debugging library if found (and requested), but deal
562 # with it if we don't have one.
563 if debug:
564 try_names = [lib + "_d", lib]
565 else:
566 try_names = [lib]
567 for dir in dirs:
568 for name in try_names:
569 libfile = os.path.join(dir, self.library_filename(name))
570 if os.path.isfile(libfile):
571 return libfile
572 else:
573 # Oops, didn't find it in *any* of 'dirs'
574 return None