blob: 4f72e78096b209f77701c53313540ad2dfd607da [file] [log] [blame]
Christian Heimes3305c522007-12-03 13:47:29 +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
Mark Hammond495cf992008-04-07 01:53:39 +000025from distutils.util import get_platform
Christian Heimes3305c522007-12-03 13:47:29 +000026
27import _winreg
28
29RegOpenKeyEx = _winreg.OpenKeyEx
30RegEnumKey = _winreg.EnumKey
31RegEnumValue = _winreg.EnumValue
32RegError = _winreg.error
33
34HKEYS = (_winreg.HKEY_USERS,
35 _winreg.HKEY_CURRENT_USER,
36 _winreg.HKEY_LOCAL_MACHINE,
37 _winreg.HKEY_CLASSES_ROOT)
38
39VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
40WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
41NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimes3305c522007-12-03 13:47:29 +000042
Mark Hammond495cf992008-04-07 01:53:39 +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 Heimes3305c522007-12-03 13:47:29 +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 Heimes3305c522007-12-03 13:47:29 +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
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000196def removeDuplicates(variable):
197 """Remove duplicate values of an environment variable.
198 """
199 oldList = variable.split(os.pathsep)
200 newList = []
201 for i in oldList:
202 if i not in newList:
203 newList.append(i)
204 newVariable = os.pathsep.join(newList)
205 return newVariable
206
Christian Heimes3305c522007-12-03 13:47:29 +0000207def find_vcvarsall(version):
208 """Find the vcvarsall.bat file
209
210 At first it tries to find the productdir of VS 2008 in the registry. If
211 that fails it falls back to the VS90COMNTOOLS env var.
212 """
213 vsbase = VS_BASE % version
214 try:
215 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
216 "productdir")
217 except KeyError:
218 log.debug("Unable to find productdir in registry")
219 productdir = None
220
221 if not productdir or not os.path.isdir(productdir):
222 toolskey = "VS%0.f0COMNTOOLS" % version
223 toolsdir = os.environ.get(toolskey, None)
224
225 if toolsdir and os.path.isdir(toolsdir):
226 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
227 productdir = os.path.abspath(productdir)
228 if not os.path.isdir(productdir):
229 log.debug("%s is not a valid directory" % productdir)
230 return None
231 else:
232 log.debug("Env var %s is not set or invalid" % toolskey)
233 if not productdir:
234 log.debug("No productdir found")
235 return None
236 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
237 if os.path.isfile(vcvarsall):
238 return vcvarsall
239 log.debug("Unable to find vcvarsall.bat")
240 return None
241
242def query_vcvarsall(version, arch="x86"):
243 """Launch vcvarsall.bat and read the settings from its environment
244 """
245 vcvarsall = find_vcvarsall(version)
246 interesting = set(("include", "lib", "libpath", "path"))
247 result = {}
248
249 if vcvarsall is None:
250 raise IOError("Unable to find vcvarsall.bat")
Mark Hammond495cf992008-04-07 01:53:39 +0000251 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimes3305c522007-12-03 13:47:29 +0000252 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
253 stdout=subprocess.PIPE,
254 stderr=subprocess.PIPE)
Christian Heimes3305c522007-12-03 13:47:29 +0000255
Christian Heimescbdb7052007-12-05 20:10:38 +0000256 stdout, stderr = popen.communicate()
257 if popen.wait() != 0:
258 raise IOError(stderr.decode("mbcs"))
259
260 stdout = stdout.decode("mbcs")
261 for line in stdout.split("\n"):
Christian Heimes3305c522007-12-03 13:47:29 +0000262 line = Reg.convert_mbcs(line)
263 if '=' not in line:
264 continue
265 line = line.strip()
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000266 key, value = line.split('=', 1)
Christian Heimes3305c522007-12-03 13:47:29 +0000267 key = key.lower()
268 if key in interesting:
269 if value.endswith(os.pathsep):
270 value = value[:-1]
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000271 result[key] = removeDuplicates(value)
Christian Heimes3305c522007-12-03 13:47:29 +0000272
273 if len(result) != len(interesting):
274 raise ValueError(str(list(result.keys())))
275
276 return result
277
278# More globals
279VERSION = get_build_version()
280if VERSION < 8.0:
281 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000282# MACROS = MacroExpander(VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000283
284class MSVCCompiler(CCompiler) :
285 """Concrete class that implements an interface to Microsoft Visual C++,
286 as defined by the CCompiler abstract class."""
287
288 compiler_type = 'msvc'
289
290 # Just set this so CCompiler's constructor doesn't barf. We currently
291 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
292 # as it really isn't necessary for this sort of single-compiler class.
293 # Would be nice to have a consistent interface with UnixCCompiler,
294 # though, so it's worth thinking about.
295 executables = {}
296
297 # Private class data (need to distinguish C from C++ source for compiler)
298 _c_extensions = ['.c']
299 _cpp_extensions = ['.cc', '.cpp', '.cxx']
300 _rc_extensions = ['.rc']
301 _mc_extensions = ['.mc']
302
303 # Needed for the filename generation methods provided by the
304 # base class, CCompiler.
305 src_extensions = (_c_extensions + _cpp_extensions +
306 _rc_extensions + _mc_extensions)
307 res_extension = '.res'
308 obj_extension = '.obj'
309 static_lib_extension = '.lib'
310 shared_lib_extension = '.dll'
311 static_lib_format = shared_lib_format = '%s%s'
312 exe_extension = '.exe'
313
314 def __init__(self, verbose=0, dry_run=0, force=0):
315 CCompiler.__init__ (self, verbose, dry_run, force)
316 self.__version = VERSION
Christian Heimes3305c522007-12-03 13:47:29 +0000317 self.__root = r"Software\Microsoft\VisualStudio"
318 # self.__macros = MACROS
Christian Heimesaa674712008-11-28 11:02:32 +0000319 self.__paths = []
Mark Hammond495cf992008-04-07 01:53:39 +0000320 # target platform (.plat_name is consistent with 'bdist')
321 self.plat_name = None
322 self.__arch = None # deprecated name
Christian Heimes3305c522007-12-03 13:47:29 +0000323 self.initialized = False
324
Mark Hammond495cf992008-04-07 01:53:39 +0000325 def initialize(self, plat_name=None):
326 # multi-init means we would need to check platform same each time...
327 assert not self.initialized, "don't init multiple times"
328 if plat_name is None:
329 plat_name = get_platform()
330 # sanity check for platforms to prevent obscure errors later.
331 ok_plats = 'win32', 'win-amd64', 'win-ia64'
332 if plat_name not in ok_plats:
333 raise DistutilsPlatformError("--plat-name must be one of %s" %
334 (ok_plats,))
335
Christian Heimes3305c522007-12-03 13:47:29 +0000336 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
337 # Assume that the SDK set up everything alright; don't try to be
338 # smarter
339 self.cc = "cl.exe"
340 self.linker = "link.exe"
341 self.lib = "lib.exe"
342 self.rc = "rc.exe"
343 self.mc = "mc.exe"
344 else:
Mark Hammond495cf992008-04-07 01:53:39 +0000345 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
346 # to cross compile, you use 'x86_amd64'.
347 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
348 # compile use 'x86' (ie, it runs the x86 compiler directly)
349 # No idea how itanium handles this, if at all.
350 if plat_name == get_platform() or plat_name == 'win32':
351 # native build or cross-compile to win32
352 plat_spec = PLAT_TO_VCVARS[plat_name]
353 else:
354 # cross compile from win32 -> some 64bit
355 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
356 PLAT_TO_VCVARS[plat_name]
357
358 vc_env = query_vcvarsall(VERSION, plat_spec)
359
Mark Hammond900155f2008-09-18 03:51:46 +0000360 # take care to only use strings in the environment.
361 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
362 os.environ['lib'] = vc_env['lib'].encode('mbcs')
363 os.environ['include'] = vc_env['include'].encode('mbcs')
Christian Heimes3305c522007-12-03 13:47:29 +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])
482 except DistutilsExecError as msg:
483 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
509 except DistutilsExecError as msg:
510 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)
522 except DistutilsExecError as msg:
523 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)
547 except DistutilsExecError as msg:
548 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.
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000609 build_temp = os.path.dirname(objects[0])
Christian Heimes3305c522007-12-03 13:47:29 +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(
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000614 build_temp,
Christian Heimes3305c522007-12-03 13:47:29 +0000615 self.library_filename(dll_name))
616 ld_args.append ('/IMPLIB:' + implib_file)
617
Mark Hammond7c5c8e62008-05-02 12:48:15 +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 Heimes3305c522007-12-03 13:47:29 +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)
636 except DistutilsExecError as msg:
637 raise LinkError(msg)
638
Mark Hammond7c5c8e62008-05-02 12:48:15 +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.
644 mfid = 1 if target_desc == CCompiler.EXECUTABLE else 2
645 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
646 try:
647 self.spawn(['mt.exe', '-nologo', '-manifest',
648 temp_manifest, out_arg])
649 except DistutilsExecError as msg:
650 raise LinkError(msg)
Christian Heimes3305c522007-12-03 13:47:29 +0000651 else:
652 log.debug("skipping %s (up-to-date)", output_filename)
653
654
655 # -- Miscellaneous methods -----------------------------------------
656 # These are all used by the 'gen_lib_options() function, in
657 # ccompiler.py.
658
659 def library_dir_option(self, dir):
660 return "/LIBPATH:" + dir
661
662 def runtime_library_dir_option(self, dir):
663 raise DistutilsPlatformError(
664 "don't know how to set runtime library search path for MSVC++")
665
666 def library_option(self, lib):
667 return self.library_filename(lib)
668
669
670 def find_library_file(self, dirs, lib, debug=0):
671 # Prefer a debugging library if found (and requested), but deal
672 # with it if we don't have one.
673 if debug:
674 try_names = [lib + "_d", lib]
675 else:
676 try_names = [lib]
677 for dir in dirs:
678 for name in try_names:
679 libfile = os.path.join(dir, self.library_filename (name))
680 if os.path.exists(libfile):
681 return libfile
682 else:
683 # Oops, didn't find it in *any* of 'dirs'
684 return None
685
686 # Helper methods for using the MSVC registry settings
687
688 def find_exe(self, exe):
689 """Return path to an MSVC executable program.
690
691 Tries to find the program in several places: first, one of the
692 MSVC program search paths from the registry; next, the directories
693 in the PATH environment variable. If any of those work, return an
694 absolute path that is known to exist. If none of them work, just
695 return the original program name, 'exe'.
696 """
697 for p in self.__paths:
698 fn = os.path.join(os.path.abspath(p), exe)
699 if os.path.isfile(fn):
700 return fn
701
702 # didn't find it; try existing path
703 for p in os.environ['Path'].split(';'):
704 fn = os.path.join(os.path.abspath(p),exe)
705 if os.path.isfile(fn):
706 return fn
707
708 return exe