blob: c84fb0b4a688f0321254197c799047598b3efdf6 [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
15__revision__ = "$Id$"
16
17import os
18import subprocess
19import sys
Martin v. Löwis1679ea82009-12-03 20:57:49 +000020import re
Tarek Ziadé63b64c02009-03-07 00:51:53 +000021
22from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
23 CompileError, LibError, LinkError
24from distutils.ccompiler import CCompiler, gen_preprocess_options, \
25 gen_lib_options
Christian Heimescbf3b5c2007-12-03 21:02:03 +000026from distutils import log
Christian Heimes5e696852008-04-09 08:37:03 +000027from distutils.util import get_platform
Christian Heimescbf3b5c2007-12-03 21:02:03 +000028
Georg Brandl38feaf02008-05-25 07:45:51 +000029import winreg
Christian Heimescbf3b5c2007-12-03 21:02:03 +000030
Georg Brandl38feaf02008-05-25 07:45:51 +000031RegOpenKeyEx = winreg.OpenKeyEx
32RegEnumKey = winreg.EnumKey
33RegEnumValue = winreg.EnumValue
34RegError = winreg.error
Christian Heimescbf3b5c2007-12-03 21:02:03 +000035
Georg Brandl38feaf02008-05-25 07:45:51 +000036HKEYS = (winreg.HKEY_USERS,
37 winreg.HKEY_CURRENT_USER,
38 winreg.HKEY_LOCAL_MACHINE,
39 winreg.HKEY_CLASSES_ROOT)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000040
41VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
42WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
43NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimescbf3b5c2007-12-03 21:02:03 +000044
Christian Heimes5e696852008-04-09 08:37:03 +000045# A map keyed by get_platform() return values to values accepted by
46# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
47# the param to cross-compile on x86 targetting amd64.)
48PLAT_TO_VCVARS = {
49 'win32' : 'x86',
50 'win-amd64' : 'amd64',
51 'win-ia64' : 'ia64',
52}
Christian Heimescbf3b5c2007-12-03 21:02:03 +000053
54class Reg:
55 """Helper class to read values from the registry
56 """
57
Christian Heimescbf3b5c2007-12-03 21:02:03 +000058 def get_value(cls, path, key):
59 for base in HKEYS:
60 d = cls.read_values(base, path)
61 if d and key in d:
62 return d[key]
63 raise KeyError(key)
Tarek Ziadé63b64c02009-03-07 00:51:53 +000064 get_value = classmethod(get_value)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000065
Christian Heimescbf3b5c2007-12-03 21:02:03 +000066 def read_keys(cls, base, key):
67 """Return list of registry keys."""
68 try:
69 handle = RegOpenKeyEx(base, key)
70 except RegError:
71 return None
72 L = []
73 i = 0
74 while True:
75 try:
76 k = RegEnumKey(handle, i)
77 except RegError:
78 break
79 L.append(k)
80 i += 1
81 return L
Tarek Ziadé63b64c02009-03-07 00:51:53 +000082 read_keys = classmethod(read_keys)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000083
Christian Heimescbf3b5c2007-12-03 21:02:03 +000084 def read_values(cls, base, key):
85 """Return dict of registry keys and values.
86
87 All names are converted to lowercase.
88 """
89 try:
90 handle = RegOpenKeyEx(base, key)
91 except RegError:
92 return None
93 d = {}
94 i = 0
95 while True:
96 try:
97 name, value, type = RegEnumValue(handle, i)
98 except RegError:
99 break
100 name = name.lower()
101 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
102 i += 1
103 return d
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000104 read_values = classmethod(read_values)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000105
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000106 def convert_mbcs(s):
107 dec = getattr(s, "decode", None)
108 if dec is not None:
109 try:
110 s = dec("mbcs")
111 except UnicodeError:
112 pass
113 return s
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000114 convert_mbcs = staticmethod(convert_mbcs)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000115
116class MacroExpander:
117
118 def __init__(self, version):
119 self.macros = {}
120 self.vsbase = VS_BASE % version
121 self.load_macros(version)
122
123 def set_macro(self, macro, path, key):
124 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
125
126 def load_macros(self, version):
127 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
128 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
129 self.set_macro("FrameworkDir", NET_BASE, "installroot")
130 try:
131 if version >= 8.0:
132 self.set_macro("FrameworkSDKDir", NET_BASE,
133 "sdkinstallrootv2.0")
134 else:
135 raise KeyError("sdkinstallrootv2.0")
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000136 except KeyError:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000137 raise DistutilsPlatformError(
138 """Python was built with Visual Studio 2008;
139extensions must be built with a compiler than can generate compatible binaries.
140Visual Studio 2008 was not found on this system. If you have Cygwin installed,
141you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
142
143 if version >= 9.0:
144 self.set_macro("FrameworkVersion", self.vsbase, "clr version")
145 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
146 else:
147 p = r"Software\Microsoft\NET Framework Setup\Product"
148 for base in HKEYS:
149 try:
150 h = RegOpenKeyEx(base, p)
151 except RegError:
152 continue
153 key = RegEnumKey(h, 0)
154 d = Reg.get_value(base, r"%s\%s" % (p, key))
155 self.macros["$(FrameworkVersion)"] = d["version"]
156
157 def sub(self, s):
158 for k, v in self.macros.items():
159 s = s.replace(k, v)
160 return s
161
162def get_build_version():
163 """Return the version of MSVC that was used to build Python.
164
165 For Python 2.3 and up, the version number is included in
166 sys.version. For earlier versions, assume the compiler is MSVC 6.
167 """
168 prefix = "MSC v."
169 i = sys.version.find(prefix)
170 if i == -1:
171 return 6
172 i = i + len(prefix)
173 s, rest = sys.version[i:].split(" ", 1)
174 majorVersion = int(s[:-2]) - 6
175 minorVersion = int(s[2:3]) / 10.0
176 # I don't think paths are affected by minor version in version 6
177 if majorVersion == 6:
178 minorVersion = 0
179 if majorVersion >= 6:
180 return majorVersion + minorVersion
181 # else we don't know what version of the compiler this is
182 return None
183
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000184def normalize_and_reduce_paths(paths):
185 """Return a list of normalized paths with duplicates removed.
186
187 The current order of paths is maintained.
188 """
189 # Paths are normalized so things like: /a and /a/ aren't both preserved.
190 reduced_paths = []
191 for p in paths:
192 np = os.path.normpath(p)
193 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
194 if np not in reduced_paths:
195 reduced_paths.append(np)
196 return reduced_paths
197
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000198def removeDuplicates(variable):
199 """Remove duplicate values of an environment variable.
200 """
201 oldList = variable.split(os.pathsep)
202 newList = []
203 for i in oldList:
204 if i not in newList:
205 newList.append(i)
206 newVariable = os.pathsep.join(newList)
207 return newVariable
208
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000209def find_vcvarsall(version):
210 """Find the vcvarsall.bat file
211
212 At first it tries to find the productdir of VS 2008 in the registry. If
213 that fails it falls back to the VS90COMNTOOLS env var.
214 """
215 vsbase = VS_BASE % version
216 try:
217 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
218 "productdir")
219 except KeyError:
220 log.debug("Unable to find productdir in registry")
221 productdir = None
222
223 if not productdir or not os.path.isdir(productdir):
224 toolskey = "VS%0.f0COMNTOOLS" % version
225 toolsdir = os.environ.get(toolskey, None)
226
227 if toolsdir and os.path.isdir(toolsdir):
228 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
229 productdir = os.path.abspath(productdir)
230 if not os.path.isdir(productdir):
231 log.debug("%s is not a valid directory" % productdir)
232 return None
233 else:
234 log.debug("Env var %s is not set or invalid" % toolskey)
235 if not productdir:
236 log.debug("No productdir found")
237 return None
238 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
239 if os.path.isfile(vcvarsall):
240 return vcvarsall
241 log.debug("Unable to find vcvarsall.bat")
242 return None
243
244def query_vcvarsall(version, arch="x86"):
245 """Launch vcvarsall.bat and read the settings from its environment
246 """
247 vcvarsall = find_vcvarsall(version)
248 interesting = set(("include", "lib", "libpath", "path"))
249 result = {}
250
251 if vcvarsall is None:
Tarek Ziadé9df8ce32008-12-30 23:09:20 +0000252 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Christian Heimes5e696852008-04-09 08:37:03 +0000253 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000254 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
255 stdout=subprocess.PIPE,
256 stderr=subprocess.PIPE)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000257
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000258 stdout, stderr = popen.communicate()
259 if popen.wait() != 0:
Tarek Ziadé9df8ce32008-12-30 23:09:20 +0000260 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000261
262 stdout = stdout.decode("mbcs")
263 for line in stdout.split("\n"):
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000264 line = Reg.convert_mbcs(line)
265 if '=' not in line:
266 continue
267 line = line.strip()
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000268 key, value = line.split('=', 1)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000269 key = key.lower()
270 if key in interesting:
271 if value.endswith(os.pathsep):
272 value = value[:-1]
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000273 result[key] = removeDuplicates(value)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000274
275 if len(result) != len(interesting):
276 raise ValueError(str(list(result.keys())))
277
278 return result
279
280# More globals
281VERSION = get_build_version()
282if VERSION < 8.0:
283 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000284# MACROS = MacroExpander(VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000285
286class MSVCCompiler(CCompiler) :
287 """Concrete class that implements an interface to Microsoft Visual C++,
288 as defined by the CCompiler abstract class."""
289
290 compiler_type = 'msvc'
291
292 # Just set this so CCompiler's constructor doesn't barf. We currently
293 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
294 # as it really isn't necessary for this sort of single-compiler class.
295 # Would be nice to have a consistent interface with UnixCCompiler,
296 # though, so it's worth thinking about.
297 executables = {}
298
299 # Private class data (need to distinguish C from C++ source for compiler)
300 _c_extensions = ['.c']
301 _cpp_extensions = ['.cc', '.cpp', '.cxx']
302 _rc_extensions = ['.rc']
303 _mc_extensions = ['.mc']
304
305 # Needed for the filename generation methods provided by the
306 # base class, CCompiler.
307 src_extensions = (_c_extensions + _cpp_extensions +
308 _rc_extensions + _mc_extensions)
309 res_extension = '.res'
310 obj_extension = '.obj'
311 static_lib_extension = '.lib'
312 shared_lib_extension = '.dll'
313 static_lib_format = shared_lib_format = '%s%s'
314 exe_extension = '.exe'
315
316 def __init__(self, verbose=0, dry_run=0, force=0):
317 CCompiler.__init__ (self, verbose, dry_run, force)
318 self.__version = VERSION
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000319 self.__root = r"Software\Microsoft\VisualStudio"
320 # self.__macros = MACROS
Christian Heimes94e07722008-11-28 11:05:17 +0000321 self.__paths = []
Christian Heimes5e696852008-04-09 08:37:03 +0000322 # target platform (.plat_name is consistent with 'bdist')
323 self.plat_name = None
324 self.__arch = None # deprecated name
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000325 self.initialized = False
326
Christian Heimes5e696852008-04-09 08:37:03 +0000327 def initialize(self, plat_name=None):
328 # multi-init means we would need to check platform same each time...
329 assert not self.initialized, "don't init multiple times"
330 if plat_name is None:
331 plat_name = get_platform()
332 # sanity check for platforms to prevent obscure errors later.
333 ok_plats = 'win32', 'win-amd64', 'win-ia64'
334 if plat_name not in ok_plats:
335 raise DistutilsPlatformError("--plat-name must be one of %s" %
336 (ok_plats,))
337
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000338 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
339 # Assume that the SDK set up everything alright; don't try to be
340 # smarter
341 self.cc = "cl.exe"
342 self.linker = "link.exe"
343 self.lib = "lib.exe"
344 self.rc = "rc.exe"
345 self.mc = "mc.exe"
346 else:
Christian Heimes5e696852008-04-09 08:37:03 +0000347 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
348 # to cross compile, you use 'x86_amd64'.
349 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
350 # compile use 'x86' (ie, it runs the x86 compiler directly)
351 # No idea how itanium handles this, if at all.
352 if plat_name == get_platform() or plat_name == 'win32':
353 # native build or cross-compile to win32
354 plat_spec = PLAT_TO_VCVARS[plat_name]
355 else:
356 # cross compile from win32 -> some 64bit
357 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
358 PLAT_TO_VCVARS[plat_name]
359
360 vc_env = query_vcvarsall(VERSION, plat_spec)
361
362 self.__paths = vc_env['path'].split(os.pathsep)
363 os.environ['lib'] = vc_env['lib']
364 os.environ['include'] = vc_env['include']
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000365
366 if len(self.__paths) == 0:
367 raise DistutilsPlatformError("Python was built with %s, "
368 "and extensions need to be built with the same "
369 "version of the compiler, but it isn't installed."
370 % self.__product)
371
372 self.cc = self.find_exe("cl.exe")
373 self.linker = self.find_exe("link.exe")
374 self.lib = self.find_exe("lib.exe")
375 self.rc = self.find_exe("rc.exe") # resource compiler
376 self.mc = self.find_exe("mc.exe") # message compiler
377 #self.set_path_env_var('lib')
378 #self.set_path_env_var('include')
379
380 # extend the MSVC path with the current path
381 try:
382 for p in os.environ['path'].split(';'):
383 self.__paths.append(p)
384 except KeyError:
385 pass
386 self.__paths = normalize_and_reduce_paths(self.__paths)
387 os.environ['path'] = ";".join(self.__paths)
388
389 self.preprocess_options = None
390 if self.__arch == "x86":
391 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
392 '/DNDEBUG']
393 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
394 '/Z7', '/D_DEBUG']
395 else:
396 # Win64
397 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
398 '/DNDEBUG']
399 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
400 '/Z7', '/D_DEBUG']
401
402 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
403 if self.__version >= 7:
404 self.ldflags_shared_debug = [
405 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
406 ]
407 self.ldflags_static = [ '/nologo']
408
409 self.initialized = True
410
411 # -- Worker methods ------------------------------------------------
412
413 def object_filenames(self,
414 source_filenames,
415 strip_dir=0,
416 output_dir=''):
417 # Copied from ccompiler.py, extended to return .res as 'object'-file
418 # for .rc input file
419 if output_dir is None: output_dir = ''
420 obj_names = []
421 for src_name in source_filenames:
422 (base, ext) = os.path.splitext (src_name)
423 base = os.path.splitdrive(base)[1] # Chop off the drive
424 base = base[os.path.isabs(base):] # If abs, chop off leading /
425 if ext not in self.src_extensions:
426 # Better to raise an exception instead of silently continuing
427 # and later complain about sources and targets having
428 # different lengths
429 raise CompileError ("Don't know how to compile %s" % src_name)
430 if strip_dir:
431 base = os.path.basename (base)
432 if ext in self._rc_extensions:
433 obj_names.append (os.path.join (output_dir,
434 base + self.res_extension))
435 elif ext in self._mc_extensions:
436 obj_names.append (os.path.join (output_dir,
437 base + self.res_extension))
438 else:
439 obj_names.append (os.path.join (output_dir,
440 base + self.obj_extension))
441 return obj_names
442
443
444 def compile(self, sources,
445 output_dir=None, macros=None, include_dirs=None, debug=0,
446 extra_preargs=None, extra_postargs=None, depends=None):
447
448 if not self.initialized:
449 self.initialize()
450 compile_info = self._setup_compile(output_dir, macros, include_dirs,
451 sources, depends, extra_postargs)
452 macros, objects, extra_postargs, pp_opts, build = compile_info
453
454 compile_opts = extra_preargs or []
455 compile_opts.append ('/c')
456 if debug:
457 compile_opts.extend(self.compile_options_debug)
458 else:
459 compile_opts.extend(self.compile_options)
460
461 for obj in objects:
462 try:
463 src, ext = build[obj]
464 except KeyError:
465 continue
466 if debug:
467 # pass the full pathname to MSVC in debug mode,
468 # this allows the debugger to find the source file
469 # without asking the user to browse for it
470 src = os.path.abspath(src)
471
472 if ext in self._c_extensions:
473 input_opt = "/Tc" + src
474 elif ext in self._cpp_extensions:
475 input_opt = "/Tp" + src
476 elif ext in self._rc_extensions:
477 # compile .RC to .RES file
478 input_opt = src
479 output_opt = "/fo" + obj
480 try:
481 self.spawn([self.rc] + pp_opts +
482 [output_opt] + [input_opt])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000483 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000484 raise CompileError(msg)
485 continue
486 elif ext in self._mc_extensions:
487 # Compile .MC to .RC file to .RES file.
488 # * '-h dir' specifies the directory for the
489 # generated include file
490 # * '-r dir' specifies the target directory of the
491 # generated RC file and the binary message resource
492 # it includes
493 #
494 # For now (since there are no options to change this),
495 # we use the source-directory for the include file and
496 # the build directory for the RC file and message
497 # resources. This works at least for win32all.
498 h_dir = os.path.dirname(src)
499 rc_dir = os.path.dirname(obj)
500 try:
501 # first compile .MC to .RC and .H file
502 self.spawn([self.mc] +
503 ['-h', h_dir, '-r', rc_dir] + [src])
504 base, _ = os.path.splitext (os.path.basename (src))
505 rc_file = os.path.join (rc_dir, base + '.rc')
506 # then compile .RC to .RES file
507 self.spawn([self.rc] +
508 ["/fo" + obj] + [rc_file])
509
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000510 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000511 raise CompileError(msg)
512 continue
513 else:
514 # how to handle this file?
515 raise CompileError("Don't know how to compile %s to %s"
516 % (src, obj))
517
518 output_opt = "/Fo" + obj
519 try:
520 self.spawn([self.cc] + compile_opts + pp_opts +
521 [input_opt, output_opt] +
522 extra_postargs)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000523 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000524 raise CompileError(msg)
525
526 return objects
527
528
529 def create_static_lib(self,
530 objects,
531 output_libname,
532 output_dir=None,
533 debug=0,
534 target_lang=None):
535
536 if not self.initialized:
537 self.initialize()
538 (objects, output_dir) = self._fix_object_args(objects, output_dir)
539 output_filename = self.library_filename(output_libname,
540 output_dir=output_dir)
541
542 if self._need_link(objects, output_filename):
543 lib_args = objects + ['/OUT:' + output_filename]
544 if debug:
545 pass # XXX what goes here?
546 try:
547 self.spawn([self.lib] + lib_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000548 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000549 raise LibError(msg)
550 else:
551 log.debug("skipping %s (up-to-date)", output_filename)
552
553
554 def link(self,
555 target_desc,
556 objects,
557 output_filename,
558 output_dir=None,
559 libraries=None,
560 library_dirs=None,
561 runtime_library_dirs=None,
562 export_symbols=None,
563 debug=0,
564 extra_preargs=None,
565 extra_postargs=None,
566 build_temp=None,
567 target_lang=None):
568
569 if not self.initialized:
570 self.initialize()
571 (objects, output_dir) = self._fix_object_args(objects, output_dir)
572 fixed_args = self._fix_lib_args(libraries, library_dirs,
573 runtime_library_dirs)
574 (libraries, library_dirs, runtime_library_dirs) = fixed_args
575
576 if runtime_library_dirs:
577 self.warn ("I don't know what to do with 'runtime_library_dirs': "
578 + str (runtime_library_dirs))
579
580 lib_opts = gen_lib_options(self,
581 library_dirs, runtime_library_dirs,
582 libraries)
583 if output_dir is not None:
584 output_filename = os.path.join(output_dir, output_filename)
585
586 if self._need_link(objects, output_filename):
587 if target_desc == CCompiler.EXECUTABLE:
588 if debug:
589 ldflags = self.ldflags_shared_debug[1:]
590 else:
591 ldflags = self.ldflags_shared[1:]
592 else:
593 if debug:
594 ldflags = self.ldflags_shared_debug
595 else:
596 ldflags = self.ldflags_shared
597
598 export_opts = []
599 for sym in (export_symbols or []):
600 export_opts.append("/EXPORT:" + sym)
601
602 ld_args = (ldflags + lib_opts + export_opts +
603 objects + ['/OUT:' + output_filename])
604
605 # The MSVC linker generates .lib and .exp files, which cannot be
606 # suppressed by any linker switches. The .lib files may even be
607 # needed! Make sure they are generated in the temporary build
608 # directory. Since they have different names for debug and release
609 # builds, they can go into the same directory.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000610 build_temp = os.path.dirname(objects[0])
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000611 if export_symbols is not None:
612 (dll_name, dll_ext) = os.path.splitext(
613 os.path.basename(output_filename))
614 implib_file = os.path.join(
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000615 build_temp,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000616 self.library_filename(dll_name))
617 ld_args.append ('/IMPLIB:' + implib_file)
618
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000619 # Embedded manifests are recommended - see MSDN article titled
620 # "How to: Embed a Manifest Inside a C/C++ Application"
621 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
622 # Ask the linker to generate the manifest in the temp dir, so
623 # we can embed it later.
624 temp_manifest = os.path.join(
625 build_temp,
626 os.path.basename(output_filename) + ".manifest")
627 ld_args.append('/MANIFESTFILE:' + temp_manifest)
628
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000629 if extra_preargs:
630 ld_args[:0] = extra_preargs
631 if extra_postargs:
632 ld_args.extend(extra_postargs)
633
634 self.mkpath(os.path.dirname(output_filename))
635 try:
636 self.spawn([self.linker] + ld_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000637 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000638 raise LinkError(msg)
639
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000640 # embed the manifest
641 # XXX - this is somewhat fragile - if mt.exe fails, distutils
642 # will still consider the DLL up-to-date, but it will not have a
643 # manifest. Maybe we should link to a temp file? OTOH, that
644 # implies a build environment error that shouldn't go undetected.
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000645 if target_desc == CCompiler.EXECUTABLE:
646 mfid = 1
647 else:
648 mfid = 2
Martin v. Löwis1679ea82009-12-03 20:57:49 +0000649 try:
650 # Remove references to the Visual C runtime, so they will
651 # fall through to the Visual C dependency of Python.exe.
652 # This way, when installed for a restricted user (e.g.
653 # runtimes are not in WinSxS folder, but in Python's own
654 # folder), the runtimes do not need to be in every folder
655 # with .pyd's.
656 manifest_f = open(temp_manifest, "rb")
657 manifest_buf = manifest_f.read()
658 manifest_f.close()
659 pattern = re.compile(
660 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
661 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
662 re.DOTALL)
663 manifest_buf = re.sub(pattern, "", manifest_buf)
664 pattern = "<dependentAssembly>\s*</dependentAssembly>"
665 manifest_buf = re.sub(pattern, "", manifest_buf)
666 manifest_f = open(temp_manifest, "wb")
667 manifest_f.write(manifest_buf)
668 manifest_f.close()
669 except IOError:
670 pass
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000671 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
672 try:
673 self.spawn(['mt.exe', '-nologo', '-manifest',
674 temp_manifest, out_arg])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000675 except DistutilsExecError as msg:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000676 raise LinkError(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000677 else:
678 log.debug("skipping %s (up-to-date)", output_filename)
679
680
681 # -- Miscellaneous methods -----------------------------------------
682 # These are all used by the 'gen_lib_options() function, in
683 # ccompiler.py.
684
685 def library_dir_option(self, dir):
686 return "/LIBPATH:" + dir
687
688 def runtime_library_dir_option(self, dir):
689 raise DistutilsPlatformError(
690 "don't know how to set runtime library search path for MSVC++")
691
692 def library_option(self, lib):
693 return self.library_filename(lib)
694
695
696 def find_library_file(self, dirs, lib, debug=0):
697 # Prefer a debugging library if found (and requested), but deal
698 # with it if we don't have one.
699 if debug:
700 try_names = [lib + "_d", lib]
701 else:
702 try_names = [lib]
703 for dir in dirs:
704 for name in try_names:
705 libfile = os.path.join(dir, self.library_filename (name))
706 if os.path.exists(libfile):
707 return libfile
708 else:
709 # Oops, didn't find it in *any* of 'dirs'
710 return None
711
712 # Helper methods for using the MSVC registry settings
713
714 def find_exe(self, exe):
715 """Return path to an MSVC executable program.
716
717 Tries to find the program in several places: first, one of the
718 MSVC program search paths from the registry; next, the directories
719 in the PATH environment variable. If any of those work, return an
720 absolute path that is known to exist. If none of them work, just
721 return the original program name, 'exe'.
722 """
723 for p in self.__paths:
724 fn = os.path.join(os.path.abspath(p), exe)
725 if os.path.isfile(fn):
726 return fn
727
728 # didn't find it; try existing path
729 for p in os.environ['Path'].split(';'):
730 fn = os.path.join(os.path.abspath(p),exe)
731 if os.path.isfile(fn):
732 return fn
733
734 return exe