blob: 03a5986d984dc36d2f15cbb399c29de1dd954032 [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 Dower53125a52018-10-27 16:48:33 -040059 """Returns "15, path" based on the result of invoking vswhere.exe
60 If no install is found, returns "None, None"
Steve Dowerfd3664b2015-05-23 09:02:50 -070061
Steve Dower53125a52018-10-27 16:48:33 -040062 The version is returned to avoid unnecessarily changing the function
63 result. It may be ignored when the path is not None.
Steve Dower05f01d82017-09-07 11:49:23 -070064
Steve Dower53125a52018-10-27 16:48:33 -040065 If vswhere.exe is not available, by definition, VS 2017 is not
66 installed.
67 """
68 import json
Steve Dower05f01d82017-09-07 11:49:23 -070069
Steve Dower53125a52018-10-27 16:48:33 -040070 root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
71 if not root:
72 return None, None
73
Steve Dower05f01d82017-09-07 11:49:23 -070074 try:
Steve Dower53125a52018-10-27 16:48:33 -040075 path = subprocess.check_output([
76 os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
77 "-latest",
78 "-prerelease",
79 "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
80 "-property", "installationPath",
Marc Schlaichb2dc4a32019-01-20 19:47:42 +010081 "-products", "*",
Steve Dower53125a52018-10-27 16:48:33 -040082 ], encoding="mbcs", errors="strict").strip()
83 except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
84 return None, None
85
86 path = os.path.join(path, "VC", "Auxiliary", "Build")
87 if os.path.isdir(path):
88 return 15, path
89
90 return None, None
Steve Dower05f01d82017-09-07 11:49:23 -070091
Paul Monson62dfd7d2019-04-25 11:36:45 -070092PLAT_SPEC_TO_RUNTIME = {
93 'x86' : 'x86',
94 'x86_amd64' : 'x64',
95 'x86_arm' : 'arm',
Paul Monsondaf62622019-06-12 10:16:49 -070096 'x86_arm64' : 'arm64'
Paul Monson62dfd7d2019-04-25 11:36:45 -070097}
98
Steve Dower05f01d82017-09-07 11:49:23 -070099def _find_vcvarsall(plat_spec):
Steve Dowerce3a4982020-03-03 00:04:11 +0000100 # bpo-38597: Removed vcruntime return value
Steve Dower53125a52018-10-27 16:48:33 -0400101 _, best_dir = _find_vc2017()
Steve Dower05f01d82017-09-07 11:49:23 -0700102
Steve Dower53125a52018-10-27 16:48:33 -0400103 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700104 best_version, best_dir = _find_vc2015()
Steve Dower05f01d82017-09-07 11:49:23 -0700105
Steve Dower53125a52018-10-27 16:48:33 -0400106 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700107 log.debug("No suitable Visual C++ version found")
108 return None, None
109
110 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
111 if not os.path.isfile(vcvarsall):
112 log.debug("%s cannot be found", vcvarsall)
113 return None, None
114
Steve Dowerce3a4982020-03-03 00:04:11 +0000115 return vcvarsall, None
Steve Dowerfd3664b2015-05-23 09:02:50 -0700116
117def _get_vc_env(plat_spec):
118 if os.getenv("DISTUTILS_USE_SDK"):
119 return {
120 key.lower(): value
121 for key, value in os.environ.items()
122 }
123
Steve Dowerce3a4982020-03-03 00:04:11 +0000124 vcvarsall, _ = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700125 if not vcvarsall:
126 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
127
128 try:
129 out = subprocess.check_output(
Steve Dower08bb8a42016-06-17 09:32:38 -0700130 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
Steve Dowerfd3664b2015-05-23 09:02:50 -0700131 stderr=subprocess.STDOUT,
Steve Dower08bb8a42016-06-17 09:32:38 -0700132 ).decode('utf-16le', errors='replace')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700133 except subprocess.CalledProcessError as exc:
134 log.error(exc.output)
135 raise DistutilsPlatformError("Error executing {}"
136 .format(exc.cmd))
137
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700138 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700139 key.lower(): value
140 for key, _, value in
141 (line.partition('=') for line in out.splitlines())
142 if key and value
143 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700144
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700145 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700146
147def _find_exe(exe, paths=None):
148 """Return path to an MSVC executable program.
149
150 Tries to find the program in several places: first, one of the
151 MSVC program search paths from the registry; next, the directories
152 in the PATH environment variable. If any of those work, return an
153 absolute path that is known to exist. If none of them work, just
154 return the original program name, 'exe'.
155 """
156 if not paths:
157 paths = os.getenv('path').split(os.pathsep)
158 for p in paths:
159 fn = os.path.join(os.path.abspath(p), exe)
160 if os.path.isfile(fn):
161 return fn
162 return exe
163
164# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800165# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
166# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700167PLAT_TO_VCVARS = {
168 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800169 'win-amd64' : 'x86_amd64',
Paul Monson62dfd7d2019-04-25 11:36:45 -0700170 'win-arm32' : 'x86_arm',
Paul Monsondaf62622019-06-12 10:16:49 -0700171 'win-arm64' : 'x86_arm64'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700172}
173
174class MSVCCompiler(CCompiler) :
175 """Concrete class that implements an interface to Microsoft Visual C++,
176 as defined by the CCompiler abstract class."""
177
178 compiler_type = 'msvc'
179
180 # Just set this so CCompiler's constructor doesn't barf. We currently
181 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
182 # as it really isn't necessary for this sort of single-compiler class.
183 # Would be nice to have a consistent interface with UnixCCompiler,
184 # though, so it's worth thinking about.
185 executables = {}
186
187 # Private class data (need to distinguish C from C++ source for compiler)
188 _c_extensions = ['.c']
189 _cpp_extensions = ['.cc', '.cpp', '.cxx']
190 _rc_extensions = ['.rc']
191 _mc_extensions = ['.mc']
192
193 # Needed for the filename generation methods provided by the
194 # base class, CCompiler.
195 src_extensions = (_c_extensions + _cpp_extensions +
196 _rc_extensions + _mc_extensions)
197 res_extension = '.res'
198 obj_extension = '.obj'
199 static_lib_extension = '.lib'
200 shared_lib_extension = '.dll'
201 static_lib_format = shared_lib_format = '%s%s'
202 exe_extension = '.exe'
203
204
205 def __init__(self, verbose=0, dry_run=0, force=0):
206 CCompiler.__init__ (self, verbose, dry_run, force)
207 # target platform (.plat_name is consistent with 'bdist')
208 self.plat_name = None
209 self.initialized = False
210
211 def initialize(self, plat_name=None):
212 # multi-init means we would need to check platform same each time...
213 assert not self.initialized, "don't init multiple times"
214 if plat_name is None:
215 plat_name = get_platform()
216 # sanity check for platforms to prevent obscure errors later.
217 if plat_name not in PLAT_TO_VCVARS:
218 raise DistutilsPlatformError("--plat-name must be one of {}"
219 .format(tuple(PLAT_TO_VCVARS)))
220
Steve Dower1d329412016-01-16 12:39:10 -0800221 # Get the vcvarsall.bat spec for the requested platform.
222 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700223
224 vc_env = _get_vc_env(plat_spec)
225 if not vc_env:
226 raise DistutilsPlatformError("Unable to find a compatible "
227 "Visual Studio installation.")
228
Steve Dower31202ea2015-08-05 11:39:19 -0700229 self._paths = vc_env.get('path', '')
230 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700231 self.cc = _find_exe("cl.exe", paths)
232 self.linker = _find_exe("link.exe", paths)
233 self.lib = _find_exe("lib.exe", paths)
234 self.rc = _find_exe("rc.exe", paths) # resource compiler
235 self.mc = _find_exe("mc.exe", paths) # message compiler
236 self.mt = _find_exe("mt.exe", paths) # message compiler
237
238 for dir in vc_env.get('include', '').split(os.pathsep):
239 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700240 self.add_include_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700241
242 for dir in vc_env.get('lib', '').split(os.pathsep):
243 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700244 self.add_library_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700245
246 self.preprocess_options = None
Steve Dowerce3a4982020-03-03 00:04:11 +0000247 # bpo-38597: Always compile with dynamic linking
248 # Future releases of Python 3.x will include all past
249 # versions of vcruntime*.dll for compatibility.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700250 self.compile_options = [
Steve Dowerce3a4982020-03-03 00:04:11 +0000251 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG', '/MD'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700252 ]
Larry Hastings52e40cd2015-09-09 06:54:57 -0700253
Steve Dowerfd3664b2015-05-23 09:02:50 -0700254 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700255 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700256 ]
257
Steve Dower31202ea2015-08-05 11:39:19 -0700258 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700259 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700260 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700261
Steve Dower31202ea2015-08-05 11:39:19 -0700262 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700263 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700264 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700265
266 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
267 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
268 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
269 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
270 self.ldflags_static = [*ldflags]
271 self.ldflags_static_debug = [*ldflags_debug]
272
273 self._ldflags = {
274 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
275 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
276 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
277 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
278 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
279 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
280 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
281 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
282 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
283 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700284
285 self.initialized = True
286
287 # -- Worker methods ------------------------------------------------
288
289 def object_filenames(self,
290 source_filenames,
291 strip_dir=0,
292 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700293 ext_map = {
294 **{ext: self.obj_extension for ext in self.src_extensions},
295 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
296 }
297
298 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700299
300 def make_out_path(p):
301 base, ext = os.path.splitext(p)
302 if strip_dir:
303 base = os.path.basename(base)
304 else:
305 _, base = os.path.splitdrive(base)
306 if base.startswith((os.path.sep, os.path.altsep)):
307 base = base[1:]
308 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700309 # XXX: This may produce absurdly long paths. We should check
310 # the length of the result and trim base until we fit within
311 # 260 characters.
312 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700313 except LookupError:
314 # Better to raise an exception instead of silently continuing
315 # and later complain about sources and targets having
316 # different lengths
317 raise CompileError("Don't know how to compile {}".format(p))
318
Steve Dower31202ea2015-08-05 11:39:19 -0700319 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700320
321
322 def compile(self, sources,
323 output_dir=None, macros=None, include_dirs=None, debug=0,
324 extra_preargs=None, extra_postargs=None, depends=None):
325
326 if not self.initialized:
327 self.initialize()
328 compile_info = self._setup_compile(output_dir, macros, include_dirs,
329 sources, depends, extra_postargs)
330 macros, objects, extra_postargs, pp_opts, build = compile_info
331
332 compile_opts = extra_preargs or []
333 compile_opts.append('/c')
334 if debug:
335 compile_opts.extend(self.compile_options_debug)
336 else:
337 compile_opts.extend(self.compile_options)
338
339
340 add_cpp_opts = False
341
342 for obj in objects:
343 try:
344 src, ext = build[obj]
345 except KeyError:
346 continue
347 if debug:
348 # pass the full pathname to MSVC in debug mode,
349 # this allows the debugger to find the source file
350 # without asking the user to browse for it
351 src = os.path.abspath(src)
352
353 if ext in self._c_extensions:
354 input_opt = "/Tc" + src
355 elif ext in self._cpp_extensions:
356 input_opt = "/Tp" + src
357 add_cpp_opts = True
358 elif ext in self._rc_extensions:
359 # compile .RC to .RES file
360 input_opt = src
361 output_opt = "/fo" + obj
362 try:
363 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
364 except DistutilsExecError as msg:
365 raise CompileError(msg)
366 continue
367 elif ext in self._mc_extensions:
368 # Compile .MC to .RC file to .RES file.
369 # * '-h dir' specifies the directory for the
370 # generated include file
371 # * '-r dir' specifies the target directory of the
372 # generated RC file and the binary message resource
373 # it includes
374 #
375 # For now (since there are no options to change this),
376 # we use the source-directory for the include file and
377 # the build directory for the RC file and message
378 # resources. This works at least for win32all.
379 h_dir = os.path.dirname(src)
380 rc_dir = os.path.dirname(obj)
381 try:
382 # first compile .MC to .RC and .H file
383 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
384 base, _ = os.path.splitext(os.path.basename (src))
385 rc_file = os.path.join(rc_dir, base + '.rc')
386 # then compile .RC to .RES file
387 self.spawn([self.rc, "/fo" + obj, rc_file])
388
389 except DistutilsExecError as msg:
390 raise CompileError(msg)
391 continue
392 else:
393 # how to handle this file?
394 raise CompileError("Don't know how to compile {} to {}"
395 .format(src, obj))
396
397 args = [self.cc] + compile_opts + pp_opts
398 if add_cpp_opts:
399 args.append('/EHsc')
400 args.append(input_opt)
401 args.append("/Fo" + obj)
402 args.extend(extra_postargs)
403
404 try:
405 self.spawn(args)
406 except DistutilsExecError as msg:
407 raise CompileError(msg)
408
409 return objects
410
411
412 def create_static_lib(self,
413 objects,
414 output_libname,
415 output_dir=None,
416 debug=0,
417 target_lang=None):
418
419 if not self.initialized:
420 self.initialize()
421 objects, output_dir = self._fix_object_args(objects, output_dir)
422 output_filename = self.library_filename(output_libname,
423 output_dir=output_dir)
424
425 if self._need_link(objects, output_filename):
426 lib_args = objects + ['/OUT:' + output_filename]
427 if debug:
428 pass # XXX what goes here?
429 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700430 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700431 self.spawn([self.lib] + lib_args)
432 except DistutilsExecError as msg:
433 raise LibError(msg)
434 else:
435 log.debug("skipping %s (up-to-date)", output_filename)
436
437
438 def link(self,
439 target_desc,
440 objects,
441 output_filename,
442 output_dir=None,
443 libraries=None,
444 library_dirs=None,
445 runtime_library_dirs=None,
446 export_symbols=None,
447 debug=0,
448 extra_preargs=None,
449 extra_postargs=None,
450 build_temp=None,
451 target_lang=None):
452
453 if not self.initialized:
454 self.initialize()
455 objects, output_dir = self._fix_object_args(objects, output_dir)
456 fixed_args = self._fix_lib_args(libraries, library_dirs,
457 runtime_library_dirs)
458 libraries, library_dirs, runtime_library_dirs = fixed_args
459
460 if runtime_library_dirs:
461 self.warn("I don't know what to do with 'runtime_library_dirs': "
462 + str(runtime_library_dirs))
463
464 lib_opts = gen_lib_options(self,
465 library_dirs, runtime_library_dirs,
466 libraries)
467 if output_dir is not None:
468 output_filename = os.path.join(output_dir, output_filename)
469
470 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700471 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700472
Steve Dower31202ea2015-08-05 11:39:19 -0700473 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700474
475 ld_args = (ldflags + lib_opts + export_opts +
476 objects + ['/OUT:' + output_filename])
477
478 # The MSVC linker generates .lib and .exp files, which cannot be
479 # suppressed by any linker switches. The .lib files may even be
480 # needed! Make sure they are generated in the temporary build
481 # directory. Since they have different names for debug and release
482 # builds, they can go into the same directory.
483 build_temp = os.path.dirname(objects[0])
484 if export_symbols is not None:
485 (dll_name, dll_ext) = os.path.splitext(
486 os.path.basename(output_filename))
487 implib_file = os.path.join(
488 build_temp,
489 self.library_filename(dll_name))
490 ld_args.append ('/IMPLIB:' + implib_file)
491
Steve Dowerfd3664b2015-05-23 09:02:50 -0700492 if extra_preargs:
493 ld_args[:0] = extra_preargs
494 if extra_postargs:
495 ld_args.extend(extra_postargs)
496
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700497 output_dir = os.path.dirname(os.path.abspath(output_filename))
498 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700499 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700500 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700501 self.spawn([self.linker] + ld_args)
502 except DistutilsExecError as msg:
503 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700504 else:
505 log.debug("skipping %s (up-to-date)", output_filename)
506
Steve Dower31202ea2015-08-05 11:39:19 -0700507 def spawn(self, cmd):
508 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700509 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700510 os.environ['path'] = self._paths
511 return super().spawn(cmd)
512 finally:
513 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700514
515 # -- Miscellaneous methods -----------------------------------------
516 # These are all used by the 'gen_lib_options() function, in
517 # ccompiler.py.
518
519 def library_dir_option(self, dir):
520 return "/LIBPATH:" + dir
521
522 def runtime_library_dir_option(self, dir):
523 raise DistutilsPlatformError(
524 "don't know how to set runtime library search path for MSVC")
525
526 def library_option(self, lib):
527 return self.library_filename(lib)
528
529 def find_library_file(self, dirs, lib, debug=0):
530 # Prefer a debugging library if found (and requested), but deal
531 # with it if we don't have one.
532 if debug:
533 try_names = [lib + "_d", lib]
534 else:
535 try_names = [lib]
536 for dir in dirs:
537 for name in try_names:
538 libfile = os.path.join(dir, self.library_filename(name))
539 if os.path.isfile(libfile):
540 return libfile
541 else:
542 # Oops, didn't find it in *any* of 'dirs'
543 return None