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