Issue #7575: An overflow test for math.expm1 was failing on OS X 10.4/Intel,
[python.git] / Lib / distutils / msvc9compiler.py
blob41d67faf59c212759b0b8caeb4e581ffbe97ea1a
1 """distutils.msvc9compiler
3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
4 for the Microsoft Visual Studio 2008.
6 The module is compatible with VS 2005 and VS 2008. You can find legacy support
7 for older versions of VS in distutils.msvccompiler.
8 """
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
15 __revision__ = "$Id$"
17 import os
18 import subprocess
19 import sys
20 import re
22 from distutils.errors import (DistutilsExecError, DistutilsPlatformError,
23 CompileError, LibError, LinkError)
24 from distutils.ccompiler import CCompiler, gen_lib_options
25 from distutils import log
26 from distutils.util import get_platform
28 import _winreg
30 RegOpenKeyEx = _winreg.OpenKeyEx
31 RegEnumKey = _winreg.EnumKey
32 RegEnumValue = _winreg.EnumValue
33 RegError = _winreg.error
35 HKEYS = (_winreg.HKEY_USERS,
36 _winreg.HKEY_CURRENT_USER,
37 _winreg.HKEY_LOCAL_MACHINE,
38 _winreg.HKEY_CLASSES_ROOT)
40 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
41 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
42 NET_BASE = r"Software\Microsoft\.NETFramework"
44 # 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.)
47 PLAT_TO_VCVARS = {
48 'win32' : 'x86',
49 'win-amd64' : 'amd64',
50 'win-ia64' : 'ia64',
53 class Reg:
54 """Helper class to read values from the registry
55 """
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 get_value = classmethod(get_value)
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 read_keys = classmethod(read_keys)
83 def read_values(cls, base, key):
84 """Return dict of registry keys and values.
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 read_values = classmethod(read_values)
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 convert_mbcs = staticmethod(convert_mbcs)
115 class MacroExpander:
117 def __init__(self, version):
118 self.macros = {}
119 self.vsbase = VS_BASE % version
120 self.load_macros(version)
122 def set_macro(self, macro, path, key):
123 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
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")
135 except KeyError:
136 raise DistutilsPlatformError(
137 """Python was built with Visual Studio 2008;
138 extensions must be built with a compiler than can generate compatible binaries.
139 Visual Studio 2008 was not found on this system. If you have Cygwin installed,
140 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
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"]
156 def sub(self, s):
157 for k, v in self.macros.items():
158 s = s.replace(k, v)
159 return s
161 def get_build_version():
162 """Return the version of MSVC that was used to build Python.
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.
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
183 def normalize_and_reduce_paths(paths):
184 """Return a list of normalized paths with duplicates removed.
186 The current order of paths is maintained.
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
197 def removeDuplicates(variable):
198 """Remove duplicate values of an environment variable.
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
208 def find_vcvarsall(version):
209 """Find the vcvarsall.bat file
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.
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
222 if not productdir or not os.path.isdir(productdir):
223 toolskey = "VS%0.f0COMNTOOLS" % version
224 toolsdir = os.environ.get(toolskey, None)
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
243 def query_vcvarsall(version, arch="x86"):
244 """Launch vcvarsall.bat and read the settings from its environment
246 vcvarsall = find_vcvarsall(version)
247 interesting = set(("include", "lib", "libpath", "path"))
248 result = {}
250 if vcvarsall is None:
251 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
252 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
253 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
254 stdout=subprocess.PIPE,
255 stderr=subprocess.PIPE)
257 stdout, stderr = popen.communicate()
258 if popen.wait() != 0:
259 raise DistutilsPlatformError(stderr.decode("mbcs"))
261 stdout = stdout.decode("mbcs")
262 for line in stdout.split("\n"):
263 line = Reg.convert_mbcs(line)
264 if '=' not in line:
265 continue
266 line = line.strip()
267 key, value = line.split('=', 1)
268 key = key.lower()
269 if key in interesting:
270 if value.endswith(os.pathsep):
271 value = value[:-1]
272 result[key] = removeDuplicates(value)
274 if len(result) != len(interesting):
275 raise ValueError(str(list(result.keys())))
277 return result
279 # More globals
280 VERSION = get_build_version()
281 if VERSION < 8.0:
282 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
283 # MACROS = MacroExpander(VERSION)
285 class MSVCCompiler(CCompiler) :
286 """Concrete class that implements an interface to Microsoft Visual C++,
287 as defined by the CCompiler abstract class."""
289 compiler_type = 'msvc'
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 = {}
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']
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'
315 def __init__(self, verbose=0, dry_run=0, force=0):
316 CCompiler.__init__ (self, verbose, dry_run, force)
317 self.__version = VERSION
318 self.__root = r"Software\Microsoft\VisualStudio"
319 # self.__macros = MACROS
320 self.__paths = []
321 # target platform (.plat_name is consistent with 'bdist')
322 self.plat_name = None
323 self.__arch = None # deprecated name
324 self.initialized = False
326 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,))
337 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:
346 # 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]
359 vc_env = query_vcvarsall(VERSION, plat_spec)
361 # take care to only use strings in the environment.
362 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
363 os.environ['lib'] = vc_env['lib'].encode('mbcs')
364 os.environ['include'] = vc_env['include'].encode('mbcs')
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)
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')
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)
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']
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'
407 self.ldflags_static = [ '/nologo']
409 self.initialized = True
411 # -- Worker methods ------------------------------------------------
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
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):
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
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)
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)
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])
483 except DistutilsExecError, msg:
484 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
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])
510 except DistutilsExecError, msg:
511 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))
518 output_opt = "/Fo" + obj
519 try:
520 self.spawn([self.cc] + compile_opts + pp_opts +
521 [input_opt, output_opt] +
522 extra_postargs)
523 except DistutilsExecError, msg:
524 raise CompileError(msg)
526 return objects
529 def create_static_lib(self,
530 objects,
531 output_libname,
532 output_dir=None,
533 debug=0,
534 target_lang=None):
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)
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)
548 except DistutilsExecError, msg:
549 raise LibError(msg)
550 else:
551 log.debug("skipping %s (up-to-date)", output_filename)
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):
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
576 if runtime_library_dirs:
577 self.warn ("I don't know what to do with 'runtime_library_dirs': "
578 + str (runtime_library_dirs))
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)
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
598 export_opts = []
599 for sym in (export_symbols or []):
600 export_opts.append("/EXPORT:" + sym)
602 ld_args = (ldflags + lib_opts + export_opts +
603 objects + ['/OUT:' + output_filename])
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.
610 build_temp = os.path.dirname(objects[0])
611 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(
615 build_temp,
616 self.library_filename(dll_name))
617 ld_args.append ('/IMPLIB:' + implib_file)
619 # 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)
629 if extra_preargs:
630 ld_args[:0] = extra_preargs
631 if extra_postargs:
632 ld_args.extend(extra_postargs)
634 self.mkpath(os.path.dirname(output_filename))
635 try:
636 self.spawn([self.linker] + ld_args)
637 except DistutilsExecError, msg:
638 raise LinkError(msg)
640 # 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.
645 if target_desc == CCompiler.EXECUTABLE:
646 mfid = 1
647 else:
648 mfid = 2
649 self._remove_visual_c_ref(temp_manifest)
650 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
651 try:
652 self.spawn(['mt.exe', '-nologo', '-manifest',
653 temp_manifest, out_arg])
654 except DistutilsExecError, msg:
655 raise LinkError(msg)
656 else:
657 log.debug("skipping %s (up-to-date)", output_filename)
659 def _remove_visual_c_ref(self, manifest_file):
660 try:
661 # Remove references to the Visual C runtime, so they will
662 # fall through to the Visual C dependency of Python.exe.
663 # This way, when installed for a restricted user (e.g.
664 # runtimes are not in WinSxS folder, but in Python's own
665 # folder), the runtimes do not need to be in every folder
666 # with .pyd's.
667 manifest_f = open(manifest_file)
668 try:
669 manifest_buf = manifest_f.read()
670 finally:
671 manifest_f.close()
672 pattern = re.compile(
673 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
674 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
675 re.DOTALL)
676 manifest_buf = re.sub(pattern, "", manifest_buf)
677 pattern = "<dependentAssembly>\s*</dependentAssembly>"
678 manifest_buf = re.sub(pattern, "", manifest_buf)
679 manifest_f = open(manifest_file, 'w')
680 try:
681 manifest_f.write(manifest_buf)
682 finally:
683 manifest_f.close()
684 except IOError:
685 pass
687 # -- Miscellaneous methods -----------------------------------------
688 # These are all used by the 'gen_lib_options() function, in
689 # ccompiler.py.
691 def library_dir_option(self, dir):
692 return "/LIBPATH:" + dir
694 def runtime_library_dir_option(self, dir):
695 raise DistutilsPlatformError(
696 "don't know how to set runtime library search path for MSVC++")
698 def library_option(self, lib):
699 return self.library_filename(lib)
702 def find_library_file(self, dirs, lib, debug=0):
703 # Prefer a debugging library if found (and requested), but deal
704 # with it if we don't have one.
705 if debug:
706 try_names = [lib + "_d", lib]
707 else:
708 try_names = [lib]
709 for dir in dirs:
710 for name in try_names:
711 libfile = os.path.join(dir, self.library_filename (name))
712 if os.path.exists(libfile):
713 return libfile
714 else:
715 # Oops, didn't find it in *any* of 'dirs'
716 return None
718 # Helper methods for using the MSVC registry settings
720 def find_exe(self, exe):
721 """Return path to an MSVC executable program.
723 Tries to find the program in several places: first, one of the
724 MSVC program search paths from the registry; next, the directories
725 in the PATH environment variable. If any of those work, return an
726 absolute path that is known to exist. If none of them work, just
727 return the original program name, 'exe'.
729 for p in self.__paths:
730 fn = os.path.join(os.path.abspath(p), exe)
731 if os.path.isfile(fn):
732 return fn
734 # didn't find it; try existing path
735 for p in os.environ['Path'].split(';'):
736 fn = os.path.join(os.path.abspath(p),exe)
737 if os.path.isfile(fn):
738 return fn
740 return exe