]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/distutils/msvc9compiler.py
6c03974df8033fb3b2e8fd3512d2d5eb603f4041
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.
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
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
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 NATIVE_WIN64
= (sys
.platform
== 'win32' and sys
.maxsize
> 2**32)
42 # Visual C++ is a 32-bit application, so we need to look in
43 # the corresponding registry branch, if we're running a
44 # 64-bit Python on Win64
45 VS_BASE
= r
"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
46 VSEXPRESS_BASE
= r
"Software\Wow6432Node\Microsoft\VCExpress\%0.1f"
47 WINSDK_BASE
= r
"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"
48 NET_BASE
= r
"Software\Wow6432Node\Microsoft\.NETFramework"
50 VS_BASE
= r
"Software\Microsoft\VisualStudio\%0.1f"
51 VSEXPRESS_BASE
= r
"Software\Microsoft\VCExpress\%0.1f"
52 WINSDK_BASE
= r
"Software\Microsoft\Microsoft SDKs\Windows"
53 NET_BASE
= r
"Software\Microsoft\.NETFramework"
55 # A map keyed by get_platform() return values to values accepted by
56 # 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
57 # the param to cross-compile on x86 targetting amd64.)
60 'win-amd64' : 'amd64',
65 """Helper class to read values from the registry
68 def get_value(cls
, path
, key
):
70 d
= cls
.read_values(base
, path
)
74 get_value
= classmethod(get_value
)
76 def read_keys(cls
, base
, key
):
77 """Return list of registry keys."""
79 handle
= RegOpenKeyEx(base
, key
)
86 k
= RegEnumKey(handle
, i
)
92 read_keys
= classmethod(read_keys
)
94 def read_values(cls
, base
, key
):
95 """Return dict of registry keys and values.
97 All names are converted to lowercase.
100 handle
= RegOpenKeyEx(base
, key
)
107 name
, value
, type = RegEnumValue(handle
, i
)
111 d
[cls
.convert_mbcs(name
)] = cls
.convert_mbcs(value
)
114 read_values
= classmethod(read_values
)
117 dec
= getattr(s
, "decode", None)
124 convert_mbcs
= staticmethod(convert_mbcs
)
128 def __init__(self
, version
):
130 self
.vsbase
= VS_BASE
% version
131 self
.load_macros(version
)
133 def set_macro(self
, macro
, path
, key
):
134 self
.macros
["$(%s)" % macro
] = Reg
.get_value(path
, key
)
136 def load_macros(self
, version
):
137 self
.set_macro("VCInstallDir", self
.vsbase
+ r
"\Setup\VC", "productdir")
138 self
.set_macro("VSInstallDir", self
.vsbase
+ r
"\Setup\VS", "productdir")
139 self
.set_macro("FrameworkDir", NET_BASE
, "installroot")
142 self
.set_macro("FrameworkSDKDir", NET_BASE
,
143 "sdkinstallrootv2.0")
145 raise KeyError("sdkinstallrootv2.0")
147 raise DistutilsPlatformError(
148 """Python was built with Visual Studio 2008;
149 extensions must be built with a compiler than can generate compatible binaries.
150 Visual Studio 2008 was not found on this system. If you have Cygwin installed,
151 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
154 self
.set_macro("FrameworkVersion", self
.vsbase
, "clr version")
155 self
.set_macro("WindowsSdkDir", WINSDK_BASE
, "currentinstallfolder")
157 p
= r
"Software\Microsoft\NET Framework Setup\Product"
160 h
= RegOpenKeyEx(base
, p
)
163 key
= RegEnumKey(h
, 0)
164 d
= Reg
.get_value(base
, r
"%s\%s" % (p
, key
))
165 self
.macros
["$(FrameworkVersion)"] = d
["version"]
168 for k
, v
in self
.macros
.items():
172 def get_build_version():
173 """Return the version of MSVC that was used to build Python.
175 For Python 2.3 and up, the version number is included in
176 sys.version. For earlier versions, assume the compiler is MSVC 6.
179 i
= sys
.version
.find(prefix
)
183 s
, rest
= sys
.version
[i
:].split(" ", 1)
184 majorVersion
= int(s
[:-2]) - 6
185 minorVersion
= int(s
[2:3]) / 10.0
186 # I don't think paths are affected by minor version in version 6
187 if majorVersion
== 6:
189 if majorVersion
>= 6:
190 return majorVersion
+ minorVersion
191 # else we don't know what version of the compiler this is
194 def normalize_and_reduce_paths(paths
):
195 """Return a list of normalized paths with duplicates removed.
197 The current order of paths is maintained.
199 # Paths are normalized so things like: /a and /a/ aren't both preserved.
202 np
= os
.path
.normpath(p
)
203 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
204 if np
not in reduced_paths
:
205 reduced_paths
.append(np
)
208 def removeDuplicates(variable
):
209 """Remove duplicate values of an environment variable.
211 oldList
= variable
.split(os
.pathsep
)
216 newVariable
= os
.pathsep
.join(newList
)
219 def find_vcvarsall(version
):
220 """Find the vcvarsall.bat file
222 At first it tries to find the productdir of VS 2008 in the registry. If
223 that fails it falls back to the VS90COMNTOOLS env var.
225 vsbase
= VS_BASE
% version
227 productdir
= Reg
.get_value(r
"%s\Setup\VC" % vsbase
,
232 # trying Express edition
233 if productdir
is None:
234 vsbase
= VSEXPRESS_BASE
% version
236 productdir
= Reg
.get_value(r
"%s\Setup\VC" % vsbase
,
240 log
.debug("Unable to find productdir in registry")
242 if not productdir
or not os
.path
.isdir(productdir
):
243 toolskey
= "VS%0.f0COMNTOOLS" % version
244 toolsdir
= os
.environ
.get(toolskey
, None)
246 if toolsdir
and os
.path
.isdir(toolsdir
):
247 productdir
= os
.path
.join(toolsdir
, os
.pardir
, os
.pardir
, "VC")
248 productdir
= os
.path
.abspath(productdir
)
249 if not os
.path
.isdir(productdir
):
250 log
.debug("%s is not a valid directory" % productdir
)
253 log
.debug("Env var %s is not set or invalid" % toolskey
)
255 log
.debug("No productdir found")
257 vcvarsall
= os
.path
.join(productdir
, "vcvarsall.bat")
258 if os
.path
.isfile(vcvarsall
):
260 log
.debug("Unable to find vcvarsall.bat")
263 def query_vcvarsall(version
, arch
="x86"):
264 """Launch vcvarsall.bat and read the settings from its environment
266 vcvarsall
= find_vcvarsall(version
)
267 interesting
= set(("include", "lib", "libpath", "path"))
270 if vcvarsall
is None:
271 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
272 log
.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch
, version
)
273 popen
= subprocess
.Popen('"%s" %s & set' % (vcvarsall
, arch
),
274 stdout
=subprocess
.PIPE
,
275 stderr
=subprocess
.PIPE
)
277 stdout
, stderr
= popen
.communicate()
278 if popen
.wait() != 0:
279 raise DistutilsPlatformError(stderr
.decode("mbcs"))
281 stdout
= stdout
.decode("mbcs")
282 for line
in stdout
.split("\n"):
283 line
= Reg
.convert_mbcs(line
)
287 key
, value
= line
.split('=', 1)
289 if key
in interesting
:
290 if value
.endswith(os
.pathsep
):
292 result
[key
] = removeDuplicates(value
)
298 if len(result
) != len(interesting
):
299 raise ValueError(str(list(result
.keys())))
304 VERSION
= get_build_version()
306 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION
)
307 # MACROS = MacroExpander(VERSION)
309 class MSVCCompiler(CCompiler
) :
310 """Concrete class that implements an interface to Microsoft Visual C++,
311 as defined by the CCompiler abstract class."""
313 compiler_type
= 'msvc'
315 # Just set this so CCompiler's constructor doesn't barf. We currently
316 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
317 # as it really isn't necessary for this sort of single-compiler class.
318 # Would be nice to have a consistent interface with UnixCCompiler,
319 # though, so it's worth thinking about.
322 # Private class data (need to distinguish C from C++ source for compiler)
323 _c_extensions
= ['.c']
324 _cpp_extensions
= ['.cc', '.cpp', '.cxx']
325 _rc_extensions
= ['.rc']
326 _mc_extensions
= ['.mc']
328 # Needed for the filename generation methods provided by the
329 # base class, CCompiler.
330 src_extensions
= (_c_extensions
+ _cpp_extensions
+
331 _rc_extensions
+ _mc_extensions
)
332 res_extension
= '.res'
333 obj_extension
= '.obj'
334 static_lib_extension
= '.lib'
335 shared_lib_extension
= '.dll'
336 static_lib_format
= shared_lib_format
= '%s%s'
337 exe_extension
= '.exe'
339 def __init__(self
, verbose
=0, dry_run
=0, force
=0):
340 CCompiler
.__init
__ (self
, verbose
, dry_run
, force
)
341 self
.__version
= VERSION
342 self
.__root
= r
"Software\Microsoft\VisualStudio"
343 # self.__macros = MACROS
345 # target platform (.plat_name is consistent with 'bdist')
346 self
.plat_name
= None
347 self
.__arch
= None # deprecated name
348 self
.initialized
= False
350 def initialize(self
, plat_name
=None):
351 # multi-init means we would need to check platform same each time...
352 assert not self
.initialized
, "don't init multiple times"
353 if plat_name
is None:
354 plat_name
= get_platform()
355 # sanity check for platforms to prevent obscure errors later.
356 ok_plats
= 'win32', 'win-amd64', 'win-ia64'
357 if plat_name
not in ok_plats
:
358 raise DistutilsPlatformError("--plat-name must be one of %s" %
361 if "DISTUTILS_USE_SDK" in os
.environ
and "MSSdk" in os
.environ
and self
.find_exe("cl.exe"):
362 # Assume that the SDK set up everything alright; don't try to be
365 self
.linker
= "link.exe"
370 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
371 # to cross compile, you use 'x86_amd64'.
372 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
373 # compile use 'x86' (ie, it runs the x86 compiler directly)
374 # No idea how itanium handles this, if at all.
375 if plat_name
== get_platform() or plat_name
== 'win32':
376 # native build or cross-compile to win32
377 plat_spec
= PLAT_TO_VCVARS
[plat_name
]
379 # cross compile from win32 -> some 64bit
380 plat_spec
= PLAT_TO_VCVARS
[get_platform()] + '_' + \
381 PLAT_TO_VCVARS
[plat_name
]
383 vc_env
= query_vcvarsall(VERSION
, plat_spec
)
385 # take care to only use strings in the environment.
386 self
.__paths
= vc_env
['path'].encode('mbcs').split(os
.pathsep
)
387 os
.environ
['lib'] = vc_env
['lib'].encode('mbcs')
388 os
.environ
['include'] = vc_env
['include'].encode('mbcs')
390 if len(self
.__paths
) == 0:
391 raise DistutilsPlatformError("Python was built with %s, "
392 "and extensions need to be built with the same "
393 "version of the compiler, but it isn't installed."
396 self
.cc
= self
.find_exe("cl.exe")
397 self
.linker
= self
.find_exe("link.exe")
398 self
.lib
= self
.find_exe("lib.exe")
399 self
.rc
= self
.find_exe("rc.exe") # resource compiler
400 self
.mc
= self
.find_exe("mc.exe") # message compiler
401 #self.set_path_env_var('lib')
402 #self.set_path_env_var('include')
404 # extend the MSVC path with the current path
406 for p
in os
.environ
['path'].split(';'):
407 self
.__paths
.append(p
)
410 self
.__paths
= normalize_and_reduce_paths(self
.__paths
)
411 os
.environ
['path'] = ";".join(self
.__paths
)
413 self
.preprocess_options
= None
414 if self
.__arch
== "x86":
415 self
.compile_options
= [ '/nologo', '/Ox', '/MD', '/W3',
417 self
.compile_options_debug
= ['/nologo', '/Od', '/MDd', '/W3',
421 self
.compile_options
= [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
423 self
.compile_options_debug
= ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
426 self
.ldflags_shared
= ['/DLL', '/nologo', '/INCREMENTAL:NO']
427 if self
.__version
>= 7:
428 self
.ldflags_shared_debug
= [
429 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
431 self
.ldflags_static
= [ '/nologo']
433 self
.initialized
= True
435 # -- Worker methods ------------------------------------------------
437 def object_filenames(self
,
441 # Copied from ccompiler.py, extended to return .res as 'object'-file
443 if output_dir
is None: output_dir
= ''
445 for src_name
in source_filenames
:
446 (base
, ext
) = os
.path
.splitext (src_name
)
447 base
= os
.path
.splitdrive(base
)[1] # Chop off the drive
448 base
= base
[os
.path
.isabs(base
):] # If abs, chop off leading /
449 if ext
not in self
.src_extensions
:
450 # Better to raise an exception instead of silently continuing
451 # and later complain about sources and targets having
453 raise CompileError ("Don't know how to compile %s" % src_name
)
455 base
= os
.path
.basename (base
)
456 if ext
in self
._rc
_extensions
:
457 obj_names
.append (os
.path
.join (output_dir
,
458 base
+ self
.res_extension
))
459 elif ext
in self
._mc
_extensions
:
460 obj_names
.append (os
.path
.join (output_dir
,
461 base
+ self
.res_extension
))
463 obj_names
.append (os
.path
.join (output_dir
,
464 base
+ self
.obj_extension
))
468 def compile(self
, sources
,
469 output_dir
=None, macros
=None, include_dirs
=None, debug
=0,
470 extra_preargs
=None, extra_postargs
=None, depends
=None):
472 if not self
.initialized
:
474 compile_info
= self
._setup
_compile
(output_dir
, macros
, include_dirs
,
475 sources
, depends
, extra_postargs
)
476 macros
, objects
, extra_postargs
, pp_opts
, build
= compile_info
478 compile_opts
= extra_preargs
or []
479 compile_opts
.append ('/c')
481 compile_opts
.extend(self
.compile_options_debug
)
483 compile_opts
.extend(self
.compile_options
)
487 src
, ext
= build
[obj
]
491 # pass the full pathname to MSVC in debug mode,
492 # this allows the debugger to find the source file
493 # without asking the user to browse for it
494 src
= os
.path
.abspath(src
)
496 if ext
in self
._c
_extensions
:
497 input_opt
= "/Tc" + src
498 elif ext
in self
._cpp
_extensions
:
499 input_opt
= "/Tp" + src
500 elif ext
in self
._rc
_extensions
:
501 # compile .RC to .RES file
503 output_opt
= "/fo" + obj
505 self
.spawn([self
.rc
] + pp_opts
+
506 [output_opt
] + [input_opt
])
507 except DistutilsExecError
, msg
:
508 raise CompileError(msg
)
510 elif ext
in self
._mc
_extensions
:
511 # Compile .MC to .RC file to .RES file.
512 # * '-h dir' specifies the directory for the
513 # generated include file
514 # * '-r dir' specifies the target directory of the
515 # generated RC file and the binary message resource
518 # For now (since there are no options to change this),
519 # we use the source-directory for the include file and
520 # the build directory for the RC file and message
521 # resources. This works at least for win32all.
522 h_dir
= os
.path
.dirname(src
)
523 rc_dir
= os
.path
.dirname(obj
)
525 # first compile .MC to .RC and .H file
526 self
.spawn([self
.mc
] +
527 ['-h', h_dir
, '-r', rc_dir
] + [src
])
528 base
, _
= os
.path
.splitext (os
.path
.basename (src
))
529 rc_file
= os
.path
.join (rc_dir
, base
+ '.rc')
530 # then compile .RC to .RES file
531 self
.spawn([self
.rc
] +
532 ["/fo" + obj
] + [rc_file
])
534 except DistutilsExecError
, msg
:
535 raise CompileError(msg
)
538 # how to handle this file?
539 raise CompileError("Don't know how to compile %s to %s"
542 output_opt
= "/Fo" + obj
544 self
.spawn([self
.cc
] + compile_opts
+ pp_opts
+
545 [input_opt
, output_opt
] +
547 except DistutilsExecError
, msg
:
548 raise CompileError(msg
)
553 def create_static_lib(self
,
560 if not self
.initialized
:
562 (objects
, output_dir
) = self
._fix
_object
_args
(objects
, output_dir
)
563 output_filename
= self
.library_filename(output_libname
,
564 output_dir
=output_dir
)
566 if self
._need
_link
(objects
, output_filename
):
567 lib_args
= objects
+ ['/OUT:' + output_filename
]
569 pass # XXX what goes here?
571 self
.spawn([self
.lib
] + lib_args
)
572 except DistutilsExecError
, msg
:
575 log
.debug("skipping %s (up-to-date)", output_filename
)
585 runtime_library_dirs
=None,
593 if not self
.initialized
:
595 (objects
, output_dir
) = self
._fix
_object
_args
(objects
, output_dir
)
596 fixed_args
= self
._fix
_lib
_args
(libraries
, library_dirs
,
597 runtime_library_dirs
)
598 (libraries
, library_dirs
, runtime_library_dirs
) = fixed_args
600 if runtime_library_dirs
:
601 self
.warn ("I don't know what to do with 'runtime_library_dirs': "
602 + str (runtime_library_dirs
))
604 lib_opts
= gen_lib_options(self
,
605 library_dirs
, runtime_library_dirs
,
607 if output_dir
is not None:
608 output_filename
= os
.path
.join(output_dir
, output_filename
)
610 if self
._need
_link
(objects
, output_filename
):
611 if target_desc
== CCompiler
.EXECUTABLE
:
613 ldflags
= self
.ldflags_shared_debug
[1:]
615 ldflags
= self
.ldflags_shared
[1:]
618 ldflags
= self
.ldflags_shared_debug
620 ldflags
= self
.ldflags_shared
623 for sym
in (export_symbols
or []):
624 export_opts
.append("/EXPORT:" + sym
)
626 ld_args
= (ldflags
+ lib_opts
+ export_opts
+
627 objects
+ ['/OUT:' + output_filename
])
629 # The MSVC linker generates .lib and .exp files, which cannot be
630 # suppressed by any linker switches. The .lib files may even be
631 # needed! Make sure they are generated in the temporary build
632 # directory. Since they have different names for debug and release
633 # builds, they can go into the same directory.
634 build_temp
= os
.path
.dirname(objects
[0])
635 if export_symbols
is not None:
636 (dll_name
, dll_ext
) = os
.path
.splitext(
637 os
.path
.basename(output_filename
))
638 implib_file
= os
.path
.join(
640 self
.library_filename(dll_name
))
641 ld_args
.append ('/IMPLIB:' + implib_file
)
643 # Embedded manifests are recommended - see MSDN article titled
644 # "How to: Embed a Manifest Inside a C/C++ Application"
645 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
646 # Ask the linker to generate the manifest in the temp dir, so
647 # we can embed it later.
648 temp_manifest
= os
.path
.join(
650 os
.path
.basename(output_filename
) + ".manifest")
651 ld_args
.append('/MANIFESTFILE:' + temp_manifest
)
654 ld_args
[:0] = extra_preargs
656 ld_args
.extend(extra_postargs
)
658 self
.mkpath(os
.path
.dirname(output_filename
))
660 self
.spawn([self
.linker
] + ld_args
)
661 except DistutilsExecError
, msg
:
665 # XXX - this is somewhat fragile - if mt.exe fails, distutils
666 # will still consider the DLL up-to-date, but it will not have a
667 # manifest. Maybe we should link to a temp file? OTOH, that
668 # implies a build environment error that shouldn't go undetected.
669 if target_desc
== CCompiler
.EXECUTABLE
:
673 self
._remove
_visual
_c
_ref
(temp_manifest
)
674 out_arg
= '-outputresource:%s;%s' % (output_filename
, mfid
)
676 self
.spawn(['mt.exe', '-nologo', '-manifest',
677 temp_manifest
, out_arg
])
678 except DistutilsExecError
, msg
:
681 log
.debug("skipping %s (up-to-date)", output_filename
)
683 def _remove_visual_c_ref(self
, manifest_file
):
685 # Remove references to the Visual C runtime, so they will
686 # fall through to the Visual C dependency of Python.exe.
687 # This way, when installed for a restricted user (e.g.
688 # runtimes are not in WinSxS folder, but in Python's own
689 # folder), the runtimes do not need to be in every folder
691 manifest_f
= open(manifest_file
)
693 manifest_buf
= manifest_f
.read()
696 pattern
= re
.compile(
697 r
"""<assemblyIdentity.*?name=("|')Microsoft\."""\
698 r
"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
700 manifest_buf
= re
.sub(pattern
, "", manifest_buf
)
701 pattern
= "<dependentAssembly>\s*</dependentAssembly>"
702 manifest_buf
= re
.sub(pattern
, "", manifest_buf
)
703 manifest_f
= open(manifest_file
, 'w')
705 manifest_f
.write(manifest_buf
)
711 # -- Miscellaneous methods -----------------------------------------
712 # These are all used by the 'gen_lib_options() function, in
715 def library_dir_option(self
, dir):
716 return "/LIBPATH:" + dir
718 def runtime_library_dir_option(self
, dir):
719 raise DistutilsPlatformError(
720 "don't know how to set runtime library search path for MSVC++")
722 def library_option(self
, lib
):
723 return self
.library_filename(lib
)
726 def find_library_file(self
, dirs
, lib
, debug
=0):
727 # Prefer a debugging library if found (and requested), but deal
728 # with it if we don't have one.
730 try_names
= [lib
+ "_d", lib
]
734 for name
in try_names
:
735 libfile
= os
.path
.join(dir, self
.library_filename (name
))
736 if os
.path
.exists(libfile
):
739 # Oops, didn't find it in *any* of 'dirs'
742 # Helper methods for using the MSVC registry settings
744 def find_exe(self
, exe
):
745 """Return path to an MSVC executable program.
747 Tries to find the program in several places: first, one of the
748 MSVC program search paths from the registry; next, the directories
749 in the PATH environment variable. If any of those work, return an
750 absolute path that is known to exist. If none of them work, just
751 return the original program name, 'exe'.
753 for p
in self
.__paths
:
754 fn
= os
.path
.join(os
.path
.abspath(p
), exe
)
755 if os
.path
.isfile(fn
):
758 # didn't find it; try existing path
759 for p
in os
.environ
['Path'].split(';'):
760 fn
= os
.path
.join(os
.path
.abspath(p
),exe
)
761 if os
.path
.isfile(fn
):