blob: e8e4b717b9736f22ddbde50fd57499eb33e76d68 [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',
Miss Islington (bot)bb3e8a62019-06-12 10:44:29 -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 Dower53125a52018-10-27 16:48:33 -0400100 _, best_dir = _find_vc2017()
Steve Dower05f01d82017-09-07 11:49:23 -0700101 vcruntime = None
Paul Monson62dfd7d2019-04-25 11:36:45 -0700102
103 if plat_spec in PLAT_SPEC_TO_RUNTIME:
104 vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]
105 else:
106 vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
107
Steve Dower53125a52018-10-27 16:48:33 -0400108 if best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700109 vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
Miss Islington (bot)2ed0ac62019-09-10 07:42:26 -0700110 vcruntime_plat, "Microsoft.VC14*.CRT", "vcruntime140.dll")
Steve Dower05f01d82017-09-07 11:49:23 -0700111 try:
112 import glob
113 vcruntime = glob.glob(vcredist, recursive=True)[-1]
114 except (ImportError, OSError, LookupError):
115 vcruntime = None
116
Steve Dower53125a52018-10-27 16:48:33 -0400117 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700118 best_version, best_dir = _find_vc2015()
119 if best_version:
120 vcruntime = os.path.join(best_dir, 'redist', vcruntime_plat,
121 "Microsoft.VC140.CRT", "vcruntime140.dll")
122
Steve Dower53125a52018-10-27 16:48:33 -0400123 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700124 log.debug("No suitable Visual C++ version found")
125 return None, None
126
127 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
128 if not os.path.isfile(vcvarsall):
129 log.debug("%s cannot be found", vcvarsall)
130 return None, None
131
132 if not vcruntime or not os.path.isfile(vcruntime):
133 log.debug("%s cannot be found", vcruntime)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700134 vcruntime = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700135
Steve Dower05f01d82017-09-07 11:49:23 -0700136 return vcvarsall, vcruntime
Steve Dowerfd3664b2015-05-23 09:02:50 -0700137
138def _get_vc_env(plat_spec):
139 if os.getenv("DISTUTILS_USE_SDK"):
140 return {
141 key.lower(): value
142 for key, value in os.environ.items()
143 }
144
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700145 vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700146 if not vcvarsall:
147 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
148
149 try:
150 out = subprocess.check_output(
Steve Dower08bb8a42016-06-17 09:32:38 -0700151 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
Steve Dowerfd3664b2015-05-23 09:02:50 -0700152 stderr=subprocess.STDOUT,
Steve Dower08bb8a42016-06-17 09:32:38 -0700153 ).decode('utf-16le', errors='replace')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700154 except subprocess.CalledProcessError as exc:
155 log.error(exc.output)
156 raise DistutilsPlatformError("Error executing {}"
157 .format(exc.cmd))
158
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700159 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700160 key.lower(): value
161 for key, _, value in
162 (line.partition('=') for line in out.splitlines())
163 if key and value
164 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700165
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700166 if vcruntime:
167 env['py_vcruntime_redist'] = vcruntime
168 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700169
170def _find_exe(exe, paths=None):
171 """Return path to an MSVC executable program.
172
173 Tries to find the program in several places: first, one of the
174 MSVC program search paths from the registry; next, the directories
175 in the PATH environment variable. If any of those work, return an
176 absolute path that is known to exist. If none of them work, just
177 return the original program name, 'exe'.
178 """
179 if not paths:
180 paths = os.getenv('path').split(os.pathsep)
181 for p in paths:
182 fn = os.path.join(os.path.abspath(p), exe)
183 if os.path.isfile(fn):
184 return fn
185 return exe
186
187# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800188# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
189# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700190PLAT_TO_VCVARS = {
191 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800192 'win-amd64' : 'x86_amd64',
Paul Monson62dfd7d2019-04-25 11:36:45 -0700193 'win-arm32' : 'x86_arm',
Miss Islington (bot)bb3e8a62019-06-12 10:44:29 -0700194 'win-arm64' : 'x86_arm64'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700195}
196
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700197# A set containing the DLLs that are guaranteed to be available for
198# all micro versions of this Python version. Known extension
199# dependencies that are not in this set will be copied to the output
200# path.
201_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
202
Steve Dowerfd3664b2015-05-23 09:02:50 -0700203class MSVCCompiler(CCompiler) :
204 """Concrete class that implements an interface to Microsoft Visual C++,
205 as defined by the CCompiler abstract class."""
206
207 compiler_type = 'msvc'
208
209 # Just set this so CCompiler's constructor doesn't barf. We currently
210 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
211 # as it really isn't necessary for this sort of single-compiler class.
212 # Would be nice to have a consistent interface with UnixCCompiler,
213 # though, so it's worth thinking about.
214 executables = {}
215
216 # Private class data (need to distinguish C from C++ source for compiler)
217 _c_extensions = ['.c']
218 _cpp_extensions = ['.cc', '.cpp', '.cxx']
219 _rc_extensions = ['.rc']
220 _mc_extensions = ['.mc']
221
222 # Needed for the filename generation methods provided by the
223 # base class, CCompiler.
224 src_extensions = (_c_extensions + _cpp_extensions +
225 _rc_extensions + _mc_extensions)
226 res_extension = '.res'
227 obj_extension = '.obj'
228 static_lib_extension = '.lib'
229 shared_lib_extension = '.dll'
230 static_lib_format = shared_lib_format = '%s%s'
231 exe_extension = '.exe'
232
233
234 def __init__(self, verbose=0, dry_run=0, force=0):
235 CCompiler.__init__ (self, verbose, dry_run, force)
236 # target platform (.plat_name is consistent with 'bdist')
237 self.plat_name = None
238 self.initialized = False
239
240 def initialize(self, plat_name=None):
241 # multi-init means we would need to check platform same each time...
242 assert not self.initialized, "don't init multiple times"
243 if plat_name is None:
244 plat_name = get_platform()
245 # sanity check for platforms to prevent obscure errors later.
246 if plat_name not in PLAT_TO_VCVARS:
247 raise DistutilsPlatformError("--plat-name must be one of {}"
248 .format(tuple(PLAT_TO_VCVARS)))
249
Steve Dower1d329412016-01-16 12:39:10 -0800250 # Get the vcvarsall.bat spec for the requested platform.
251 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700252
253 vc_env = _get_vc_env(plat_spec)
254 if not vc_env:
255 raise DistutilsPlatformError("Unable to find a compatible "
256 "Visual Studio installation.")
257
Steve Dower31202ea2015-08-05 11:39:19 -0700258 self._paths = vc_env.get('path', '')
259 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700260 self.cc = _find_exe("cl.exe", paths)
261 self.linker = _find_exe("link.exe", paths)
262 self.lib = _find_exe("lib.exe", paths)
263 self.rc = _find_exe("rc.exe", paths) # resource compiler
264 self.mc = _find_exe("mc.exe", paths) # message compiler
265 self.mt = _find_exe("mt.exe", paths) # message compiler
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700266 self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700267
268 for dir in vc_env.get('include', '').split(os.pathsep):
269 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700270 self.add_include_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700271
272 for dir in vc_env.get('lib', '').split(os.pathsep):
273 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700274 self.add_library_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700275
276 self.preprocess_options = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700277 # If vcruntime_redist is available, link against it dynamically. Otherwise,
278 # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
Steve Dower31202ea2015-08-05 11:39:19 -0700279 # later to dynamically link to ucrtbase but not vcruntime.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700280 self.compile_options = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700281 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700282 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700283 self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
Larry Hastings52e40cd2015-09-09 06:54:57 -0700284
Steve Dowerfd3664b2015-05-23 09:02:50 -0700285 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700286 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700287 ]
288
Steve Dower31202ea2015-08-05 11:39:19 -0700289 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700290 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700291 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700292 if not self._vcruntime_redist:
293 ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
294
Steve Dower31202ea2015-08-05 11:39:19 -0700295 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700296 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700297 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700298
299 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
300 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
301 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
302 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
303 self.ldflags_static = [*ldflags]
304 self.ldflags_static_debug = [*ldflags_debug]
305
306 self._ldflags = {
307 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
308 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
309 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
310 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
311 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
312 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
313 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
314 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
315 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
316 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700317
318 self.initialized = True
319
320 # -- Worker methods ------------------------------------------------
321
322 def object_filenames(self,
323 source_filenames,
324 strip_dir=0,
325 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700326 ext_map = {
327 **{ext: self.obj_extension for ext in self.src_extensions},
328 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
329 }
330
331 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700332
333 def make_out_path(p):
334 base, ext = os.path.splitext(p)
335 if strip_dir:
336 base = os.path.basename(base)
337 else:
338 _, base = os.path.splitdrive(base)
339 if base.startswith((os.path.sep, os.path.altsep)):
340 base = base[1:]
341 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700342 # XXX: This may produce absurdly long paths. We should check
343 # the length of the result and trim base until we fit within
344 # 260 characters.
345 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700346 except LookupError:
347 # Better to raise an exception instead of silently continuing
348 # and later complain about sources and targets having
349 # different lengths
350 raise CompileError("Don't know how to compile {}".format(p))
351
Steve Dower31202ea2015-08-05 11:39:19 -0700352 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700353
354
355 def compile(self, sources,
356 output_dir=None, macros=None, include_dirs=None, debug=0,
357 extra_preargs=None, extra_postargs=None, depends=None):
358
359 if not self.initialized:
360 self.initialize()
361 compile_info = self._setup_compile(output_dir, macros, include_dirs,
362 sources, depends, extra_postargs)
363 macros, objects, extra_postargs, pp_opts, build = compile_info
364
365 compile_opts = extra_preargs or []
366 compile_opts.append('/c')
367 if debug:
368 compile_opts.extend(self.compile_options_debug)
369 else:
370 compile_opts.extend(self.compile_options)
371
372
373 add_cpp_opts = False
374
375 for obj in objects:
376 try:
377 src, ext = build[obj]
378 except KeyError:
379 continue
380 if debug:
381 # pass the full pathname to MSVC in debug mode,
382 # this allows the debugger to find the source file
383 # without asking the user to browse for it
384 src = os.path.abspath(src)
385
386 if ext in self._c_extensions:
387 input_opt = "/Tc" + src
388 elif ext in self._cpp_extensions:
389 input_opt = "/Tp" + src
390 add_cpp_opts = True
391 elif ext in self._rc_extensions:
392 # compile .RC to .RES file
393 input_opt = src
394 output_opt = "/fo" + obj
395 try:
396 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
397 except DistutilsExecError as msg:
398 raise CompileError(msg)
399 continue
400 elif ext in self._mc_extensions:
401 # Compile .MC to .RC file to .RES file.
402 # * '-h dir' specifies the directory for the
403 # generated include file
404 # * '-r dir' specifies the target directory of the
405 # generated RC file and the binary message resource
406 # it includes
407 #
408 # For now (since there are no options to change this),
409 # we use the source-directory for the include file and
410 # the build directory for the RC file and message
411 # resources. This works at least for win32all.
412 h_dir = os.path.dirname(src)
413 rc_dir = os.path.dirname(obj)
414 try:
415 # first compile .MC to .RC and .H file
416 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
417 base, _ = os.path.splitext(os.path.basename (src))
418 rc_file = os.path.join(rc_dir, base + '.rc')
419 # then compile .RC to .RES file
420 self.spawn([self.rc, "/fo" + obj, rc_file])
421
422 except DistutilsExecError as msg:
423 raise CompileError(msg)
424 continue
425 else:
426 # how to handle this file?
427 raise CompileError("Don't know how to compile {} to {}"
428 .format(src, obj))
429
430 args = [self.cc] + compile_opts + pp_opts
431 if add_cpp_opts:
432 args.append('/EHsc')
433 args.append(input_opt)
434 args.append("/Fo" + obj)
435 args.extend(extra_postargs)
436
437 try:
438 self.spawn(args)
439 except DistutilsExecError as msg:
440 raise CompileError(msg)
441
442 return objects
443
444
445 def create_static_lib(self,
446 objects,
447 output_libname,
448 output_dir=None,
449 debug=0,
450 target_lang=None):
451
452 if not self.initialized:
453 self.initialize()
454 objects, output_dir = self._fix_object_args(objects, output_dir)
455 output_filename = self.library_filename(output_libname,
456 output_dir=output_dir)
457
458 if self._need_link(objects, output_filename):
459 lib_args = objects + ['/OUT:' + output_filename]
460 if debug:
461 pass # XXX what goes here?
462 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700463 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700464 self.spawn([self.lib] + lib_args)
465 except DistutilsExecError as msg:
466 raise LibError(msg)
467 else:
468 log.debug("skipping %s (up-to-date)", output_filename)
469
470
471 def link(self,
472 target_desc,
473 objects,
474 output_filename,
475 output_dir=None,
476 libraries=None,
477 library_dirs=None,
478 runtime_library_dirs=None,
479 export_symbols=None,
480 debug=0,
481 extra_preargs=None,
482 extra_postargs=None,
483 build_temp=None,
484 target_lang=None):
485
486 if not self.initialized:
487 self.initialize()
488 objects, output_dir = self._fix_object_args(objects, output_dir)
489 fixed_args = self._fix_lib_args(libraries, library_dirs,
490 runtime_library_dirs)
491 libraries, library_dirs, runtime_library_dirs = fixed_args
492
493 if runtime_library_dirs:
494 self.warn("I don't know what to do with 'runtime_library_dirs': "
495 + str(runtime_library_dirs))
496
497 lib_opts = gen_lib_options(self,
498 library_dirs, runtime_library_dirs,
499 libraries)
500 if output_dir is not None:
501 output_filename = os.path.join(output_dir, output_filename)
502
503 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700504 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700505
Steve Dower31202ea2015-08-05 11:39:19 -0700506 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700507
508 ld_args = (ldflags + lib_opts + export_opts +
509 objects + ['/OUT:' + output_filename])
510
511 # The MSVC linker generates .lib and .exp files, which cannot be
512 # suppressed by any linker switches. The .lib files may even be
513 # needed! Make sure they are generated in the temporary build
514 # directory. Since they have different names for debug and release
515 # builds, they can go into the same directory.
516 build_temp = os.path.dirname(objects[0])
517 if export_symbols is not None:
518 (dll_name, dll_ext) = os.path.splitext(
519 os.path.basename(output_filename))
520 implib_file = os.path.join(
521 build_temp,
522 self.library_filename(dll_name))
523 ld_args.append ('/IMPLIB:' + implib_file)
524
Steve Dowerfd3664b2015-05-23 09:02:50 -0700525 if extra_preargs:
526 ld_args[:0] = extra_preargs
527 if extra_postargs:
528 ld_args.extend(extra_postargs)
529
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700530 output_dir = os.path.dirname(os.path.abspath(output_filename))
531 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700532 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700533 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700534 self.spawn([self.linker] + ld_args)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700535 self._copy_vcruntime(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700536 except DistutilsExecError as msg:
537 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700538 else:
539 log.debug("skipping %s (up-to-date)", output_filename)
540
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700541 def _copy_vcruntime(self, output_dir):
542 vcruntime = self._vcruntime_redist
543 if not vcruntime or not os.path.isfile(vcruntime):
544 return
545
546 if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
547 return
548
549 log.debug('Copying "%s"', vcruntime)
550 vcruntime = shutil.copy(vcruntime, output_dir)
551 os.chmod(vcruntime, stat.S_IWRITE)
552
Steve Dower31202ea2015-08-05 11:39:19 -0700553 def spawn(self, cmd):
554 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700555 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700556 os.environ['path'] = self._paths
557 return super().spawn(cmd)
558 finally:
559 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700560
561 # -- Miscellaneous methods -----------------------------------------
562 # These are all used by the 'gen_lib_options() function, in
563 # ccompiler.py.
564
565 def library_dir_option(self, dir):
566 return "/LIBPATH:" + dir
567
568 def runtime_library_dir_option(self, dir):
569 raise DistutilsPlatformError(
570 "don't know how to set runtime library search path for MSVC")
571
572 def library_option(self, lib):
573 return self.library_filename(lib)
574
575 def find_library_file(self, dirs, lib, debug=0):
576 # Prefer a debugging library if found (and requested), but deal
577 # with it if we don't have one.
578 if debug:
579 try_names = [lib + "_d", lib]
580 else:
581 try_names = [lib]
582 for dir in dirs:
583 for name in try_names:
584 libfile = os.path.join(dir, self.library_filename(name))
585 if os.path.isfile(libfile):
586 return libfile
587 else:
588 # Oops, didn't find it in *any* of 'dirs'
589 return None