blob: 03a5f10ee782842fb571e2b45857c1408eaa9c29 [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
Steve Dowerfcbe1df2015-09-08 21:39:01 -070017import shutil
18import stat
Steve Dowerfd3664b2015-05-23 09:02:50 -070019import subprocess
Steve Dowerfd3664b2015-05-23 09:02:50 -070020
21from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
22 CompileError, LibError, LinkError
23from distutils.ccompiler import CCompiler, gen_lib_options
24from distutils import log
25from distutils.util import get_platform
26
27import winreg
28from itertools import count
29
Steve Dowerfcbe1df2015-09-08 21:39:01 -070030def _find_vcvarsall(plat_spec):
Steve Dowerfd3664b2015-05-23 09:02:50 -070031 with winreg.OpenKeyEx(
32 winreg.HKEY_LOCAL_MACHINE,
33 r"Software\Microsoft\VisualStudio\SxS\VC7",
34 access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
35 ) as key:
36 if not key:
37 log.debug("Visual C++ is not registered")
Steve Dowerfcbe1df2015-09-08 21:39:01 -070038 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070039
40 best_version = 0
41 best_dir = None
42 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
54 if not best_version:
55 log.debug("No suitable Visual C++ version found")
Steve Dowerfcbe1df2015-09-08 21:39:01 -070056 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070057
58 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
59 if not os.path.isfile(vcvarsall):
60 log.debug("%s cannot be found", vcvarsall)
Steve Dowerfcbe1df2015-09-08 21:39:01 -070061 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070062
Steve Dowerfcbe1df2015-09-08 21:39:01 -070063 vcruntime = None
64 vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST.get(plat_spec)
65 if vcruntime_spec:
66 vcruntime = os.path.join(best_dir,
67 vcruntime_spec.format(best_version))
68 if not os.path.isfile(vcruntime):
69 log.debug("%s cannot be found", vcruntime)
70 vcruntime = None
71
72 return vcvarsall, vcruntime
Steve Dowerfd3664b2015-05-23 09:02:50 -070073
74def _get_vc_env(plat_spec):
75 if os.getenv("DISTUTILS_USE_SDK"):
76 return {
77 key.lower(): value
78 for key, value in os.environ.items()
79 }
80
Steve Dowerfcbe1df2015-09-08 21:39:01 -070081 vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -070082 if not vcvarsall:
83 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
84
85 try:
86 out = subprocess.check_output(
87 '"{}" {} && set'.format(vcvarsall, plat_spec),
88 shell=True,
89 stderr=subprocess.STDOUT,
90 universal_newlines=True,
91 )
92 except subprocess.CalledProcessError as exc:
93 log.error(exc.output)
94 raise DistutilsPlatformError("Error executing {}"
95 .format(exc.cmd))
96
Steve Dowerfcbe1df2015-09-08 21:39:01 -070097 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -070098 key.lower(): value
99 for key, _, value in
100 (line.partition('=') for line in out.splitlines())
101 if key and value
102 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700103
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700104 if vcruntime:
105 env['py_vcruntime_redist'] = vcruntime
106 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700107
108def _find_exe(exe, paths=None):
109 """Return path to an MSVC executable program.
110
111 Tries to find the program in several places: first, one of the
112 MSVC program search paths from the registry; next, the directories
113 in the PATH environment variable. If any of those work, return an
114 absolute path that is known to exist. If none of them work, just
115 return the original program name, 'exe'.
116 """
117 if not paths:
118 paths = os.getenv('path').split(os.pathsep)
119 for p in paths:
120 fn = os.path.join(os.path.abspath(p), exe)
121 if os.path.isfile(fn):
122 return fn
123 return exe
124
125# A map keyed by get_platform() return values to values accepted by
126# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
127# the param to cross-compile on x86 targetting amd64.)
128PLAT_TO_VCVARS = {
129 'win32' : 'x86',
130 'win-amd64' : 'amd64',
131}
132
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700133# A map keyed by get_platform() return values to the file under
134# the VC install directory containing the vcruntime redistributable.
135_VCVARS_PLAT_TO_VCRUNTIME_REDIST = {
136 'x86' : 'redist\\x86\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
137 'amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
138 'x86_amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
139}
140
141# A set containing the DLLs that are guaranteed to be available for
142# all micro versions of this Python version. Known extension
143# dependencies that are not in this set will be copied to the output
144# path.
145_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
146
Steve Dowerfd3664b2015-05-23 09:02:50 -0700147class MSVCCompiler(CCompiler) :
148 """Concrete class that implements an interface to Microsoft Visual C++,
149 as defined by the CCompiler abstract class."""
150
151 compiler_type = 'msvc'
152
153 # Just set this so CCompiler's constructor doesn't barf. We currently
154 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
155 # as it really isn't necessary for this sort of single-compiler class.
156 # Would be nice to have a consistent interface with UnixCCompiler,
157 # though, so it's worth thinking about.
158 executables = {}
159
160 # Private class data (need to distinguish C from C++ source for compiler)
161 _c_extensions = ['.c']
162 _cpp_extensions = ['.cc', '.cpp', '.cxx']
163 _rc_extensions = ['.rc']
164 _mc_extensions = ['.mc']
165
166 # Needed for the filename generation methods provided by the
167 # base class, CCompiler.
168 src_extensions = (_c_extensions + _cpp_extensions +
169 _rc_extensions + _mc_extensions)
170 res_extension = '.res'
171 obj_extension = '.obj'
172 static_lib_extension = '.lib'
173 shared_lib_extension = '.dll'
174 static_lib_format = shared_lib_format = '%s%s'
175 exe_extension = '.exe'
176
177
178 def __init__(self, verbose=0, dry_run=0, force=0):
179 CCompiler.__init__ (self, verbose, dry_run, force)
180 # target platform (.plat_name is consistent with 'bdist')
181 self.plat_name = None
182 self.initialized = False
183
184 def initialize(self, plat_name=None):
185 # multi-init means we would need to check platform same each time...
186 assert not self.initialized, "don't init multiple times"
187 if plat_name is None:
188 plat_name = get_platform()
189 # sanity check for platforms to prevent obscure errors later.
190 if plat_name not in PLAT_TO_VCVARS:
191 raise DistutilsPlatformError("--plat-name must be one of {}"
192 .format(tuple(PLAT_TO_VCVARS)))
193
194 # On x86, 'vcvarsall.bat amd64' creates an env that doesn't work;
195 # to cross compile, you use 'x86_amd64'.
196 # On AMD64, 'vcvarsall.bat amd64' is a native build env; to cross
197 # compile use 'x86' (ie, it runs the x86 compiler directly)
198 if plat_name == get_platform() or plat_name == 'win32':
199 # native build or cross-compile to win32
200 plat_spec = PLAT_TO_VCVARS[plat_name]
201 else:
202 # cross compile from win32 -> some 64bit
203 plat_spec = '{}_{}'.format(
204 PLAT_TO_VCVARS[get_platform()],
205 PLAT_TO_VCVARS[plat_name]
206 )
207
208 vc_env = _get_vc_env(plat_spec)
209 if not vc_env:
210 raise DistutilsPlatformError("Unable to find a compatible "
211 "Visual Studio installation.")
212
Steve Dower31202ea2015-08-05 11:39:19 -0700213 self._paths = vc_env.get('path', '')
214 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700215 self.cc = _find_exe("cl.exe", paths)
216 self.linker = _find_exe("link.exe", paths)
217 self.lib = _find_exe("lib.exe", paths)
218 self.rc = _find_exe("rc.exe", paths) # resource compiler
219 self.mc = _find_exe("mc.exe", paths) # message compiler
220 self.mt = _find_exe("mt.exe", paths) # message compiler
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700221 self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700222
223 for dir in vc_env.get('include', '').split(os.pathsep):
224 if dir:
225 self.add_include_dir(dir)
226
227 for dir in vc_env.get('lib', '').split(os.pathsep):
228 if dir:
229 self.add_library_dir(dir)
230
231 self.preprocess_options = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700232 # If vcruntime_redist is available, link against it dynamically. Otherwise,
233 # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
Steve Dower31202ea2015-08-05 11:39:19 -0700234 # later to dynamically link to ucrtbase but not vcruntime.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700235 self.compile_options = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700236 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700237 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700238 self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
Larry Hastings52e40cd2015-09-09 06:54:57 -0700239
Steve Dowerfd3664b2015-05-23 09:02:50 -0700240 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700241 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700242 ]
243
Steve Dower31202ea2015-08-05 11:39:19 -0700244 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700245 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700246 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700247 if not self._vcruntime_redist:
248 ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
249
Steve Dower31202ea2015-08-05 11:39:19 -0700250 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700251 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700252 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700253
254 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
255 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
256 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
257 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
258 self.ldflags_static = [*ldflags]
259 self.ldflags_static_debug = [*ldflags_debug]
260
261 self._ldflags = {
262 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
263 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
264 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
265 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
266 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
267 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
268 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
269 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
270 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
271 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700272
273 self.initialized = True
274
275 # -- Worker methods ------------------------------------------------
276
277 def object_filenames(self,
278 source_filenames,
279 strip_dir=0,
280 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700281 ext_map = {
282 **{ext: self.obj_extension for ext in self.src_extensions},
283 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
284 }
285
286 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700287
288 def make_out_path(p):
289 base, ext = os.path.splitext(p)
290 if strip_dir:
291 base = os.path.basename(base)
292 else:
293 _, base = os.path.splitdrive(base)
294 if base.startswith((os.path.sep, os.path.altsep)):
295 base = base[1:]
296 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700297 # XXX: This may produce absurdly long paths. We should check
298 # the length of the result and trim base until we fit within
299 # 260 characters.
300 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700301 except LookupError:
302 # Better to raise an exception instead of silently continuing
303 # and later complain about sources and targets having
304 # different lengths
305 raise CompileError("Don't know how to compile {}".format(p))
306
Steve Dower31202ea2015-08-05 11:39:19 -0700307 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700308
309
310 def compile(self, sources,
311 output_dir=None, macros=None, include_dirs=None, debug=0,
312 extra_preargs=None, extra_postargs=None, depends=None):
313
314 if not self.initialized:
315 self.initialize()
316 compile_info = self._setup_compile(output_dir, macros, include_dirs,
317 sources, depends, extra_postargs)
318 macros, objects, extra_postargs, pp_opts, build = compile_info
319
320 compile_opts = extra_preargs or []
321 compile_opts.append('/c')
322 if debug:
323 compile_opts.extend(self.compile_options_debug)
324 else:
325 compile_opts.extend(self.compile_options)
326
327
328 add_cpp_opts = False
329
330 for obj in objects:
331 try:
332 src, ext = build[obj]
333 except KeyError:
334 continue
335 if debug:
336 # pass the full pathname to MSVC in debug mode,
337 # this allows the debugger to find the source file
338 # without asking the user to browse for it
339 src = os.path.abspath(src)
340
341 if ext in self._c_extensions:
342 input_opt = "/Tc" + src
343 elif ext in self._cpp_extensions:
344 input_opt = "/Tp" + src
345 add_cpp_opts = True
346 elif ext in self._rc_extensions:
347 # compile .RC to .RES file
348 input_opt = src
349 output_opt = "/fo" + obj
350 try:
351 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
352 except DistutilsExecError as msg:
353 raise CompileError(msg)
354 continue
355 elif ext in self._mc_extensions:
356 # Compile .MC to .RC file to .RES file.
357 # * '-h dir' specifies the directory for the
358 # generated include file
359 # * '-r dir' specifies the target directory of the
360 # generated RC file and the binary message resource
361 # it includes
362 #
363 # For now (since there are no options to change this),
364 # we use the source-directory for the include file and
365 # the build directory for the RC file and message
366 # resources. This works at least for win32all.
367 h_dir = os.path.dirname(src)
368 rc_dir = os.path.dirname(obj)
369 try:
370 # first compile .MC to .RC and .H file
371 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
372 base, _ = os.path.splitext(os.path.basename (src))
373 rc_file = os.path.join(rc_dir, base + '.rc')
374 # then compile .RC to .RES file
375 self.spawn([self.rc, "/fo" + obj, rc_file])
376
377 except DistutilsExecError as msg:
378 raise CompileError(msg)
379 continue
380 else:
381 # how to handle this file?
382 raise CompileError("Don't know how to compile {} to {}"
383 .format(src, obj))
384
385 args = [self.cc] + compile_opts + pp_opts
386 if add_cpp_opts:
387 args.append('/EHsc')
388 args.append(input_opt)
389 args.append("/Fo" + obj)
390 args.extend(extra_postargs)
391
392 try:
393 self.spawn(args)
394 except DistutilsExecError as msg:
395 raise CompileError(msg)
396
397 return objects
398
399
400 def create_static_lib(self,
401 objects,
402 output_libname,
403 output_dir=None,
404 debug=0,
405 target_lang=None):
406
407 if not self.initialized:
408 self.initialize()
409 objects, output_dir = self._fix_object_args(objects, output_dir)
410 output_filename = self.library_filename(output_libname,
411 output_dir=output_dir)
412
413 if self._need_link(objects, output_filename):
414 lib_args = objects + ['/OUT:' + output_filename]
415 if debug:
416 pass # XXX what goes here?
417 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700418 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700419 self.spawn([self.lib] + lib_args)
420 except DistutilsExecError as msg:
421 raise LibError(msg)
422 else:
423 log.debug("skipping %s (up-to-date)", output_filename)
424
425
426 def link(self,
427 target_desc,
428 objects,
429 output_filename,
430 output_dir=None,
431 libraries=None,
432 library_dirs=None,
433 runtime_library_dirs=None,
434 export_symbols=None,
435 debug=0,
436 extra_preargs=None,
437 extra_postargs=None,
438 build_temp=None,
439 target_lang=None):
440
441 if not self.initialized:
442 self.initialize()
443 objects, output_dir = self._fix_object_args(objects, output_dir)
444 fixed_args = self._fix_lib_args(libraries, library_dirs,
445 runtime_library_dirs)
446 libraries, library_dirs, runtime_library_dirs = fixed_args
447
448 if runtime_library_dirs:
449 self.warn("I don't know what to do with 'runtime_library_dirs': "
450 + str(runtime_library_dirs))
451
452 lib_opts = gen_lib_options(self,
453 library_dirs, runtime_library_dirs,
454 libraries)
455 if output_dir is not None:
456 output_filename = os.path.join(output_dir, output_filename)
457
458 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700459 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700460
Steve Dower31202ea2015-08-05 11:39:19 -0700461 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700462
463 ld_args = (ldflags + lib_opts + export_opts +
464 objects + ['/OUT:' + output_filename])
465
466 # The MSVC linker generates .lib and .exp files, which cannot be
467 # suppressed by any linker switches. The .lib files may even be
468 # needed! Make sure they are generated in the temporary build
469 # directory. Since they have different names for debug and release
470 # builds, they can go into the same directory.
471 build_temp = os.path.dirname(objects[0])
472 if export_symbols is not None:
473 (dll_name, dll_ext) = os.path.splitext(
474 os.path.basename(output_filename))
475 implib_file = os.path.join(
476 build_temp,
477 self.library_filename(dll_name))
478 ld_args.append ('/IMPLIB:' + implib_file)
479
Steve Dowerfd3664b2015-05-23 09:02:50 -0700480 if extra_preargs:
481 ld_args[:0] = extra_preargs
482 if extra_postargs:
483 ld_args.extend(extra_postargs)
484
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700485 output_dir = os.path.dirname(os.path.abspath(output_filename))
486 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700487 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700488 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700489 self.spawn([self.linker] + ld_args)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700490 self._copy_vcruntime(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700491 except DistutilsExecError as msg:
492 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700493 else:
494 log.debug("skipping %s (up-to-date)", output_filename)
495
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700496 def _copy_vcruntime(self, output_dir):
497 vcruntime = self._vcruntime_redist
498 if not vcruntime or not os.path.isfile(vcruntime):
499 return
500
501 if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
502 return
503
504 log.debug('Copying "%s"', vcruntime)
505 vcruntime = shutil.copy(vcruntime, output_dir)
506 os.chmod(vcruntime, stat.S_IWRITE)
507
Steve Dower31202ea2015-08-05 11:39:19 -0700508 def spawn(self, cmd):
509 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700510 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700511 os.environ['path'] = self._paths
512 return super().spawn(cmd)
513 finally:
514 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700515
516 # -- Miscellaneous methods -----------------------------------------
517 # These are all used by the 'gen_lib_options() function, in
518 # ccompiler.py.
519
520 def library_dir_option(self, dir):
521 return "/LIBPATH:" + dir
522
523 def runtime_library_dir_option(self, dir):
524 raise DistutilsPlatformError(
525 "don't know how to set runtime library search path for MSVC")
526
527 def library_option(self, lib):
528 return self.library_filename(lib)
529
530 def find_library_file(self, dirs, lib, debug=0):
531 # Prefer a debugging library if found (and requested), but deal
532 # with it if we don't have one.
533 if debug:
534 try_names = [lib + "_d", lib]
535 else:
536 try_names = [lib]
537 for dir in dirs:
538 for name in try_names:
539 libfile = os.path.join(dir, self.library_filename(name))
540 if os.path.isfile(libfile):
541 return libfile
542 else:
543 # Oops, didn't find it in *any* of 'dirs'
544 return None