blob: 58b20a2102473394a64b627de3339da2e6cc5fe4 [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
92def _find_vcvarsall(plat_spec):
Steve Dower53125a52018-10-27 16:48:33 -040093 _, best_dir = _find_vc2017()
Steve Dower05f01d82017-09-07 11:49:23 -070094 vcruntime = None
95 vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
Steve Dower53125a52018-10-27 16:48:33 -040096 if best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -070097 vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
98 "Microsoft.VC141.CRT", "vcruntime140.dll")
99 try:
100 import glob
101 vcruntime = glob.glob(vcredist, recursive=True)[-1]
102 except (ImportError, OSError, LookupError):
103 vcruntime = None
104
Steve Dower53125a52018-10-27 16:48:33 -0400105 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700106 best_version, best_dir = _find_vc2015()
107 if best_version:
108 vcruntime = os.path.join(best_dir, 'redist', vcruntime_plat,
109 "Microsoft.VC140.CRT", "vcruntime140.dll")
110
Steve Dower53125a52018-10-27 16:48:33 -0400111 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700112 log.debug("No suitable Visual C++ version found")
113 return None, None
114
115 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
116 if not os.path.isfile(vcvarsall):
117 log.debug("%s cannot be found", vcvarsall)
118 return None, None
119
120 if not vcruntime or not os.path.isfile(vcruntime):
121 log.debug("%s cannot be found", vcruntime)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700122 vcruntime = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700123
Steve Dower05f01d82017-09-07 11:49:23 -0700124 return vcvarsall, vcruntime
Steve Dowerfd3664b2015-05-23 09:02:50 -0700125
126def _get_vc_env(plat_spec):
127 if os.getenv("DISTUTILS_USE_SDK"):
128 return {
129 key.lower(): value
130 for key, value in os.environ.items()
131 }
132
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700133 vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700134 if not vcvarsall:
135 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
136
137 try:
138 out = subprocess.check_output(
Steve Dower08bb8a42016-06-17 09:32:38 -0700139 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
Steve Dowerfd3664b2015-05-23 09:02:50 -0700140 stderr=subprocess.STDOUT,
Steve Dower08bb8a42016-06-17 09:32:38 -0700141 ).decode('utf-16le', errors='replace')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700142 except subprocess.CalledProcessError as exc:
143 log.error(exc.output)
144 raise DistutilsPlatformError("Error executing {}"
145 .format(exc.cmd))
146
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700147 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700148 key.lower(): value
149 for key, _, value in
150 (line.partition('=') for line in out.splitlines())
151 if key and value
152 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700153
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700154 if vcruntime:
155 env['py_vcruntime_redist'] = vcruntime
156 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700157
158def _find_exe(exe, paths=None):
159 """Return path to an MSVC executable program.
160
161 Tries to find the program in several places: first, one of the
162 MSVC program search paths from the registry; next, the directories
163 in the PATH environment variable. If any of those work, return an
164 absolute path that is known to exist. If none of them work, just
165 return the original program name, 'exe'.
166 """
167 if not paths:
168 paths = os.getenv('path').split(os.pathsep)
169 for p in paths:
170 fn = os.path.join(os.path.abspath(p), exe)
171 if os.path.isfile(fn):
172 return fn
173 return exe
174
175# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800176# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
177# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700178PLAT_TO_VCVARS = {
179 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800180 'win-amd64' : 'x86_amd64',
Steve Dowerfd3664b2015-05-23 09:02:50 -0700181}
182
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700183# A set containing the DLLs that are guaranteed to be available for
184# all micro versions of this Python version. Known extension
185# dependencies that are not in this set will be copied to the output
186# path.
187_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
188
Steve Dowerfd3664b2015-05-23 09:02:50 -0700189class MSVCCompiler(CCompiler) :
190 """Concrete class that implements an interface to Microsoft Visual C++,
191 as defined by the CCompiler abstract class."""
192
193 compiler_type = 'msvc'
194
195 # Just set this so CCompiler's constructor doesn't barf. We currently
196 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
197 # as it really isn't necessary for this sort of single-compiler class.
198 # Would be nice to have a consistent interface with UnixCCompiler,
199 # though, so it's worth thinking about.
200 executables = {}
201
202 # Private class data (need to distinguish C from C++ source for compiler)
203 _c_extensions = ['.c']
204 _cpp_extensions = ['.cc', '.cpp', '.cxx']
205 _rc_extensions = ['.rc']
206 _mc_extensions = ['.mc']
207
208 # Needed for the filename generation methods provided by the
209 # base class, CCompiler.
210 src_extensions = (_c_extensions + _cpp_extensions +
211 _rc_extensions + _mc_extensions)
212 res_extension = '.res'
213 obj_extension = '.obj'
214 static_lib_extension = '.lib'
215 shared_lib_extension = '.dll'
216 static_lib_format = shared_lib_format = '%s%s'
217 exe_extension = '.exe'
218
219
220 def __init__(self, verbose=0, dry_run=0, force=0):
221 CCompiler.__init__ (self, verbose, dry_run, force)
222 # target platform (.plat_name is consistent with 'bdist')
223 self.plat_name = None
224 self.initialized = False
225
226 def initialize(self, plat_name=None):
227 # multi-init means we would need to check platform same each time...
228 assert not self.initialized, "don't init multiple times"
229 if plat_name is None:
230 plat_name = get_platform()
231 # sanity check for platforms to prevent obscure errors later.
232 if plat_name not in PLAT_TO_VCVARS:
233 raise DistutilsPlatformError("--plat-name must be one of {}"
234 .format(tuple(PLAT_TO_VCVARS)))
235
Steve Dower1d329412016-01-16 12:39:10 -0800236 # Get the vcvarsall.bat spec for the requested platform.
237 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700238
239 vc_env = _get_vc_env(plat_spec)
240 if not vc_env:
241 raise DistutilsPlatformError("Unable to find a compatible "
242 "Visual Studio installation.")
243
Steve Dower31202ea2015-08-05 11:39:19 -0700244 self._paths = vc_env.get('path', '')
245 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700246 self.cc = _find_exe("cl.exe", paths)
247 self.linker = _find_exe("link.exe", paths)
248 self.lib = _find_exe("lib.exe", paths)
249 self.rc = _find_exe("rc.exe", paths) # resource compiler
250 self.mc = _find_exe("mc.exe", paths) # message compiler
251 self.mt = _find_exe("mt.exe", paths) # message compiler
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700252 self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700253
254 for dir in vc_env.get('include', '').split(os.pathsep):
255 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700256 self.add_include_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700257
258 for dir in vc_env.get('lib', '').split(os.pathsep):
259 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700260 self.add_library_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700261
262 self.preprocess_options = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700263 # If vcruntime_redist is available, link against it dynamically. Otherwise,
264 # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
Steve Dower31202ea2015-08-05 11:39:19 -0700265 # later to dynamically link to ucrtbase but not vcruntime.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700266 self.compile_options = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700267 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700268 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700269 self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
Larry Hastings52e40cd2015-09-09 06:54:57 -0700270
Steve Dowerfd3664b2015-05-23 09:02:50 -0700271 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700272 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700273 ]
274
Steve Dower31202ea2015-08-05 11:39:19 -0700275 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700276 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700277 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700278 if not self._vcruntime_redist:
279 ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
280
Steve Dower31202ea2015-08-05 11:39:19 -0700281 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700282 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700283 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700284
285 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
286 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
287 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
288 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
289 self.ldflags_static = [*ldflags]
290 self.ldflags_static_debug = [*ldflags_debug]
291
292 self._ldflags = {
293 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
294 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
295 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
296 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
297 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
298 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
299 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
300 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
301 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
302 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700303
304 self.initialized = True
305
306 # -- Worker methods ------------------------------------------------
307
308 def object_filenames(self,
309 source_filenames,
310 strip_dir=0,
311 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700312 ext_map = {
313 **{ext: self.obj_extension for ext in self.src_extensions},
314 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
315 }
316
317 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700318
319 def make_out_path(p):
320 base, ext = os.path.splitext(p)
321 if strip_dir:
322 base = os.path.basename(base)
323 else:
324 _, base = os.path.splitdrive(base)
325 if base.startswith((os.path.sep, os.path.altsep)):
326 base = base[1:]
327 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700328 # XXX: This may produce absurdly long paths. We should check
329 # the length of the result and trim base until we fit within
330 # 260 characters.
331 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700332 except LookupError:
333 # Better to raise an exception instead of silently continuing
334 # and later complain about sources and targets having
335 # different lengths
336 raise CompileError("Don't know how to compile {}".format(p))
337
Steve Dower31202ea2015-08-05 11:39:19 -0700338 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700339
340
341 def compile(self, sources,
342 output_dir=None, macros=None, include_dirs=None, debug=0,
343 extra_preargs=None, extra_postargs=None, depends=None):
344
345 if not self.initialized:
346 self.initialize()
347 compile_info = self._setup_compile(output_dir, macros, include_dirs,
348 sources, depends, extra_postargs)
349 macros, objects, extra_postargs, pp_opts, build = compile_info
350
351 compile_opts = extra_preargs or []
352 compile_opts.append('/c')
353 if debug:
354 compile_opts.extend(self.compile_options_debug)
355 else:
356 compile_opts.extend(self.compile_options)
357
358
359 add_cpp_opts = False
360
361 for obj in objects:
362 try:
363 src, ext = build[obj]
364 except KeyError:
365 continue
366 if debug:
367 # pass the full pathname to MSVC in debug mode,
368 # this allows the debugger to find the source file
369 # without asking the user to browse for it
370 src = os.path.abspath(src)
371
372 if ext in self._c_extensions:
373 input_opt = "/Tc" + src
374 elif ext in self._cpp_extensions:
375 input_opt = "/Tp" + src
376 add_cpp_opts = True
377 elif ext in self._rc_extensions:
378 # compile .RC to .RES file
379 input_opt = src
380 output_opt = "/fo" + obj
381 try:
382 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
383 except DistutilsExecError as msg:
384 raise CompileError(msg)
385 continue
386 elif ext in self._mc_extensions:
387 # Compile .MC to .RC file to .RES file.
388 # * '-h dir' specifies the directory for the
389 # generated include file
390 # * '-r dir' specifies the target directory of the
391 # generated RC file and the binary message resource
392 # it includes
393 #
394 # For now (since there are no options to change this),
395 # we use the source-directory for the include file and
396 # the build directory for the RC file and message
397 # resources. This works at least for win32all.
398 h_dir = os.path.dirname(src)
399 rc_dir = os.path.dirname(obj)
400 try:
401 # first compile .MC to .RC and .H file
402 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
403 base, _ = os.path.splitext(os.path.basename (src))
404 rc_file = os.path.join(rc_dir, base + '.rc')
405 # then compile .RC to .RES file
406 self.spawn([self.rc, "/fo" + obj, rc_file])
407
408 except DistutilsExecError as msg:
409 raise CompileError(msg)
410 continue
411 else:
412 # how to handle this file?
413 raise CompileError("Don't know how to compile {} to {}"
414 .format(src, obj))
415
416 args = [self.cc] + compile_opts + pp_opts
417 if add_cpp_opts:
418 args.append('/EHsc')
419 args.append(input_opt)
420 args.append("/Fo" + obj)
421 args.extend(extra_postargs)
422
423 try:
424 self.spawn(args)
425 except DistutilsExecError as msg:
426 raise CompileError(msg)
427
428 return objects
429
430
431 def create_static_lib(self,
432 objects,
433 output_libname,
434 output_dir=None,
435 debug=0,
436 target_lang=None):
437
438 if not self.initialized:
439 self.initialize()
440 objects, output_dir = self._fix_object_args(objects, output_dir)
441 output_filename = self.library_filename(output_libname,
442 output_dir=output_dir)
443
444 if self._need_link(objects, output_filename):
445 lib_args = objects + ['/OUT:' + output_filename]
446 if debug:
447 pass # XXX what goes here?
448 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700449 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700450 self.spawn([self.lib] + lib_args)
451 except DistutilsExecError as msg:
452 raise LibError(msg)
453 else:
454 log.debug("skipping %s (up-to-date)", output_filename)
455
456
457 def link(self,
458 target_desc,
459 objects,
460 output_filename,
461 output_dir=None,
462 libraries=None,
463 library_dirs=None,
464 runtime_library_dirs=None,
465 export_symbols=None,
466 debug=0,
467 extra_preargs=None,
468 extra_postargs=None,
469 build_temp=None,
470 target_lang=None):
471
472 if not self.initialized:
473 self.initialize()
474 objects, output_dir = self._fix_object_args(objects, output_dir)
475 fixed_args = self._fix_lib_args(libraries, library_dirs,
476 runtime_library_dirs)
477 libraries, library_dirs, runtime_library_dirs = fixed_args
478
479 if runtime_library_dirs:
480 self.warn("I don't know what to do with 'runtime_library_dirs': "
481 + str(runtime_library_dirs))
482
483 lib_opts = gen_lib_options(self,
484 library_dirs, runtime_library_dirs,
485 libraries)
486 if output_dir is not None:
487 output_filename = os.path.join(output_dir, output_filename)
488
489 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700490 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700491
Steve Dower31202ea2015-08-05 11:39:19 -0700492 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700493
494 ld_args = (ldflags + lib_opts + export_opts +
495 objects + ['/OUT:' + output_filename])
496
497 # The MSVC linker generates .lib and .exp files, which cannot be
498 # suppressed by any linker switches. The .lib files may even be
499 # needed! Make sure they are generated in the temporary build
500 # directory. Since they have different names for debug and release
501 # builds, they can go into the same directory.
502 build_temp = os.path.dirname(objects[0])
503 if export_symbols is not None:
504 (dll_name, dll_ext) = os.path.splitext(
505 os.path.basename(output_filename))
506 implib_file = os.path.join(
507 build_temp,
508 self.library_filename(dll_name))
509 ld_args.append ('/IMPLIB:' + implib_file)
510
Steve Dowerfd3664b2015-05-23 09:02:50 -0700511 if extra_preargs:
512 ld_args[:0] = extra_preargs
513 if extra_postargs:
514 ld_args.extend(extra_postargs)
515
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700516 output_dir = os.path.dirname(os.path.abspath(output_filename))
517 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700518 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700519 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700520 self.spawn([self.linker] + ld_args)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700521 self._copy_vcruntime(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700522 except DistutilsExecError as msg:
523 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700524 else:
525 log.debug("skipping %s (up-to-date)", output_filename)
526
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700527 def _copy_vcruntime(self, output_dir):
528 vcruntime = self._vcruntime_redist
529 if not vcruntime or not os.path.isfile(vcruntime):
530 return
531
532 if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
533 return
534
535 log.debug('Copying "%s"', vcruntime)
536 vcruntime = shutil.copy(vcruntime, output_dir)
537 os.chmod(vcruntime, stat.S_IWRITE)
538
Steve Dower31202ea2015-08-05 11:39:19 -0700539 def spawn(self, cmd):
540 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700541 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700542 os.environ['path'] = self._paths
543 return super().spawn(cmd)
544 finally:
545 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700546
547 # -- Miscellaneous methods -----------------------------------------
548 # These are all used by the 'gen_lib_options() function, in
549 # ccompiler.py.
550
551 def library_dir_option(self, dir):
552 return "/LIBPATH:" + dir
553
554 def runtime_library_dir_option(self, dir):
555 raise DistutilsPlatformError(
556 "don't know how to set runtime library search path for MSVC")
557
558 def library_option(self, lib):
559 return self.library_filename(lib)
560
561 def find_library_file(self, dirs, lib, debug=0):
562 # Prefer a debugging library if found (and requested), but deal
563 # with it if we don't have one.
564 if debug:
565 try_names = [lib + "_d", lib]
566 else:
567 try_names = [lib]
568 for dir in dirs:
569 for name in try_names:
570 libfile = os.path.join(dir, self.library_filename(name))
571 if os.path.isfile(libfile):
572 return libfile
573 else:
574 # Oops, didn't find it in *any* of 'dirs'
575 return None