blob: d0ba7d6d1efc0061d34e92f9695da6e88e53e463 [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 Dowerf0ccf022015-10-05 10:35:00 -070031 try:
32 key = winreg.OpenKeyEx(
33 winreg.HKEY_LOCAL_MACHINE,
34 r"Software\Microsoft\VisualStudio\SxS\VC7",
35 access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
36 )
37 except OSError:
38 log.debug("Visual C++ is not registered")
39 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070040
Steve Dowerf0ccf022015-10-05 10:35:00 -070041 with key:
Steve Dowerfd3664b2015-05-23 09:02:50 -070042 best_version = 0
43 best_dir = None
44 for i in count():
45 try:
46 v, vc_dir, vt = winreg.EnumValue(key, i)
47 except OSError:
48 break
49 if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
50 try:
51 version = int(float(v))
52 except (ValueError, TypeError):
53 continue
54 if version >= 14 and version > best_version:
55 best_version, best_dir = version, vc_dir
56 if not best_version:
57 log.debug("No suitable Visual C++ version found")
Steve Dowerfcbe1df2015-09-08 21:39:01 -070058 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070059
60 vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
61 if not os.path.isfile(vcvarsall):
62 log.debug("%s cannot be found", vcvarsall)
Steve Dowerfcbe1df2015-09-08 21:39:01 -070063 return None, None
Steve Dowerfd3664b2015-05-23 09:02:50 -070064
Steve Dowerfcbe1df2015-09-08 21:39:01 -070065 vcruntime = None
66 vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST.get(plat_spec)
67 if vcruntime_spec:
68 vcruntime = os.path.join(best_dir,
69 vcruntime_spec.format(best_version))
70 if not os.path.isfile(vcruntime):
71 log.debug("%s cannot be found", vcruntime)
72 vcruntime = None
73
74 return vcvarsall, vcruntime
Steve Dowerfd3664b2015-05-23 09:02:50 -070075
76def _get_vc_env(plat_spec):
77 if os.getenv("DISTUTILS_USE_SDK"):
78 return {
79 key.lower(): value
80 for key, value in os.environ.items()
81 }
82
Steve Dowerfcbe1df2015-09-08 21:39:01 -070083 vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
Steve Dowerfd3664b2015-05-23 09:02:50 -070084 if not vcvarsall:
85 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
86
87 try:
88 out = subprocess.check_output(
89 '"{}" {} && set'.format(vcvarsall, plat_spec),
90 shell=True,
91 stderr=subprocess.STDOUT,
92 universal_newlines=True,
93 )
94 except subprocess.CalledProcessError as exc:
95 log.error(exc.output)
96 raise DistutilsPlatformError("Error executing {}"
97 .format(exc.cmd))
98
Steve Dowerfcbe1df2015-09-08 21:39:01 -070099 env = {
Steve Dowerfd3664b2015-05-23 09:02:50 -0700100 key.lower(): value
101 for key, _, value in
102 (line.partition('=') for line in out.splitlines())
103 if key and value
104 }
Larry Hastings52e40cd2015-09-09 06:54:57 -0700105
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700106 if vcruntime:
107 env['py_vcruntime_redist'] = vcruntime
108 return env
Steve Dowerfd3664b2015-05-23 09:02:50 -0700109
110def _find_exe(exe, paths=None):
111 """Return path to an MSVC executable program.
112
113 Tries to find the program in several places: first, one of the
114 MSVC program search paths from the registry; next, the directories
115 in the PATH environment variable. If any of those work, return an
116 absolute path that is known to exist. If none of them work, just
117 return the original program name, 'exe'.
118 """
119 if not paths:
120 paths = os.getenv('path').split(os.pathsep)
121 for p in paths:
122 fn = os.path.join(os.path.abspath(p), exe)
123 if os.path.isfile(fn):
124 return fn
125 return exe
126
127# A map keyed by get_platform() return values to values accepted by
Steve Dower1d329412016-01-16 12:39:10 -0800128# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
129# lighter-weight MSVC installs that do not include native 64-bit tools.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700130PLAT_TO_VCVARS = {
131 'win32' : 'x86',
Steve Dower1d329412016-01-16 12:39:10 -0800132 'win-amd64' : 'x86_amd64',
Steve Dowerfd3664b2015-05-23 09:02:50 -0700133}
134
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700135# A map keyed by get_platform() return values to the file under
136# the VC install directory containing the vcruntime redistributable.
137_VCVARS_PLAT_TO_VCRUNTIME_REDIST = {
138 'x86' : 'redist\\x86\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
139 'amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
140 'x86_amd64' : 'redist\\x64\\Microsoft.VC{0}0.CRT\\vcruntime{0}0.dll',
141}
142
143# A set containing the DLLs that are guaranteed to be available for
144# all micro versions of this Python version. Known extension
145# dependencies that are not in this set will be copied to the output
146# path.
147_BUNDLED_DLLS = frozenset(['vcruntime140.dll'])
148
Steve Dowerfd3664b2015-05-23 09:02:50 -0700149class MSVCCompiler(CCompiler) :
150 """Concrete class that implements an interface to Microsoft Visual C++,
151 as defined by the CCompiler abstract class."""
152
153 compiler_type = 'msvc'
154
155 # Just set this so CCompiler's constructor doesn't barf. We currently
156 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
157 # as it really isn't necessary for this sort of single-compiler class.
158 # Would be nice to have a consistent interface with UnixCCompiler,
159 # though, so it's worth thinking about.
160 executables = {}
161
162 # Private class data (need to distinguish C from C++ source for compiler)
163 _c_extensions = ['.c']
164 _cpp_extensions = ['.cc', '.cpp', '.cxx']
165 _rc_extensions = ['.rc']
166 _mc_extensions = ['.mc']
167
168 # Needed for the filename generation methods provided by the
169 # base class, CCompiler.
170 src_extensions = (_c_extensions + _cpp_extensions +
171 _rc_extensions + _mc_extensions)
172 res_extension = '.res'
173 obj_extension = '.obj'
174 static_lib_extension = '.lib'
175 shared_lib_extension = '.dll'
176 static_lib_format = shared_lib_format = '%s%s'
177 exe_extension = '.exe'
178
179
180 def __init__(self, verbose=0, dry_run=0, force=0):
181 CCompiler.__init__ (self, verbose, dry_run, force)
182 # target platform (.plat_name is consistent with 'bdist')
183 self.plat_name = None
184 self.initialized = False
185
186 def initialize(self, plat_name=None):
187 # multi-init means we would need to check platform same each time...
188 assert not self.initialized, "don't init multiple times"
189 if plat_name is None:
190 plat_name = get_platform()
191 # sanity check for platforms to prevent obscure errors later.
192 if plat_name not in PLAT_TO_VCVARS:
193 raise DistutilsPlatformError("--plat-name must be one of {}"
194 .format(tuple(PLAT_TO_VCVARS)))
195
Steve Dower1d329412016-01-16 12:39:10 -0800196 # Get the vcvarsall.bat spec for the requested platform.
197 plat_spec = PLAT_TO_VCVARS[plat_name]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700198
199 vc_env = _get_vc_env(plat_spec)
200 if not vc_env:
201 raise DistutilsPlatformError("Unable to find a compatible "
202 "Visual Studio installation.")
203
Steve Dower31202ea2015-08-05 11:39:19 -0700204 self._paths = vc_env.get('path', '')
205 paths = self._paths.split(os.pathsep)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700206 self.cc = _find_exe("cl.exe", paths)
207 self.linker = _find_exe("link.exe", paths)
208 self.lib = _find_exe("lib.exe", paths)
209 self.rc = _find_exe("rc.exe", paths) # resource compiler
210 self.mc = _find_exe("mc.exe", paths) # message compiler
211 self.mt = _find_exe("mt.exe", paths) # message compiler
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700212 self._vcruntime_redist = vc_env.get('py_vcruntime_redist', '')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700213
214 for dir in vc_env.get('include', '').split(os.pathsep):
215 if dir:
216 self.add_include_dir(dir)
217
218 for dir in vc_env.get('lib', '').split(os.pathsep):
219 if dir:
220 self.add_library_dir(dir)
221
222 self.preprocess_options = None
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700223 # If vcruntime_redist is available, link against it dynamically. Otherwise,
224 # use /MT[d] to build statically, then switch from libucrt[d].lib to ucrt[d].lib
Steve Dower31202ea2015-08-05 11:39:19 -0700225 # later to dynamically link to ucrtbase but not vcruntime.
Steve Dowerfd3664b2015-05-23 09:02:50 -0700226 self.compile_options = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700227 '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700228 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700229 self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')
Larry Hastings52e40cd2015-09-09 06:54:57 -0700230
Steve Dowerfd3664b2015-05-23 09:02:50 -0700231 self.compile_options_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700232 '/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700233 ]
234
Steve Dower31202ea2015-08-05 11:39:19 -0700235 ldflags = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700236 '/nologo', '/INCREMENTAL:NO', '/LTCG'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700237 ]
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700238 if not self._vcruntime_redist:
239 ldflags.extend(('/nodefaultlib:libucrt.lib', 'ucrt.lib'))
240
Steve Dower31202ea2015-08-05 11:39:19 -0700241 ldflags_debug = [
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700242 '/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
Steve Dowerfd3664b2015-05-23 09:02:50 -0700243 ]
Steve Dower31202ea2015-08-05 11:39:19 -0700244
245 self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
246 self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
247 self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
248 self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
249 self.ldflags_static = [*ldflags]
250 self.ldflags_static_debug = [*ldflags_debug]
251
252 self._ldflags = {
253 (CCompiler.EXECUTABLE, None): self.ldflags_exe,
254 (CCompiler.EXECUTABLE, False): self.ldflags_exe,
255 (CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
256 (CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
257 (CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
258 (CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
259 (CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
260 (CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
261 (CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
262 }
Steve Dowerfd3664b2015-05-23 09:02:50 -0700263
264 self.initialized = True
265
266 # -- Worker methods ------------------------------------------------
267
268 def object_filenames(self,
269 source_filenames,
270 strip_dir=0,
271 output_dir=''):
Steve Dower31202ea2015-08-05 11:39:19 -0700272 ext_map = {
273 **{ext: self.obj_extension for ext in self.src_extensions},
274 **{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
275 }
276
277 output_dir = output_dir or ''
Steve Dowerfd3664b2015-05-23 09:02:50 -0700278
279 def make_out_path(p):
280 base, ext = os.path.splitext(p)
281 if strip_dir:
282 base = os.path.basename(base)
283 else:
284 _, base = os.path.splitdrive(base)
285 if base.startswith((os.path.sep, os.path.altsep)):
286 base = base[1:]
287 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700288 # XXX: This may produce absurdly long paths. We should check
289 # the length of the result and trim base until we fit within
290 # 260 characters.
291 return os.path.join(output_dir, base + ext_map[ext])
Steve Dowerfd3664b2015-05-23 09:02:50 -0700292 except LookupError:
293 # Better to raise an exception instead of silently continuing
294 # and later complain about sources and targets having
295 # different lengths
296 raise CompileError("Don't know how to compile {}".format(p))
297
Steve Dower31202ea2015-08-05 11:39:19 -0700298 return list(map(make_out_path, source_filenames))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700299
300
301 def compile(self, sources,
302 output_dir=None, macros=None, include_dirs=None, debug=0,
303 extra_preargs=None, extra_postargs=None, depends=None):
304
305 if not self.initialized:
306 self.initialize()
307 compile_info = self._setup_compile(output_dir, macros, include_dirs,
308 sources, depends, extra_postargs)
309 macros, objects, extra_postargs, pp_opts, build = compile_info
310
311 compile_opts = extra_preargs or []
312 compile_opts.append('/c')
313 if debug:
314 compile_opts.extend(self.compile_options_debug)
315 else:
316 compile_opts.extend(self.compile_options)
317
318
319 add_cpp_opts = False
320
321 for obj in objects:
322 try:
323 src, ext = build[obj]
324 except KeyError:
325 continue
326 if debug:
327 # pass the full pathname to MSVC in debug mode,
328 # this allows the debugger to find the source file
329 # without asking the user to browse for it
330 src = os.path.abspath(src)
331
332 if ext in self._c_extensions:
333 input_opt = "/Tc" + src
334 elif ext in self._cpp_extensions:
335 input_opt = "/Tp" + src
336 add_cpp_opts = True
337 elif ext in self._rc_extensions:
338 # compile .RC to .RES file
339 input_opt = src
340 output_opt = "/fo" + obj
341 try:
342 self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
343 except DistutilsExecError as msg:
344 raise CompileError(msg)
345 continue
346 elif ext in self._mc_extensions:
347 # Compile .MC to .RC file to .RES file.
348 # * '-h dir' specifies the directory for the
349 # generated include file
350 # * '-r dir' specifies the target directory of the
351 # generated RC file and the binary message resource
352 # it includes
353 #
354 # For now (since there are no options to change this),
355 # we use the source-directory for the include file and
356 # the build directory for the RC file and message
357 # resources. This works at least for win32all.
358 h_dir = os.path.dirname(src)
359 rc_dir = os.path.dirname(obj)
360 try:
361 # first compile .MC to .RC and .H file
362 self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
363 base, _ = os.path.splitext(os.path.basename (src))
364 rc_file = os.path.join(rc_dir, base + '.rc')
365 # then compile .RC to .RES file
366 self.spawn([self.rc, "/fo" + obj, rc_file])
367
368 except DistutilsExecError as msg:
369 raise CompileError(msg)
370 continue
371 else:
372 # how to handle this file?
373 raise CompileError("Don't know how to compile {} to {}"
374 .format(src, obj))
375
376 args = [self.cc] + compile_opts + pp_opts
377 if add_cpp_opts:
378 args.append('/EHsc')
379 args.append(input_opt)
380 args.append("/Fo" + obj)
381 args.extend(extra_postargs)
382
383 try:
384 self.spawn(args)
385 except DistutilsExecError as msg:
386 raise CompileError(msg)
387
388 return objects
389
390
391 def create_static_lib(self,
392 objects,
393 output_libname,
394 output_dir=None,
395 debug=0,
396 target_lang=None):
397
398 if not self.initialized:
399 self.initialize()
400 objects, output_dir = self._fix_object_args(objects, output_dir)
401 output_filename = self.library_filename(output_libname,
402 output_dir=output_dir)
403
404 if self._need_link(objects, output_filename):
405 lib_args = objects + ['/OUT:' + output_filename]
406 if debug:
407 pass # XXX what goes here?
408 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700409 log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700410 self.spawn([self.lib] + lib_args)
411 except DistutilsExecError as msg:
412 raise LibError(msg)
413 else:
414 log.debug("skipping %s (up-to-date)", output_filename)
415
416
417 def link(self,
418 target_desc,
419 objects,
420 output_filename,
421 output_dir=None,
422 libraries=None,
423 library_dirs=None,
424 runtime_library_dirs=None,
425 export_symbols=None,
426 debug=0,
427 extra_preargs=None,
428 extra_postargs=None,
429 build_temp=None,
430 target_lang=None):
431
432 if not self.initialized:
433 self.initialize()
434 objects, output_dir = self._fix_object_args(objects, output_dir)
435 fixed_args = self._fix_lib_args(libraries, library_dirs,
436 runtime_library_dirs)
437 libraries, library_dirs, runtime_library_dirs = fixed_args
438
439 if runtime_library_dirs:
440 self.warn("I don't know what to do with 'runtime_library_dirs': "
441 + str(runtime_library_dirs))
442
443 lib_opts = gen_lib_options(self,
444 library_dirs, runtime_library_dirs,
445 libraries)
446 if output_dir is not None:
447 output_filename = os.path.join(output_dir, output_filename)
448
449 if self._need_link(objects, output_filename):
Steve Dower31202ea2015-08-05 11:39:19 -0700450 ldflags = self._ldflags[target_desc, debug]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700451
Steve Dower31202ea2015-08-05 11:39:19 -0700452 export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
Steve Dowerfd3664b2015-05-23 09:02:50 -0700453
454 ld_args = (ldflags + lib_opts + export_opts +
455 objects + ['/OUT:' + output_filename])
456
457 # The MSVC linker generates .lib and .exp files, which cannot be
458 # suppressed by any linker switches. The .lib files may even be
459 # needed! Make sure they are generated in the temporary build
460 # directory. Since they have different names for debug and release
461 # builds, they can go into the same directory.
462 build_temp = os.path.dirname(objects[0])
463 if export_symbols is not None:
464 (dll_name, dll_ext) = os.path.splitext(
465 os.path.basename(output_filename))
466 implib_file = os.path.join(
467 build_temp,
468 self.library_filename(dll_name))
469 ld_args.append ('/IMPLIB:' + implib_file)
470
Steve Dowerfd3664b2015-05-23 09:02:50 -0700471 if extra_preargs:
472 ld_args[:0] = extra_preargs
473 if extra_postargs:
474 ld_args.extend(extra_postargs)
475
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700476 output_dir = os.path.dirname(os.path.abspath(output_filename))
477 self.mkpath(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700478 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700479 log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
Steve Dowerfd3664b2015-05-23 09:02:50 -0700480 self.spawn([self.linker] + ld_args)
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700481 self._copy_vcruntime(output_dir)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700482 except DistutilsExecError as msg:
483 raise LinkError(msg)
Steve Dowerfd3664b2015-05-23 09:02:50 -0700484 else:
485 log.debug("skipping %s (up-to-date)", output_filename)
486
Steve Dowerfcbe1df2015-09-08 21:39:01 -0700487 def _copy_vcruntime(self, output_dir):
488 vcruntime = self._vcruntime_redist
489 if not vcruntime or not os.path.isfile(vcruntime):
490 return
491
492 if os.path.basename(vcruntime).lower() in _BUNDLED_DLLS:
493 return
494
495 log.debug('Copying "%s"', vcruntime)
496 vcruntime = shutil.copy(vcruntime, output_dir)
497 os.chmod(vcruntime, stat.S_IWRITE)
498
Steve Dower31202ea2015-08-05 11:39:19 -0700499 def spawn(self, cmd):
500 old_path = os.getenv('path')
Steve Dowerfd3664b2015-05-23 09:02:50 -0700501 try:
Steve Dower31202ea2015-08-05 11:39:19 -0700502 os.environ['path'] = self._paths
503 return super().spawn(cmd)
504 finally:
505 os.environ['path'] = old_path
Steve Dowerfd3664b2015-05-23 09:02:50 -0700506
507 # -- Miscellaneous methods -----------------------------------------
508 # These are all used by the 'gen_lib_options() function, in
509 # ccompiler.py.
510
511 def library_dir_option(self, dir):
512 return "/LIBPATH:" + dir
513
514 def runtime_library_dir_option(self, dir):
515 raise DistutilsPlatformError(
516 "don't know how to set runtime library search path for MSVC")
517
518 def library_option(self, lib):
519 return self.library_filename(lib)
520
521 def find_library_file(self, dirs, lib, debug=0):
522 # Prefer a debugging library if found (and requested), but deal
523 # with it if we don't have one.
524 if debug:
525 try_names = [lib + "_d", lib]
526 else:
527 try_names = [lib]
528 for dir in dirs:
529 for name in try_names:
530 libfile = os.path.join(dir, self.library_filename(name))
531 if os.path.isfile(libfile):
532 return libfile
533 else:
534 # Oops, didn't find it in *any* of 'dirs'
535 return None