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