blob: a7976fbe3ed924efda902f221899e35147e6c5ec [file] [log] [blame]
Christian Heimescbf3b5c2007-12-03 21:02:03 +00001"""distutils.msvc9compiler
2
3Contains MSVCCompiler, an implementation of the abstract CCompiler class
4for the Microsoft Visual Studio 2008.
5
6The module is compatible with VS 2005 and VS 2008. You can find legacy support
7for older versions of VS in 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 VS2005 and VS 2008 by Christian Heimes
14
Christian Heimescbf3b5c2007-12-03 21:02:03 +000015import os
16import subprocess
17import sys
Martin v. Löwis1679ea82009-12-03 20:57:49 +000018import re
Tarek Ziadé63b64c02009-03-07 00:51:53 +000019
Tarek Ziadé36797272010-07-22 12:50:05 +000020from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
21 CompileError, LibError, LinkError
Victor Stinnere488e302020-04-30 11:28:09 +020022from distutils.ccompiler import CCompiler, gen_lib_options
Christian Heimescbf3b5c2007-12-03 21:02:03 +000023from distutils import log
Tarek Ziadé8b441d02010-01-29 11:46:31 +000024from distutils.util import get_platform
Christian Heimescbf3b5c2007-12-03 21:02:03 +000025
Tarek Ziadé8b441d02010-01-29 11:46:31 +000026import winreg
Tarek Ziadéedacea32010-01-29 11:41:03 +000027
Georg Brandl38feaf02008-05-25 07:45:51 +000028RegOpenKeyEx = winreg.OpenKeyEx
29RegEnumKey = winreg.EnumKey
30RegEnumValue = winreg.EnumValue
31RegError = winreg.error
Christian Heimescbf3b5c2007-12-03 21:02:03 +000032
Georg Brandl38feaf02008-05-25 07:45:51 +000033HKEYS = (winreg.HKEY_USERS,
34 winreg.HKEY_CURRENT_USER,
35 winreg.HKEY_LOCAL_MACHINE,
36 winreg.HKEY_CLASSES_ROOT)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000037
Benjamin Peterson31b16a52010-06-21 15:37:16 +000038NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)
39if NATIVE_WIN64:
40 # Visual C++ is a 32-bit application, so we need to look in
41 # the corresponding registry branch, if we're running a
42 # 64-bit Python on Win64
43 VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
44 WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"
45 NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"
46else:
47 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
48 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
49 NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimescbf3b5c2007-12-03 21:02:03 +000050
Christian Heimes5e696852008-04-09 08:37:03 +000051# A map keyed by get_platform() return values to values accepted by
52# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
Martin Panter46f50722016-05-26 05:35:26 +000053# the param to cross-compile on x86 targeting amd64.)
Christian Heimes5e696852008-04-09 08:37:03 +000054PLAT_TO_VCVARS = {
55 'win32' : 'x86',
56 'win-amd64' : 'amd64',
Christian Heimes5e696852008-04-09 08:37:03 +000057}
Christian Heimescbf3b5c2007-12-03 21:02:03 +000058
59class Reg:
60 """Helper class to read values from the registry
61 """
62
Christian Heimescbf3b5c2007-12-03 21:02:03 +000063 def get_value(cls, path, key):
64 for base in HKEYS:
65 d = cls.read_values(base, path)
66 if d and key in d:
67 return d[key]
68 raise KeyError(key)
Tarek Ziadé63b64c02009-03-07 00:51:53 +000069 get_value = classmethod(get_value)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000070
Christian Heimescbf3b5c2007-12-03 21:02:03 +000071 def read_keys(cls, base, key):
72 """Return list of registry keys."""
73 try:
74 handle = RegOpenKeyEx(base, key)
75 except RegError:
76 return None
77 L = []
78 i = 0
79 while True:
80 try:
81 k = RegEnumKey(handle, i)
82 except RegError:
83 break
84 L.append(k)
85 i += 1
86 return L
Tarek Ziadé63b64c02009-03-07 00:51:53 +000087 read_keys = classmethod(read_keys)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000088
Christian Heimescbf3b5c2007-12-03 21:02:03 +000089 def read_values(cls, base, key):
90 """Return dict of registry keys and values.
91
92 All names are converted to lowercase.
93 """
94 try:
95 handle = RegOpenKeyEx(base, key)
96 except RegError:
97 return None
98 d = {}
99 i = 0
100 while True:
101 try:
102 name, value, type = RegEnumValue(handle, i)
103 except RegError:
104 break
105 name = name.lower()
106 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
107 i += 1
108 return d
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000109 read_values = classmethod(read_values)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000110
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000111 def convert_mbcs(s):
112 dec = getattr(s, "decode", None)
113 if dec is not None:
114 try:
115 s = dec("mbcs")
116 except UnicodeError:
117 pass
118 return s
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000119 convert_mbcs = staticmethod(convert_mbcs)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000120
121class MacroExpander:
122
123 def __init__(self, version):
124 self.macros = {}
125 self.vsbase = VS_BASE % version
126 self.load_macros(version)
127
128 def set_macro(self, macro, path, key):
129 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
130
131 def load_macros(self, version):
132 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
133 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
134 self.set_macro("FrameworkDir", NET_BASE, "installroot")
135 try:
136 if version >= 8.0:
137 self.set_macro("FrameworkSDKDir", NET_BASE,
138 "sdkinstallrootv2.0")
139 else:
140 raise KeyError("sdkinstallrootv2.0")
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000141 except KeyError:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000142 raise DistutilsPlatformError(
143 """Python was built with Visual Studio 2008;
144extensions must be built with a compiler than can generate compatible binaries.
145Visual Studio 2008 was not found on this system. If you have Cygwin installed,
146you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
147
148 if version >= 9.0:
149 self.set_macro("FrameworkVersion", self.vsbase, "clr version")
150 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
151 else:
152 p = r"Software\Microsoft\NET Framework Setup\Product"
153 for base in HKEYS:
154 try:
155 h = RegOpenKeyEx(base, p)
156 except RegError:
157 continue
158 key = RegEnumKey(h, 0)
159 d = Reg.get_value(base, r"%s\%s" % (p, key))
160 self.macros["$(FrameworkVersion)"] = d["version"]
161
162 def sub(self, s):
163 for k, v in self.macros.items():
164 s = s.replace(k, v)
165 return s
166
167def get_build_version():
168 """Return the version of MSVC that was used to build Python.
169
170 For Python 2.3 and up, the version number is included in
171 sys.version. For earlier versions, assume the compiler is MSVC 6.
172 """
173 prefix = "MSC v."
174 i = sys.version.find(prefix)
175 if i == -1:
176 return 6
177 i = i + len(prefix)
178 s, rest = sys.version[i:].split(" ", 1)
179 majorVersion = int(s[:-2]) - 6
Steve Dower65e4cb12014-11-22 12:54:57 -0800180 if majorVersion >= 13:
181 # v13 was skipped and should be v14
182 majorVersion += 1
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000183 minorVersion = int(s[2:3]) / 10.0
184 # I don't think paths are affected by minor version in version 6
185 if majorVersion == 6:
186 minorVersion = 0
187 if majorVersion >= 6:
188 return majorVersion + minorVersion
189 # else we don't know what version of the compiler this is
190 return None
191
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000192def normalize_and_reduce_paths(paths):
193 """Return a list of normalized paths with duplicates removed.
194
195 The current order of paths is maintained.
196 """
197 # Paths are normalized so things like: /a and /a/ aren't both preserved.
198 reduced_paths = []
199 for p in paths:
200 np = os.path.normpath(p)
201 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
202 if np not in reduced_paths:
203 reduced_paths.append(np)
204 return reduced_paths
205
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000206def removeDuplicates(variable):
207 """Remove duplicate values of an environment variable.
208 """
209 oldList = variable.split(os.pathsep)
210 newList = []
211 for i in oldList:
212 if i not in newList:
213 newList.append(i)
214 newVariable = os.pathsep.join(newList)
215 return newVariable
216
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000217def find_vcvarsall(version):
218 """Find the vcvarsall.bat file
219
220 At first it tries to find the productdir of VS 2008 in the registry. If
221 that fails it falls back to the VS90COMNTOOLS env var.
222 """
223 vsbase = VS_BASE % version
224 try:
225 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
226 "productdir")
227 except KeyError:
228 log.debug("Unable to find productdir in registry")
229 productdir = None
230
231 if not productdir or not os.path.isdir(productdir):
232 toolskey = "VS%0.f0COMNTOOLS" % version
233 toolsdir = os.environ.get(toolskey, None)
234
235 if toolsdir and os.path.isdir(toolsdir):
236 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
237 productdir = os.path.abspath(productdir)
238 if not os.path.isdir(productdir):
239 log.debug("%s is not a valid directory" % productdir)
240 return None
241 else:
242 log.debug("Env var %s is not set or invalid" % toolskey)
243 if not productdir:
244 log.debug("No productdir found")
245 return None
246 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
247 if os.path.isfile(vcvarsall):
248 return vcvarsall
249 log.debug("Unable to find vcvarsall.bat")
250 return None
251
252def query_vcvarsall(version, arch="x86"):
253 """Launch vcvarsall.bat and read the settings from its environment
254 """
255 vcvarsall = find_vcvarsall(version)
Jon Dufresne39726282017-05-18 07:35:54 -0700256 interesting = {"include", "lib", "libpath", "path"}
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000257 result = {}
258
259 if vcvarsall is None:
Tarek Ziadé9df8ce32008-12-30 23:09:20 +0000260 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Christian Heimes5e696852008-04-09 08:37:03 +0000261 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000262 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
263 stdout=subprocess.PIPE,
264 stderr=subprocess.PIPE)
Éric Araujo5ac6d802010-11-06 02:10:32 +0000265 try:
266 stdout, stderr = popen.communicate()
267 if popen.wait() != 0:
268 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000269
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000270 stdout = stdout.decode("mbcs")
271 for line in stdout.split("\n"):
272 line = Reg.convert_mbcs(line)
273 if '=' not in line:
274 continue
275 line = line.strip()
276 key, value = line.split('=', 1)
277 key = key.lower()
278 if key in interesting:
279 if value.endswith(os.pathsep):
280 value = value[:-1]
281 result[key] = removeDuplicates(value)
282
283 finally:
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000284 popen.stdout.close()
285 popen.stderr.close()
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000286
287 if len(result) != len(interesting):
288 raise ValueError(str(list(result.keys())))
289
290 return result
291
292# More globals
293VERSION = get_build_version()
294if VERSION < 8.0:
295 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000296# MACROS = MacroExpander(VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000297
298class MSVCCompiler(CCompiler) :
299 """Concrete class that implements an interface to Microsoft Visual C++,
300 as defined by the CCompiler abstract class."""
301
302 compiler_type = 'msvc'
303
304 # Just set this so CCompiler's constructor doesn't barf. We currently
305 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
306 # as it really isn't necessary for this sort of single-compiler class.
307 # Would be nice to have a consistent interface with UnixCCompiler,
308 # though, so it's worth thinking about.
309 executables = {}
310
311 # Private class data (need to distinguish C from C++ source for compiler)
312 _c_extensions = ['.c']
313 _cpp_extensions = ['.cc', '.cpp', '.cxx']
314 _rc_extensions = ['.rc']
315 _mc_extensions = ['.mc']
316
317 # Needed for the filename generation methods provided by the
318 # base class, CCompiler.
319 src_extensions = (_c_extensions + _cpp_extensions +
320 _rc_extensions + _mc_extensions)
321 res_extension = '.res'
322 obj_extension = '.obj'
323 static_lib_extension = '.lib'
324 shared_lib_extension = '.dll'
325 static_lib_format = shared_lib_format = '%s%s'
326 exe_extension = '.exe'
327
328 def __init__(self, verbose=0, dry_run=0, force=0):
329 CCompiler.__init__ (self, verbose, dry_run, force)
330 self.__version = VERSION
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000331 self.__root = r"Software\Microsoft\VisualStudio"
332 # self.__macros = MACROS
Christian Heimes94e07722008-11-28 11:05:17 +0000333 self.__paths = []
Christian Heimes5e696852008-04-09 08:37:03 +0000334 # target platform (.plat_name is consistent with 'bdist')
335 self.plat_name = None
336 self.__arch = None # deprecated name
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000337 self.initialized = False
338
Christian Heimes5e696852008-04-09 08:37:03 +0000339 def initialize(self, plat_name=None):
340 # multi-init means we would need to check platform same each time...
341 assert not self.initialized, "don't init multiple times"
342 if plat_name is None:
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000343 plat_name = get_platform()
Christian Heimes5e696852008-04-09 08:37:03 +0000344 # sanity check for platforms to prevent obscure errors later.
Jason R. Coombsfbf75b92021-03-04 13:41:49 -0500345 ok_plats = 'win32', 'win-amd64'
Christian Heimes5e696852008-04-09 08:37:03 +0000346 if plat_name not in ok_plats:
347 raise DistutilsPlatformError("--plat-name must be one of %s" %
348 (ok_plats,))
349
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000350 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
351 # Assume that the SDK set up everything alright; don't try to be
352 # smarter
353 self.cc = "cl.exe"
354 self.linker = "link.exe"
355 self.lib = "lib.exe"
356 self.rc = "rc.exe"
357 self.mc = "mc.exe"
358 else:
Christian Heimes5e696852008-04-09 08:37:03 +0000359 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
360 # to cross compile, you use 'x86_amd64'.
361 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
362 # compile use 'x86' (ie, it runs the x86 compiler directly)
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000363 if plat_name == get_platform() or plat_name == 'win32':
Christian Heimes5e696852008-04-09 08:37:03 +0000364 # native build or cross-compile to win32
365 plat_spec = PLAT_TO_VCVARS[plat_name]
366 else:
367 # cross compile from win32 -> some 64bit
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000368 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
Christian Heimes5e696852008-04-09 08:37:03 +0000369 PLAT_TO_VCVARS[plat_name]
370
371 vc_env = query_vcvarsall(VERSION, plat_spec)
372
373 self.__paths = vc_env['path'].split(os.pathsep)
374 os.environ['lib'] = vc_env['lib']
375 os.environ['include'] = vc_env['include']
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000376
377 if len(self.__paths) == 0:
378 raise DistutilsPlatformError("Python was built with %s, "
379 "and extensions need to be built with the same "
380 "version of the compiler, but it isn't installed."
381 % self.__product)
382
383 self.cc = self.find_exe("cl.exe")
384 self.linker = self.find_exe("link.exe")
385 self.lib = self.find_exe("lib.exe")
386 self.rc = self.find_exe("rc.exe") # resource compiler
387 self.mc = self.find_exe("mc.exe") # message compiler
388 #self.set_path_env_var('lib')
389 #self.set_path_env_var('include')
390
391 # extend the MSVC path with the current path
392 try:
393 for p in os.environ['path'].split(';'):
394 self.__paths.append(p)
395 except KeyError:
396 pass
397 self.__paths = normalize_and_reduce_paths(self.__paths)
398 os.environ['path'] = ";".join(self.__paths)
399
400 self.preprocess_options = None
401 if self.__arch == "x86":
402 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
403 '/DNDEBUG']
404 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
405 '/Z7', '/D_DEBUG']
406 else:
407 # Win64
408 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
409 '/DNDEBUG']
410 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
411 '/Z7', '/D_DEBUG']
412
413 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
414 if self.__version >= 7:
415 self.ldflags_shared_debug = [
Steve Dower3a7ffa72015-08-07 19:48:03 -0700416 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000417 ]
418 self.ldflags_static = [ '/nologo']
419
420 self.initialized = True
421
422 # -- Worker methods ------------------------------------------------
423
424 def object_filenames(self,
425 source_filenames,
426 strip_dir=0,
427 output_dir=''):
428 # Copied from ccompiler.py, extended to return .res as 'object'-file
429 # for .rc input file
430 if output_dir is None: output_dir = ''
431 obj_names = []
432 for src_name in source_filenames:
433 (base, ext) = os.path.splitext (src_name)
434 base = os.path.splitdrive(base)[1] # Chop off the drive
435 base = base[os.path.isabs(base):] # If abs, chop off leading /
436 if ext not in self.src_extensions:
437 # Better to raise an exception instead of silently continuing
438 # and later complain about sources and targets having
439 # different lengths
440 raise CompileError ("Don't know how to compile %s" % src_name)
441 if strip_dir:
442 base = os.path.basename (base)
443 if ext in self._rc_extensions:
444 obj_names.append (os.path.join (output_dir,
445 base + self.res_extension))
446 elif ext in self._mc_extensions:
447 obj_names.append (os.path.join (output_dir,
448 base + self.res_extension))
449 else:
450 obj_names.append (os.path.join (output_dir,
451 base + self.obj_extension))
452 return obj_names
453
454
455 def compile(self, sources,
456 output_dir=None, macros=None, include_dirs=None, debug=0,
457 extra_preargs=None, extra_postargs=None, depends=None):
458
459 if not self.initialized:
460 self.initialize()
461 compile_info = self._setup_compile(output_dir, macros, include_dirs,
462 sources, depends, extra_postargs)
463 macros, objects, extra_postargs, pp_opts, build = compile_info
464
465 compile_opts = extra_preargs or []
466 compile_opts.append ('/c')
467 if debug:
468 compile_opts.extend(self.compile_options_debug)
469 else:
470 compile_opts.extend(self.compile_options)
471
472 for obj in objects:
473 try:
474 src, ext = build[obj]
475 except KeyError:
476 continue
477 if debug:
478 # pass the full pathname to MSVC in debug mode,
479 # this allows the debugger to find the source file
480 # without asking the user to browse for it
481 src = os.path.abspath(src)
482
483 if ext in self._c_extensions:
484 input_opt = "/Tc" + src
485 elif ext in self._cpp_extensions:
486 input_opt = "/Tp" + src
487 elif ext in self._rc_extensions:
488 # compile .RC to .RES file
489 input_opt = src
490 output_opt = "/fo" + obj
491 try:
492 self.spawn([self.rc] + pp_opts +
493 [output_opt] + [input_opt])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000494 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000495 raise CompileError(msg)
496 continue
497 elif ext in self._mc_extensions:
498 # Compile .MC to .RC file to .RES file.
499 # * '-h dir' specifies the directory for the
500 # generated include file
501 # * '-r dir' specifies the target directory of the
502 # generated RC file and the binary message resource
503 # it includes
504 #
505 # For now (since there are no options to change this),
506 # we use the source-directory for the include file and
507 # the build directory for the RC file and message
508 # resources. This works at least for win32all.
509 h_dir = os.path.dirname(src)
510 rc_dir = os.path.dirname(obj)
511 try:
512 # first compile .MC to .RC and .H file
513 self.spawn([self.mc] +
514 ['-h', h_dir, '-r', rc_dir] + [src])
515 base, _ = os.path.splitext (os.path.basename (src))
516 rc_file = os.path.join (rc_dir, base + '.rc')
517 # then compile .RC to .RES file
518 self.spawn([self.rc] +
519 ["/fo" + obj] + [rc_file])
520
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000521 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000522 raise CompileError(msg)
523 continue
524 else:
525 # how to handle this file?
526 raise CompileError("Don't know how to compile %s to %s"
527 % (src, obj))
528
529 output_opt = "/Fo" + obj
530 try:
531 self.spawn([self.cc] + compile_opts + pp_opts +
532 [input_opt, output_opt] +
533 extra_postargs)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000534 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000535 raise CompileError(msg)
536
537 return objects
538
539
540 def create_static_lib(self,
541 objects,
542 output_libname,
543 output_dir=None,
544 debug=0,
545 target_lang=None):
546
547 if not self.initialized:
548 self.initialize()
549 (objects, output_dir) = self._fix_object_args(objects, output_dir)
550 output_filename = self.library_filename(output_libname,
551 output_dir=output_dir)
552
553 if self._need_link(objects, output_filename):
554 lib_args = objects + ['/OUT:' + output_filename]
555 if debug:
556 pass # XXX what goes here?
557 try:
558 self.spawn([self.lib] + lib_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000559 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000560 raise LibError(msg)
561 else:
562 log.debug("skipping %s (up-to-date)", output_filename)
563
564
565 def link(self,
566 target_desc,
567 objects,
568 output_filename,
569 output_dir=None,
570 libraries=None,
571 library_dirs=None,
572 runtime_library_dirs=None,
573 export_symbols=None,
574 debug=0,
575 extra_preargs=None,
576 extra_postargs=None,
577 build_temp=None,
578 target_lang=None):
579
580 if not self.initialized:
581 self.initialize()
582 (objects, output_dir) = self._fix_object_args(objects, output_dir)
583 fixed_args = self._fix_lib_args(libraries, library_dirs,
584 runtime_library_dirs)
585 (libraries, library_dirs, runtime_library_dirs) = fixed_args
586
587 if runtime_library_dirs:
588 self.warn ("I don't know what to do with 'runtime_library_dirs': "
589 + str (runtime_library_dirs))
590
591 lib_opts = gen_lib_options(self,
592 library_dirs, runtime_library_dirs,
593 libraries)
594 if output_dir is not None:
595 output_filename = os.path.join(output_dir, output_filename)
596
597 if self._need_link(objects, output_filename):
598 if target_desc == CCompiler.EXECUTABLE:
599 if debug:
600 ldflags = self.ldflags_shared_debug[1:]
601 else:
602 ldflags = self.ldflags_shared[1:]
603 else:
604 if debug:
605 ldflags = self.ldflags_shared_debug
606 else:
607 ldflags = self.ldflags_shared
608
609 export_opts = []
610 for sym in (export_symbols or []):
611 export_opts.append("/EXPORT:" + sym)
612
613 ld_args = (ldflags + lib_opts + export_opts +
614 objects + ['/OUT:' + output_filename])
615
616 # The MSVC linker generates .lib and .exp files, which cannot be
617 # suppressed by any linker switches. The .lib files may even be
618 # needed! Make sure they are generated in the temporary build
619 # directory. Since they have different names for debug and release
620 # builds, they can go into the same directory.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000621 build_temp = os.path.dirname(objects[0])
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000622 if export_symbols is not None:
623 (dll_name, dll_ext) = os.path.splitext(
624 os.path.basename(output_filename))
625 implib_file = os.path.join(
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000626 build_temp,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000627 self.library_filename(dll_name))
628 ld_args.append ('/IMPLIB:' + implib_file)
629
Mark Hammond6c58b282011-10-17 11:05:57 +1100630 self.manifest_setup_ldargs(output_filename, build_temp, ld_args)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000631
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000632 if extra_preargs:
633 ld_args[:0] = extra_preargs
634 if extra_postargs:
635 ld_args.extend(extra_postargs)
636
637 self.mkpath(os.path.dirname(output_filename))
638 try:
639 self.spawn([self.linker] + ld_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000640 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000641 raise LinkError(msg)
642
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000643 # embed the manifest
644 # XXX - this is somewhat fragile - if mt.exe fails, distutils
645 # will still consider the DLL up-to-date, but it will not have a
646 # manifest. Maybe we should link to a temp file? OTOH, that
647 # implies a build environment error that shouldn't go undetected.
Mark Hammond6c58b282011-10-17 11:05:57 +1100648 mfinfo = self.manifest_get_embed_info(target_desc, ld_args)
649 if mfinfo is not None:
650 mffilename, mfid = mfinfo
651 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
652 try:
653 self.spawn(['mt.exe', '-nologo', '-manifest',
654 mffilename, out_arg])
655 except DistutilsExecError as msg:
656 raise LinkError(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000657 else:
658 log.debug("skipping %s (up-to-date)", output_filename)
659
Mark Hammond6c58b282011-10-17 11:05:57 +1100660 def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
661 # If we need a manifest at all, an embedded manifest is recommended.
662 # See MSDN article titled
663 # "How to: Embed a Manifest Inside a C/C++ Application"
664 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
665 # Ask the linker to generate the manifest in the temp dir, so
666 # we can check it, and possibly embed it, later.
667 temp_manifest = os.path.join(
668 build_temp,
669 os.path.basename(output_filename) + ".manifest")
670 ld_args.append('/MANIFESTFILE:' + temp_manifest)
671
672 def manifest_get_embed_info(self, target_desc, ld_args):
673 # If a manifest should be embedded, return a tuple of
674 # (manifest_filename, resource_id). Returns None if no manifest
675 # should be embedded. See http://bugs.python.org/issue7833 for why
Łukasz Langa8c1e1da2021-09-22 01:33:59 +0200676 # we want to avoid any manifest for extension modules if we can.
Mark Hammond6c58b282011-10-17 11:05:57 +1100677 for arg in ld_args:
678 if arg.startswith("/MANIFESTFILE:"):
679 temp_manifest = arg.split(":", 1)[1]
680 break
681 else:
682 # no /MANIFESTFILE so nothing to do.
683 return None
684 if target_desc == CCompiler.EXECUTABLE:
685 # by default, executables always get the manifest with the
686 # CRT referenced.
687 mfid = 1
688 else:
689 # Extension modules try and avoid any manifest if possible.
690 mfid = 2
691 temp_manifest = self._remove_visual_c_ref(temp_manifest)
692 if temp_manifest is None:
693 return None
694 return temp_manifest, mfid
695
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000696 def _remove_visual_c_ref(self, manifest_file):
697 try:
698 # Remove references to the Visual C runtime, so they will
699 # fall through to the Visual C dependency of Python.exe.
700 # This way, when installed for a restricted user (e.g.
701 # runtimes are not in WinSxS folder, but in Python's own
702 # folder), the runtimes do not need to be in every folder
703 # with .pyd's.
Mark Hammond6c58b282011-10-17 11:05:57 +1100704 # Returns either the filename of the modified manifest or
705 # None if no manifest should be embedded.
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000706 manifest_f = open(manifest_file)
707 try:
708 manifest_buf = manifest_f.read()
709 finally:
710 manifest_f.close()
711 pattern = re.compile(
712 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
713 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
714 re.DOTALL)
715 manifest_buf = re.sub(pattern, "", manifest_buf)
R David Murray44b548d2016-09-08 13:59:53 -0400716 pattern = r"<dependentAssembly>\s*</dependentAssembly>"
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000717 manifest_buf = re.sub(pattern, "", manifest_buf)
Mark Hammond53e4a9a2011-10-17 11:35:31 +1100718 # Now see if any other assemblies are referenced - if not, we
Mark Hammond6c58b282011-10-17 11:05:57 +1100719 # don't want a manifest embedded.
720 pattern = re.compile(
721 r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""
722 r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)
723 if re.search(pattern, manifest_buf) is None:
724 return None
725
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000726 manifest_f = open(manifest_file, 'w')
727 try:
728 manifest_f.write(manifest_buf)
Mark Hammond6c58b282011-10-17 11:05:57 +1100729 return manifest_file
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000730 finally:
731 manifest_f.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200732 except OSError:
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000733 pass
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000734
735 # -- Miscellaneous methods -----------------------------------------
736 # These are all used by the 'gen_lib_options() function, in
737 # ccompiler.py.
738
739 def library_dir_option(self, dir):
740 return "/LIBPATH:" + dir
741
742 def runtime_library_dir_option(self, dir):
743 raise DistutilsPlatformError(
744 "don't know how to set runtime library search path for MSVC++")
745
746 def library_option(self, lib):
747 return self.library_filename(lib)
748
749
750 def find_library_file(self, dirs, lib, debug=0):
751 # Prefer a debugging library if found (and requested), but deal
752 # with it if we don't have one.
753 if debug:
754 try_names = [lib + "_d", lib]
755 else:
756 try_names = [lib]
757 for dir in dirs:
758 for name in try_names:
759 libfile = os.path.join(dir, self.library_filename (name))
760 if os.path.exists(libfile):
761 return libfile
762 else:
763 # Oops, didn't find it in *any* of 'dirs'
764 return None
765
766 # Helper methods for using the MSVC registry settings
767
768 def find_exe(self, exe):
769 """Return path to an MSVC executable program.
770
771 Tries to find the program in several places: first, one of the
772 MSVC program search paths from the registry; next, the directories
773 in the PATH environment variable. If any of those work, return an
774 absolute path that is known to exist. If none of them work, just
775 return the original program name, 'exe'.
776 """
777 for p in self.__paths:
778 fn = os.path.join(os.path.abspath(p), exe)
779 if os.path.isfile(fn):
780 return fn
781
782 # didn't find it; try existing path
783 for p in os.environ['Path'].split(';'):
784 fn = os.path.join(os.path.abspath(p),exe)
785 if os.path.isfile(fn):
786 return fn
787
788 return exe