blob: af8099a4078192e1b2c940b3fde563f76e611f64 [file] [log] [blame]
Steve Dowerfd3664b2015-05-23 09:02:50 -07001"""distutils._msvccompiler
2
3Contains MSVCCompiler, an implementation of the abstract CCompiler class
4for Microsoft Visual Studio 2015.
5
6The module is compatible with VS 2015 and later. You can find legacy support
7for older versions in distutils.msvc9compiler and 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 VS 2005 and VS 2008 by Christian Heimes
14# ported to VS 2015 by Steve Dower
15
16import os
17import subprocess
Steve Dower05f01d82017-09-07 11:49:23 -070018import winreg
Steve Dowerfd3664b2015-05-23 09:02:50 -070019
20from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
21 CompileError, LibError, LinkError
22from distutils.ccompiler import CCompiler, gen_lib_options
23from distutils import log
24from distutils.util import get_platform
25
Steve Dowerfd3664b2015-05-23 09:02:50 -070026from itertools import count
27
Steve Dower05f01d82017-09-07 11:49:23 -070028def _find_vc2015():
Steve Dowerf0ccf022015-10-05 10:35:00 -070029 try:
30 key = winreg.OpenKeyEx(
31 winreg.HKEY_LOCAL_MACHINE,
32 r"Software\Microsoft\VisualStudio\SxS\VC7",
33 access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
34 )
35 except OSError:
36 log.debug("Visual C++ is not registered")
37 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070038
Steve Dower05f01d82017-09-07 11:49:23 -070039 best_version = 0
40 best_dir = None
Steve Dowerf0ccf022015-10-05 10:35:00 -070041 with key:
Steve Dowerfd3664b2015-05-23 09:02:50 -070042 for i in count():
43 try:
44 v, vc_dir, vt = winreg.EnumValue(key, i)
45 except OSError:
46 break
47 if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
48 try:
49 version = int(float(v))
50 except (ValueError, TypeError):
51 continue
52 if version >= 14 and version > best_version:
53 best_version, best_dir = version, vc_dir
Steve Dower05f01d82017-09-07 11:49:23 -070054 return best_version, best_dir
Steve Dowerfd3664b2015-05-23 09:02:50 -070055
Steve Dower05f01d82017-09-07 11:49:23 -070056def _find_vc2017():
Steve Dower53125a52018-10-27 16:48:33 -040057 """Returns "15, path" based on the result of invoking vswhere.exe
58 If no install is found, returns "None, None"
Steve Dowerfd3664b2015-05-23 09:02:50 -070059
Steve Dower53125a52018-10-27 16:48:33 -040060 The version is returned to avoid unnecessarily changing the function
61 result. It may be ignored when the path is not None.
Steve Dower05f01d82017-09-07 11:49:23 -070062
Steve Dower53125a52018-10-27 16:48:33 -040063 If vswhere.exe is not available, by definition, VS 2017 is not
64 installed.
65 """
Steve Dower53125a52018-10-27 16:48:33 -040066 root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
67 if not root:
68 return None, None
69
Steve Dower05f01d82017-09-07 11:49:23 -070070 try:
Steve Dower53125a52018-10-27 16:48:33 -040071 path = subprocess.check_output([
72 os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
73 "-latest",
74 "-prerelease",
75 "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
76 "-property", "installationPath",
Marc Schlaichb2dc4a32019-01-20 19:47:42 +010077 "-products", "*",
Steve Dower53125a52018-10-27 16:48:33 -040078 ], encoding="mbcs", errors="strict").strip()
79 except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
80 return None, None
81
82 path = os.path.join(path, "VC", "Auxiliary", "Build")
83 if os.path.isdir(path):
84 return 15, path
85
86 return None, None
Steve Dower05f01d82017-09-07 11:49:23 -070087
Paul Monson62dfd7d2019-04-25 11:36:45 -070088PLAT_SPEC_TO_RUNTIME = {
89 'x86' : 'x86',
90 'x86_amd64' : 'x64',
91 'x86_arm' : 'arm',
Paul Monsondaf62622019-06-12 10:16:49 -070092 'x86_arm64' : 'arm64'
Paul Monson62dfd7d2019-04-25 11:36:45 -070093}
94
Steve Dower05f01d82017-09-07 11:49:23 -070095def _find_vcvarsall(plat_spec):
Steve Dowerce3a4982020-03-03 00:04:11 +000096 # bpo-38597: Removed vcruntime return value
Steve Dower53125a52018-10-27 16:48:33 -040097 _, best_dir = _find_vc2017()
Steve Dower05f01d82017-09-07 11:49:23 -070098
Steve Dower53125a52018-10-27 16:48:33 -040099 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700100 best_version, best_dir = _find_vc2015()
Steve Dower05f01d82017-09-07 11:49:23 -0700101
Steve Dower53125a52018-10-27 16:48:33 -0400102 if not best_dir:
Steve Dower05f01d82017-09-07 11:49:23 -0700103 log.debug("No suitable Visual C++ version found")
104 return None, None
105
106 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
107 if not os.path.isfile(vcvarsall):
108 log.debug("%s cannot be found", vcvarsall)
109 return None, None
110
Steve Dowerce3a4982020-03-03 00:04:11 +0000111 return vcvarsall, None
Steve Dowerfd3664b2015-05-23 09:02:50 -0700112
113def _get_vc_env(plat_spec):
114 if os.getenv("DISTUTILS_USE_SDK"):
115 return {
116 key.lower(): value
117 for key, value in os.environ.items()
118 }
119
Steve Dowerce3a4982020-03-03 00:04:11 +0000120 vcvarsall, _ = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700121 if not vcvarsall:
122 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
123
124 try:
125 out = subprocess.check_output(
Steve Dower08bb8a42016-06-17 09:32:38 -0700126 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
Steve Dowerfd3664b2015-05-23 09:02:50 -0700127 stderr=subprocess.STDOUT,
Steve Dower08bb8a42016-06-17 09:32:38 -0700128 ).decode('utf-16le', errors='replace')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700129 except subprocess.CalledProcessError as exc:
130 log.error(exc.output)
131 raise DistutilsPlatformError("Error executing {}"
132 .format(exc.cmd))
133
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700134 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700135 key.lower(): value
136 for key, _, value in
137 (line.partition('=') for line in out.splitlines())
138 if key and value
139 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700140
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700141 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700142
143def _find_exe(exe, paths=None):
144 """Return path to an MSVC executable program.
145
146 Tries to find the program in several places: first, one of the
147 MSVC program search paths from the registry; next, the directories
148 in the PATH environment variable. If any of those work, return an
149 absolute path that is known to exist. If none of them work, just
150 return the original program name, 'exe'.
151 """
152 if not paths:
153 paths = os.getenv('path').split(os.pathsep)
154 for p in paths:
155 fn = os.path.join(os.path.abspath(p), exe)
156 if os.path.isfile(fn):
157 return fn
158 return exe
159
160# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800161# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
162# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700163PLAT_TO_VCVARS = {
164 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800165 'win-amd64' : 'x86_amd64',
Paul Monson62dfd7d2019-04-25 11:36:45 -0700166 'win-arm32' : 'x86_arm',
Paul Monsondaf62622019-06-12 10:16:49 -0700167 'win-arm64' : 'x86_arm64'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700168}
169
170class MSVCCompiler(CCompiler) :
171 """Concrete class that implements an interface to Microsoft Visual C++,
172 as defined by the CCompiler abstract class."""
173
174 compiler_type = 'msvc'
175
176 # Just set this so CCompiler's constructor doesn't barf. We currently
177 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
178 # as it really isn't necessary for this sort of single-compiler class.
179 # Would be nice to have a consistent interface with UnixCCompiler,
180 # though, so it's worth thinking about.
181 executables = {}
182
183 # Private class data (need to distinguish C from C++ source for compiler)
184 _c_extensions = ['.c']
185 _cpp_extensions = ['.cc', '.cpp', '.cxx']
186 _rc_extensions = ['.rc']
187 _mc_extensions = ['.mc']
188
189 # Needed for the filename generation methods provided by the
190 # base class, CCompiler.
191 src_extensions = (_c_extensions + _cpp_extensions +
192 _rc_extensions + _mc_extensions)
193 res_extension = '.res'
194 obj_extension = '.obj'
195 static_lib_extension = '.lib'
196 shared_lib_extension = '.dll'
197 static_lib_format = shared_lib_format = '%s%s'
198 exe_extension = '.exe'
199
200
201 def __init__(self, verbose=0, dry_run=0, force=0):
202 CCompiler.__init__ (self, verbose, dry_run, force)
203 # target platform (.plat_name is consistent with 'bdist')
204 self.plat_name = None
205 self.initialized = False
206
207 def initialize(self, plat_name=None):
208 # multi-init means we would need to check platform same each time...
209 assert not self.initialized, "don't init multiple times"
210 if plat_name is None:
211 plat_name = get_platform()
212 # sanity check for platforms to prevent obscure errors later.
213 if plat_name not in PLAT_TO_VCVARS:
214 raise DistutilsPlatformError("--plat-name must be one of {}"
215 .format(tuple(PLAT_TO_VCVARS)))
216
Steve Dower1d329412016-01-16 12:39:10 -0800217 # Get the vcvarsall.bat spec for the requested platform.
218 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700219
220 vc_env = _get_vc_env(plat_spec)
221 if not vc_env:
222 raise DistutilsPlatformError("Unable to find a compatible "
223 "Visual Studio installation.")
224
Steve Dower31202ea2015-08-05 11:39:19 -0700225 self._paths = vc_env.get('path', '')
226 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700227 self.cc = _find_exe("cl.exe", paths)
228 self.linker = _find_exe("link.exe", paths)
229 self.lib = _find_exe("lib.exe", paths)
230 self.rc = _find_exe("rc.exe", paths) # resource compiler
231 self.mc = _find_exe("mc.exe", paths) # message compiler
232 self.mt = _find_exe("mt.exe", paths) # message compiler
233
234 for dir in vc_env.get('include', '').split(os.pathsep):
235 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700236 self.add_include_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700237
238 for dir in vc_env.get('lib', '').split(os.pathsep):
239 if dir:
Steve Dower5473f062018-07-26 04:23:10 -0700240 self.add_library_dir(dir.rstrip(os.sep))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700241
242 self.preprocess_options = None
Steve Dowerce3a4982020-03-03 00:04:11 +0000243 # bpo-38597: Always compile with dynamic linking
244 # Future releases of Python 3.x will include all past
245 # versions of vcruntime*.dll for compatibility.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700246 self.compile_options = [
Steve Dowerce3a4982020-03-03 00:04:11 +0000247 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG', '/MD'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700248 ]
Larry Hastings52e40cd2015-09-09 06:54:57 -0700249
Steve Dowerfd3664b2015-05-23 09:02:50 -0700250 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700251 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700252 ]
253
Steve Dower31202ea2015-08-05 11:39:19 -0700254 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700255 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700256 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700257
Steve Dower31202ea2015-08-05 11:39:19 -0700258 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700259 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700260 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700261
262 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
263 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
264 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
265 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
266 self.ldflags_static = [*ldflags]
267 self.ldflags_static_debug = [*ldflags_debug]
268
269 self._ldflags = {
270 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
271 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
272 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
273 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
274 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
275 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
276 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
277 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
278 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
279 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700280
281 self.initialized = True
282
283 # -- Worker methods ------------------------------------------------
284
285 def object_filenames(self,
286 source_filenames,
287 strip_dir=0,
288 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700289 ext_map = {
290 **{ext: self.obj_extension for ext in self.src_extensions},
291 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
292 }
293
294 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700295
296 def make_out_path(p):
297 base, ext = os.path.splitext(p)
298 if strip_dir:
299 base = os.path.basename(base)
300 else:
301 _, base = os.path.splitdrive(base)
302 if base.startswith((os.path.sep, os.path.altsep)):
303 base = base[1:]
304 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700305 # XXX: This may produce absurdly long paths. We should check
306 # the length of the result and trim base until we fit within
307 # 260 characters.
308 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700309 except LookupError:
310 # Better to raise an exception instead of silently continuing
311 # and later complain about sources and targets having
312 # different lengths
313 raise CompileError("Don't know how to compile {}".format(p))
314
Steve Dower31202ea2015-08-05 11:39:19 -0700315 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700316
317
318 def compile(self, sources,
319 output_dir=None, macros=None, include_dirs=None, debug=0,
320 extra_preargs=None, extra_postargs=None, depends=None):
321
322 if not self.initialized:
323 self.initialize()
324 compile_info = self._setup_compile(output_dir, macros, include_dirs,
325 sources, depends, extra_postargs)
326 macros, objects, extra_postargs, pp_opts, build = compile_info
327
328 compile_opts = extra_preargs or []
329 compile_opts.append('/c')
330 if debug:
331 compile_opts.extend(self.compile_options_debug)
332 else:
333 compile_opts.extend(self.compile_options)
334
335
336 add_cpp_opts = False
337
338 for obj in objects:
339 try:
340 src, ext = build[obj]
341 except KeyError:
342 continue
343 if debug:
344 # pass the full pathname to MSVC in debug mode,
345 # this allows the debugger to find the source file
346 # without asking the user to browse for it
347 src = os.path.abspath(src)
348
349 if ext in self._c_extensions:
350 input_opt = "/Tc" + src
351 elif ext in self._cpp_extensions:
352 input_opt = "/Tp" + src
353 add_cpp_opts = True
354 elif ext in self._rc_extensions:
355 # compile .RC to .RES file
356 input_opt = src
357 output_opt = "/fo" + obj
358 try:
359 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
360 except DistutilsExecError as msg:
361 raise CompileError(msg)
362 continue
363 elif ext in self._mc_extensions:
364 # Compile .MC to .RC file to .RES file.
365 # * '-h dir' specifies the directory for the
366 # generated include file
367 # * '-r dir' specifies the target directory of the
368 # generated RC file and the binary message resource
369 # it includes
370 #
371 # For now (since there are no options to change this),
372 # we use the source-directory for the include file and
373 # the build directory for the RC file and message
374 # resources. This works at least for win32all.
375 h_dir = os.path.dirname(src)
376 rc_dir = os.path.dirname(obj)
377 try:
378 # first compile .MC to .RC and .H file
379 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
380 base, _ = os.path.splitext(os.path.basename (src))
381 rc_file = os.path.join(rc_dir, base + '.rc')
382 # then compile .RC to .RES file
383 self.spawn([self.rc, "/fo" + obj, rc_file])
384
385 except DistutilsExecError as msg:
386 raise CompileError(msg)
387 continue
388 else:
389 # how to handle this file?
390 raise CompileError("Don't know how to compile {} to {}"
391 .format(src, obj))
392
393 args = [self.cc] + compile_opts + pp_opts
394 if add_cpp_opts:
395 args.append('/EHsc')
396 args.append(input_opt)
397 args.append("/Fo" + obj)
398 args.extend(extra_postargs)
399
400 try:
401 self.spawn(args)
402 except DistutilsExecError as msg:
403 raise CompileError(msg)
404
405 return objects
406
407
408 def create_static_lib(self,
409 objects,
410 output_libname,
411 output_dir=None,
412 debug=0,
413 target_lang=None):
414
415 if not self.initialized:
416 self.initialize()
417 objects, output_dir = self._fix_object_args(objects, output_dir)
418 output_filename = self.library_filename(output_libname,
419 output_dir=output_dir)
420
421 if self._need_link(objects, output_filename):
422 lib_args = objects + ['/OUT:' + output_filename]
423 if debug:
424 pass # XXX what goes here?
425 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700426 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700427 self.spawn([self.lib] + lib_args)
428 except DistutilsExecError as msg:
429 raise LibError(msg)
430 else:
431 log.debug("skipping %s (up-to-date)", output_filename)
432
433
434 def link(self,
435 target_desc,
436 objects,
437 output_filename,
438 output_dir=None,
439 libraries=None,
440 library_dirs=None,
441 runtime_library_dirs=None,
442 export_symbols=None,
443 debug=0,
444 extra_preargs=None,
445 extra_postargs=None,
446 build_temp=None,
447 target_lang=None):
448
449 if not self.initialized:
450 self.initialize()
451 objects, output_dir = self._fix_object_args(objects, output_dir)
452 fixed_args = self._fix_lib_args(libraries, library_dirs,
453 runtime_library_dirs)
454 libraries, library_dirs, runtime_library_dirs = fixed_args
455
456 if runtime_library_dirs:
457 self.warn("I don't know what to do with 'runtime_library_dirs': "
458 + str(runtime_library_dirs))
459
460 lib_opts = gen_lib_options(self,
461 library_dirs, runtime_library_dirs,
462 libraries)
463 if output_dir is not None:
464 output_filename = os.path.join(output_dir, output_filename)
465
466 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700467 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700468
Steve Dower31202ea2015-08-05 11:39:19 -0700469 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700470
471 ld_args = (ldflags + lib_opts + export_opts +
472 objects + ['/OUT:' + output_filename])
473
474 # The MSVC linker generates .lib and .exp files, which cannot be
475 # suppressed by any linker switches. The .lib files may even be
476 # needed! Make sure they are generated in the temporary build
477 # directory. Since they have different names for debug and release
478 # builds, they can go into the same directory.
479 build_temp = os.path.dirname(objects[0])
480 if export_symbols is not None:
481 (dll_name, dll_ext) = os.path.splitext(
482 os.path.basename(output_filename))
483 implib_file = os.path.join(
484 build_temp,
485 self.library_filename(dll_name))
486 ld_args.append ('/IMPLIB:' + implib_file)
487
Steve Dowerfd3664b2015-05-23 09:02:50 -0700488 if extra_preargs:
489 ld_args[:0] = extra_preargs
490 if extra_postargs:
491 ld_args.extend(extra_postargs)
492
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700493 output_dir = os.path.dirname(os.path.abspath(output_filename))
494 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700495 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700496 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700497 self.spawn([self.linker] + ld_args)
498 except DistutilsExecError as msg:
499 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700500 else:
501 log.debug("skipping %s (up-to-date)", output_filename)
502
Steve Dower31202ea2015-08-05 11:39:19 -0700503 def spawn(self, cmd):
504 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700505 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700506 os.environ['path'] = self._paths
507 return super().spawn(cmd)
508 finally:
509 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700510
511 # -- Miscellaneous methods -----------------------------------------
512 # These are all used by the 'gen_lib_options() function, in
513 # ccompiler.py.
514
515 def library_dir_option(self, dir):
516 return "/LIBPATH:" + dir
517
518 def runtime_library_dir_option(self, dir):
519 raise DistutilsPlatformError(
520 "don't know how to set runtime library search path for MSVC")
521
522 def library_option(self, lib):
523 return self.library_filename(lib)
524
525 def find_library_file(self, dirs, lib, debug=0):
526 # Prefer a debugging library if found (and requested), but deal
527 # with it if we don't have one.
528 if debug:
529 try_names = [lib + "_d", lib]
530 else:
531 try_names = [lib]
532 for dir in dirs:
533 for name in try_names:
534 libfile = os.path.join(dir, self.library_filename(name))
535 if os.path.isfile(libfile):
536 return libfile
537 else:
538 # Oops, didn't find it in *any* of 'dirs'
539 return None