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