1 """distutils.msvccompiler
2
3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
4 for the Microsoft Visual Studio.
5 """
6
7 # Written by Perry Stoll
8 # hacked by Robin Becker and Thomas Heller to do a better job of
9 # finding DevStudio (through the registry)
10
11 import sys, os
12 from distutils.errors import \
13 DistutilsExecError, DistutilsPlatformError, \
14 CompileError, LibError, LinkError
15 from distutils.ccompiler import \
16 CCompiler, gen_lib_options
17 from distutils import log
18
19 _can_read_reg = False
20 try:
21 import winreg
22
23 _can_read_reg = True
24 hkey_mod = winreg
25
26 RegOpenKeyEx = winreg.OpenKeyEx
27 RegEnumKey = winreg.EnumKey
28 RegEnumValue = winreg.EnumValue
29 RegError = winreg.error
30
31 except ImportError:
32 try:
33 import win32api
34 import win32con
35 _can_read_reg = True
36 hkey_mod = win32con
37
38 RegOpenKeyEx = win32api.RegOpenKeyEx
39 RegEnumKey = win32api.RegEnumKey
40 RegEnumValue = win32api.RegEnumValue
41 RegError = win32api.error
42 except ImportError:
43 log.info("Warning: Can't read registry to find the "
44 "necessary compiler setting\n"
45 "Make sure that Python modules winreg, "
46 "win32api or win32con are installed.")
47
48 if _can_read_reg:
49 HKEYS = (hkey_mod.HKEY_USERS,
50 hkey_mod.HKEY_CURRENT_USER,
51 hkey_mod.HKEY_LOCAL_MACHINE,
52 hkey_mod.HKEY_CLASSES_ROOT)
53
54 def read_keys(base, key):
55 """Return list of registry keys."""
56 try:
57 handle = RegOpenKeyEx(base, key)
58 except RegError:
59 return None
60 L = []
61 i = 0
62 while True:
63 try:
64 k = RegEnumKey(handle, i)
65 except RegError:
66 break
67 L.append(k)
68 i += 1
69 return L
70
71 def read_values(base, key):
72 """Return dict of registry keys and values.
73
74 All names are converted to lowercase.
75 """
76 try:
77 handle = RegOpenKeyEx(base, key)
78 except RegError:
79 return None
80 d = {}
81 i = 0
82 while True:
83 try:
84 name, value, type = RegEnumValue(handle, i)
85 except RegError:
86 break
87 name = name.lower()
88 d[convert_mbcs(name)] = convert_mbcs(value)
89 i += 1
90 return d
91
92 def convert_mbcs(s):
93 dec = getattr(s, "decode", None)
94 if dec is not None:
95 try:
96 s = dec("mbcs")
97 except UnicodeError:
98 pass
99 return s
100
101 class ESC[4;38;5;81mMacroExpander:
102 def __init__(self, version):
103 self.macros = {}
104 self.load_macros(version)
105
106 def set_macro(self, macro, path, key):
107 for base in HKEYS:
108 d = read_values(base, path)
109 if d:
110 self.macros["$(%s)" % macro] = d[key]
111 break
112
113 def load_macros(self, version):
114 vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
115 self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
116 self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
117 net = r"Software\Microsoft\.NETFramework"
118 self.set_macro("FrameworkDir", net, "installroot")
119 try:
120 if version > 7.0:
121 self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
122 else:
123 self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
124 except KeyError as exc: #
125 raise DistutilsPlatformError(
126 """Python was built with Visual Studio 2003;
127 extensions must be built with a compiler than can generate compatible binaries.
128 Visual Studio 2003 was not found on this system. If you have Cygwin installed,
129 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
130
131 p = r"Software\Microsoft\NET Framework Setup\Product"
132 for base in HKEYS:
133 try:
134 h = RegOpenKeyEx(base, p)
135 except RegError:
136 continue
137 key = RegEnumKey(h, 0)
138 d = read_values(base, r"%s\%s" % (p, key))
139 self.macros["$(FrameworkVersion)"] = d["version"]
140
141 def sub(self, s):
142 for k, v in self.macros.items():
143 s = s.replace(k, v)
144 return s
145
146 def get_build_version():
147 """Return the version of MSVC that was used to build Python.
148
149 For Python 2.3 and up, the version number is included in
150 sys.version. For earlier versions, assume the compiler is MSVC 6.
151 """
152 prefix = "MSC v."
153 i = sys.version.find(prefix)
154 if i == -1:
155 return 6
156 i = i + len(prefix)
157 s, rest = sys.version[i:].split(" ", 1)
158 majorVersion = int(s[:-2]) - 6
159 if majorVersion >= 13:
160 # v13 was skipped and should be v14
161 majorVersion += 1
162 minorVersion = int(s[2:3]) / 10.0
163 # I don't think paths are affected by minor version in version 6
164 if majorVersion == 6:
165 minorVersion = 0
166 if majorVersion >= 6:
167 return majorVersion + minorVersion
168 # else we don't know what version of the compiler this is
169 return None
170
171 def get_build_architecture():
172 """Return the processor architecture.
173
174 Possible results are "Intel" or "AMD64".
175 """
176
177 prefix = " bit ("
178 i = sys.version.find(prefix)
179 if i == -1:
180 return "Intel"
181 j = sys.version.find(")", i)
182 return sys.version[i+len(prefix):j]
183
184 def normalize_and_reduce_paths(paths):
185 """Return a list of normalized paths with duplicates removed.
186
187 The current order of paths is maintained.
188 """
189 # Paths are normalized so things like: /a and /a/ aren't both preserved.
190 reduced_paths = []
191 for p in paths:
192 np = os.path.normpath(p)
193 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
194 if np not in reduced_paths:
195 reduced_paths.append(np)
196 return reduced_paths
197
198
199 class ESC[4;38;5;81mMSVCCompiler(ESC[4;38;5;149mCCompiler) :
200 """Concrete class that implements an interface to Microsoft Visual C++,
201 as defined by the CCompiler abstract class."""
202
203 compiler_type = 'msvc'
204
205 # Just set this so CCompiler's constructor doesn't barf. We currently
206 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
207 # as it really isn't necessary for this sort of single-compiler class.
208 # Would be nice to have a consistent interface with UnixCCompiler,
209 # though, so it's worth thinking about.
210 executables = {}
211
212 # Private class data (need to distinguish C from C++ source for compiler)
213 _c_extensions = ['.c']
214 _cpp_extensions = ['.cc', '.cpp', '.cxx']
215 _rc_extensions = ['.rc']
216 _mc_extensions = ['.mc']
217
218 # Needed for the filename generation methods provided by the
219 # base class, CCompiler.
220 src_extensions = (_c_extensions + _cpp_extensions +
221 _rc_extensions + _mc_extensions)
222 res_extension = '.res'
223 obj_extension = '.obj'
224 static_lib_extension = '.lib'
225 shared_lib_extension = '.dll'
226 static_lib_format = shared_lib_format = '%s%s'
227 exe_extension = '.exe'
228
229 def __init__(self, verbose=0, dry_run=0, force=0):
230 CCompiler.__init__ (self, verbose, dry_run, force)
231 self.__version = get_build_version()
232 self.__arch = get_build_architecture()
233 if self.__arch == "Intel":
234 # x86
235 if self.__version >= 7:
236 self.__root = r"Software\Microsoft\VisualStudio"
237 self.__macros = MacroExpander(self.__version)
238 else:
239 self.__root = r"Software\Microsoft\Devstudio"
240 self.__product = "Visual Studio version %s" % self.__version
241 else:
242 # Win64. Assume this was built with the platform SDK
243 self.__product = "Microsoft SDK compiler %s" % (self.__version + 6)
244
245 self.initialized = False
246
247 def initialize(self):
248 self.__paths = []
249 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
250 # Assume that the SDK set up everything alright; don't try to be
251 # smarter
252 self.cc = "cl.exe"
253 self.linker = "link.exe"
254 self.lib = "lib.exe"
255 self.rc = "rc.exe"
256 self.mc = "mc.exe"
257 else:
258 self.__paths = self.get_msvc_paths("path")
259
260 if len(self.__paths) == 0:
261 raise DistutilsPlatformError("Python was built with %s, "
262 "and extensions need to be built with the same "
263 "version of the compiler, but it isn't installed."
264 % self.__product)
265
266 self.cc = self.find_exe("cl.exe")
267 self.linker = self.find_exe("link.exe")
268 self.lib = self.find_exe("lib.exe")
269 self.rc = self.find_exe("rc.exe") # resource compiler
270 self.mc = self.find_exe("mc.exe") # message compiler
271 self.set_path_env_var('lib')
272 self.set_path_env_var('include')
273
274 # extend the MSVC path with the current path
275 try:
276 for p in os.environ['path'].split(';'):
277 self.__paths.append(p)
278 except KeyError:
279 pass
280 self.__paths = normalize_and_reduce_paths(self.__paths)
281 os.environ['path'] = ";".join(self.__paths)
282
283 self.preprocess_options = None
284 if self.__arch == "Intel":
285 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
286 '/DNDEBUG']
287 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
288 '/Z7', '/D_DEBUG']
289 else:
290 # Win64
291 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
292 '/DNDEBUG']
293 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
294 '/Z7', '/D_DEBUG']
295
296 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
297 if self.__version >= 7:
298 self.ldflags_shared_debug = [
299 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
300 ]
301 else:
302 self.ldflags_shared_debug = [
303 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
304 ]
305 self.ldflags_static = [ '/nologo']
306
307 self.initialized = True
308
309 # -- Worker methods ------------------------------------------------
310
311 def object_filenames(self,
312 source_filenames,
313 strip_dir=0,
314 output_dir=''):
315 # Copied from ccompiler.py, extended to return .res as 'object'-file
316 # for .rc input file
317 if output_dir is None: output_dir = ''
318 obj_names = []
319 for src_name in source_filenames:
320 (base, ext) = os.path.splitext (src_name)
321 base = os.path.splitdrive(base)[1] # Chop off the drive
322 base = base[os.path.isabs(base):] # If abs, chop off leading /
323 if ext not in self.src_extensions:
324 # Better to raise an exception instead of silently continuing
325 # and later complain about sources and targets having
326 # different lengths
327 raise CompileError ("Don't know how to compile %s" % src_name)
328 if strip_dir:
329 base = os.path.basename (base)
330 if ext in self._rc_extensions:
331 obj_names.append (os.path.join (output_dir,
332 base + self.res_extension))
333 elif ext in self._mc_extensions:
334 obj_names.append (os.path.join (output_dir,
335 base + self.res_extension))
336 else:
337 obj_names.append (os.path.join (output_dir,
338 base + self.obj_extension))
339 return obj_names
340
341
342 def compile(self, sources,
343 output_dir=None, macros=None, include_dirs=None, debug=0,
344 extra_preargs=None, extra_postargs=None, depends=None):
345
346 if not self.initialized:
347 self.initialize()
348 compile_info = self._setup_compile(output_dir, macros, include_dirs,
349 sources, depends, extra_postargs)
350 macros, objects, extra_postargs, pp_opts, build = compile_info
351
352 compile_opts = extra_preargs or []
353 compile_opts.append ('/c')
354 if debug:
355 compile_opts.extend(self.compile_options_debug)
356 else:
357 compile_opts.extend(self.compile_options)
358
359 for obj in objects:
360 try:
361 src, ext = build[obj]
362 except KeyError:
363 continue
364 if debug:
365 # pass the full pathname to MSVC in debug mode,
366 # this allows the debugger to find the source file
367 # without asking the user to browse for it
368 src = os.path.abspath(src)
369
370 if ext in self._c_extensions:
371 input_opt = "/Tc" + src
372 elif ext in self._cpp_extensions:
373 input_opt = "/Tp" + src
374 elif ext in self._rc_extensions:
375 # compile .RC to .RES file
376 input_opt = src
377 output_opt = "/fo" + obj
378 try:
379 self.spawn([self.rc] + pp_opts +
380 [output_opt] + [input_opt])
381 except DistutilsExecError as msg:
382 raise CompileError(msg)
383 continue
384 elif ext in self._mc_extensions:
385 # Compile .MC to .RC file to .RES file.
386 # * '-h dir' specifies the directory for the
387 # generated include file
388 # * '-r dir' specifies the target directory of the
389 # generated RC file and the binary message resource
390 # it includes
391 #
392 # For now (since there are no options to change this),
393 # we use the source-directory for the include file and
394 # the build directory for the RC file and message
395 # resources. This works at least for win32all.
396 h_dir = os.path.dirname(src)
397 rc_dir = os.path.dirname(obj)
398 try:
399 # first compile .MC to .RC and .H file
400 self.spawn([self.mc] +
401 ['-h', h_dir, '-r', rc_dir] + [src])
402 base, _ = os.path.splitext (os.path.basename (src))
403 rc_file = os.path.join (rc_dir, base + '.rc')
404 # then compile .RC to .RES file
405 self.spawn([self.rc] +
406 ["/fo" + obj] + [rc_file])
407
408 except DistutilsExecError as msg:
409 raise CompileError(msg)
410 continue
411 else:
412 # how to handle this file?
413 raise CompileError("Don't know how to compile %s to %s"
414 % (src, obj))
415
416 output_opt = "/Fo" + obj
417 try:
418 self.spawn([self.cc] + compile_opts + pp_opts +
419 [input_opt, output_opt] +
420 extra_postargs)
421 except DistutilsExecError as msg:
422 raise CompileError(msg)
423
424 return objects
425
426
427 def create_static_lib(self,
428 objects,
429 output_libname,
430 output_dir=None,
431 debug=0,
432 target_lang=None):
433
434 if not self.initialized:
435 self.initialize()
436 (objects, output_dir) = self._fix_object_args(objects, output_dir)
437 output_filename = self.library_filename(output_libname,
438 output_dir=output_dir)
439
440 if self._need_link(objects, output_filename):
441 lib_args = objects + ['/OUT:' + output_filename]
442 if debug:
443 pass # XXX what goes here?
444 try:
445 self.spawn([self.lib] + lib_args)
446 except DistutilsExecError as msg:
447 raise LibError(msg)
448 else:
449 log.debug("skipping %s (up-to-date)", output_filename)
450
451
452 def link(self,
453 target_desc,
454 objects,
455 output_filename,
456 output_dir=None,
457 libraries=None,
458 library_dirs=None,
459 runtime_library_dirs=None,
460 export_symbols=None,
461 debug=0,
462 extra_preargs=None,
463 extra_postargs=None,
464 build_temp=None,
465 target_lang=None):
466
467 if not self.initialized:
468 self.initialize()
469 (objects, output_dir) = self._fix_object_args(objects, output_dir)
470 fixed_args = self._fix_lib_args(libraries, library_dirs,
471 runtime_library_dirs)
472 (libraries, library_dirs, runtime_library_dirs) = fixed_args
473
474 if runtime_library_dirs:
475 self.warn ("I don't know what to do with 'runtime_library_dirs': "
476 + str (runtime_library_dirs))
477
478 lib_opts = gen_lib_options(self,
479 library_dirs, runtime_library_dirs,
480 libraries)
481 if output_dir is not None:
482 output_filename = os.path.join(output_dir, output_filename)
483
484 if self._need_link(objects, output_filename):
485 if target_desc == CCompiler.EXECUTABLE:
486 if debug:
487 ldflags = self.ldflags_shared_debug[1:]
488 else:
489 ldflags = self.ldflags_shared[1:]
490 else:
491 if debug:
492 ldflags = self.ldflags_shared_debug
493 else:
494 ldflags = self.ldflags_shared
495
496 export_opts = []
497 for sym in (export_symbols or []):
498 export_opts.append("/EXPORT:" + sym)
499
500 ld_args = (ldflags + lib_opts + export_opts +
501 objects + ['/OUT:' + output_filename])
502
503 # The MSVC linker generates .lib and .exp files, which cannot be
504 # suppressed by any linker switches. The .lib files may even be
505 # needed! Make sure they are generated in the temporary build
506 # directory. Since they have different names for debug and release
507 # builds, they can go into the same directory.
508 if export_symbols is not None:
509 (dll_name, dll_ext) = os.path.splitext(
510 os.path.basename(output_filename))
511 implib_file = os.path.join(
512 os.path.dirname(objects[0]),
513 self.library_filename(dll_name))
514 ld_args.append ('/IMPLIB:' + implib_file)
515
516 if extra_preargs:
517 ld_args[:0] = extra_preargs
518 if extra_postargs:
519 ld_args.extend(extra_postargs)
520
521 self.mkpath(os.path.dirname(output_filename))
522 try:
523 self.spawn([self.linker] + ld_args)
524 except DistutilsExecError as msg:
525 raise LinkError(msg)
526
527 else:
528 log.debug("skipping %s (up-to-date)", output_filename)
529
530
531 # -- Miscellaneous methods -----------------------------------------
532 # These are all used by the 'gen_lib_options() function, in
533 # ccompiler.py.
534
535 def library_dir_option(self, dir):
536 return "/LIBPATH:" + dir
537
538 def runtime_library_dir_option(self, dir):
539 raise DistutilsPlatformError(
540 "don't know how to set runtime library search path for MSVC++")
541
542 def library_option(self, lib):
543 return self.library_filename(lib)
544
545
546 def find_library_file(self, dirs, lib, debug=0):
547 # Prefer a debugging library if found (and requested), but deal
548 # with it if we don't have one.
549 if debug:
550 try_names = [lib + "_d", lib]
551 else:
552 try_names = [lib]
553 for dir in dirs:
554 for name in try_names:
555 libfile = os.path.join(dir, self.library_filename (name))
556 if os.path.exists(libfile):
557 return libfile
558 else:
559 # Oops, didn't find it in *any* of 'dirs'
560 return None
561
562 # Helper methods for using the MSVC registry settings
563
564 def find_exe(self, exe):
565 """Return path to an MSVC executable program.
566
567 Tries to find the program in several places: first, one of the
568 MSVC program search paths from the registry; next, the directories
569 in the PATH environment variable. If any of those work, return an
570 absolute path that is known to exist. If none of them work, just
571 return the original program name, 'exe'.
572 """
573 for p in self.__paths:
574 fn = os.path.join(os.path.abspath(p), exe)
575 if os.path.isfile(fn):
576 return fn
577
578 # didn't find it; try existing path
579 for p in os.environ['Path'].split(';'):
580 fn = os.path.join(os.path.abspath(p),exe)
581 if os.path.isfile(fn):
582 return fn
583
584 return exe
585
586 def get_msvc_paths(self, path, platform='x86'):
587 """Get a list of devstudio directories (include, lib or path).
588
589 Return a list of strings. The list will be empty if unable to
590 access the registry or appropriate registry keys not found.
591 """
592 if not _can_read_reg:
593 return []
594
595 path = path + " dirs"
596 if self.__version >= 7:
597 key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
598 % (self.__root, self.__version))
599 else:
600 key = (r"%s\6.0\Build System\Components\Platforms"
601 r"\Win32 (%s)\Directories" % (self.__root, platform))
602
603 for base in HKEYS:
604 d = read_values(base, key)
605 if d:
606 if self.__version >= 7:
607 return self.__macros.sub(d[path]).split(";")
608 else:
609 return d[path].split(";")
610 # MSVC 6 seems to create the registry entries we need only when
611 # the GUI is run.
612 if self.__version == 6:
613 for base in HKEYS:
614 if read_values(base, r"%s\6.0" % self.__root) is not None:
615 self.warn("It seems you have Visual Studio 6 installed, "
616 "but the expected registry settings are not present.\n"
617 "You must at least run the Visual Studio GUI once "
618 "so that these entries are created.")
619 break
620 return []
621
622 def set_path_env_var(self, name):
623 """Set environment variable 'name' to an MSVC path type value.
624
625 This is equivalent to a SET command prior to execution of spawned
626 commands.
627 """
628
629 if name == "lib":
630 p = self.get_msvc_paths("library")
631 else:
632 p = self.get_msvc_paths(name)
633 if p:
634 os.environ[name] = ';'.join(p)
635
636
637 if get_build_version() >= 8.0:
638 log.debug("Importing new compiler from distutils.msvc9compiler")
639 OldMSVCCompiler = MSVCCompiler
640 from distutils.msvc9compiler import MSVCCompiler
641 # get_build_architecture not really relevant now we support cross-compile
642 from distutils.msvc9compiler import MacroExpander