Latest distutils
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23252 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
"""distutils.msvccompiler
|
||||
|
||||
Contains MSVCCompiler, an implementation of the abstract CCompiler class
|
||||
for the Microsoft Visual Studio."""
|
||||
for the Microsoft Visual Studio.
|
||||
"""
|
||||
|
||||
# Written by Perry Stoll
|
||||
# hacked by Robin Becker and Thomas Heller to do a better job of
|
||||
@@ -12,7 +13,6 @@ for the Microsoft Visual Studio."""
|
||||
__revision__ = "$Id$"
|
||||
|
||||
import sys, os, string
|
||||
from types import *
|
||||
from distutils.errors import \
|
||||
DistutilsExecError, DistutilsPlatformError, \
|
||||
CompileError, LibError, LinkError
|
||||
@@ -45,129 +45,128 @@ except ImportError:
|
||||
RegError = win32api.error
|
||||
|
||||
except ImportError:
|
||||
log.info("Warning: Can't read registry to find the "
|
||||
"necessary compiler setting\n"
|
||||
"Make sure that Python modules _winreg, "
|
||||
"win32api or win32con are installed.")
|
||||
pass
|
||||
|
||||
if _can_read_reg:
|
||||
HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
|
||||
HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
|
||||
HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
|
||||
HKEY_USERS = hkey_mod.HKEY_USERS
|
||||
HKEYS = (hkey_mod.HKEY_USERS,
|
||||
hkey_mod.HKEY_CURRENT_USER,
|
||||
hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
hkey_mod.HKEY_CLASSES_ROOT)
|
||||
|
||||
def read_keys(base, key):
|
||||
"""Return list of registry keys."""
|
||||
|
||||
|
||||
def get_devstudio_versions ():
|
||||
"""Get list of devstudio versions from the Windows registry. Return a
|
||||
list of strings containing version numbers; the list will be
|
||||
empty if we were unable to access the registry (eg. couldn't import
|
||||
a registry-access module) or the appropriate registry keys weren't
|
||||
found."""
|
||||
|
||||
if not _can_read_reg:
|
||||
return []
|
||||
|
||||
K = 'Software\\Microsoft\\Devstudio'
|
||||
try:
|
||||
handle = RegOpenKeyEx(base, key)
|
||||
except RegError:
|
||||
return None
|
||||
L = []
|
||||
for base in (HKEY_CLASSES_ROOT,
|
||||
HKEY_LOCAL_MACHINE,
|
||||
HKEY_CURRENT_USER,
|
||||
HKEY_USERS):
|
||||
i = 0
|
||||
while 1:
|
||||
try:
|
||||
k = RegOpenKeyEx(base,K)
|
||||
i = 0
|
||||
while 1:
|
||||
try:
|
||||
p = RegEnumKey(k,i)
|
||||
if p[0] in '123456789' and p not in L:
|
||||
L.append(p)
|
||||
except RegError:
|
||||
break
|
||||
i = i + 1
|
||||
k = RegEnumKey(handle, i)
|
||||
except RegError:
|
||||
pass
|
||||
L.sort()
|
||||
L.reverse()
|
||||
break
|
||||
L.append(k)
|
||||
i = i + 1
|
||||
return L
|
||||
|
||||
# get_devstudio_versions ()
|
||||
def read_values(base, key):
|
||||
"""Return dict of registry keys and values.
|
||||
|
||||
|
||||
def get_msvc_paths (path, version='6.0', platform='x86'):
|
||||
"""Get a list of devstudio directories (include, lib or path). Return
|
||||
a list of strings; will be empty list if unable to access the
|
||||
registry or appropriate registry keys not found."""
|
||||
|
||||
if not _can_read_reg:
|
||||
return []
|
||||
|
||||
L = []
|
||||
if path=='lib':
|
||||
path= 'Library'
|
||||
path = string.upper(path + ' Dirs')
|
||||
K = ('Software\\Microsoft\\Devstudio\\%s\\' +
|
||||
'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
|
||||
(version,platform)
|
||||
for base in (HKEY_CLASSES_ROOT,
|
||||
HKEY_LOCAL_MACHINE,
|
||||
HKEY_CURRENT_USER,
|
||||
HKEY_USERS):
|
||||
All names are converted to lowercase.
|
||||
"""
|
||||
try:
|
||||
handle = RegOpenKeyEx(base, key)
|
||||
except RegError:
|
||||
return None
|
||||
d = {}
|
||||
i = 0
|
||||
while 1:
|
||||
try:
|
||||
k = RegOpenKeyEx(base,K)
|
||||
i = 0
|
||||
while 1:
|
||||
try:
|
||||
(p,v,t) = RegEnumValue(k,i)
|
||||
if string.upper(p) == path:
|
||||
V = string.split(v,';')
|
||||
for v in V:
|
||||
if hasattr(v, "encode"):
|
||||
try:
|
||||
v = v.encode("mbcs")
|
||||
except UnicodeError:
|
||||
pass
|
||||
if v == '' or v in L: continue
|
||||
L.append(v)
|
||||
break
|
||||
i = i + 1
|
||||
except RegError:
|
||||
break
|
||||
name, value, type = RegEnumValue(handle, i)
|
||||
except RegError:
|
||||
break
|
||||
name = name.lower()
|
||||
d[convert_mbcs(name)] = convert_mbcs(value)
|
||||
i = i + 1
|
||||
return d
|
||||
|
||||
def convert_mbcs(s):
|
||||
enc = getattr(s, "encode", None)
|
||||
if enc is not None:
|
||||
try:
|
||||
s = enc("mbcs")
|
||||
except UnicodeError:
|
||||
pass
|
||||
return L
|
||||
return s
|
||||
|
||||
# get_msvc_paths()
|
||||
class MacroExpander:
|
||||
|
||||
def __init__(self, version):
|
||||
self.macros = {}
|
||||
self.load_macros(version)
|
||||
|
||||
def find_exe (exe, version_number):
|
||||
"""Try to find an MSVC executable program 'exe' (from version
|
||||
'version_number' of MSVC) in several places: first, one of the MSVC
|
||||
program search paths from the registry; next, the directories in the
|
||||
PATH environment variable. If any of those work, return an absolute
|
||||
path that is known to exist. If none of them work, just return the
|
||||
original program name, 'exe'."""
|
||||
def set_macro(self, macro, path, key):
|
||||
for base in HKEYS:
|
||||
d = read_values(base, path)
|
||||
if d:
|
||||
self.macros["$(%s)" % macro] = d[key]
|
||||
break
|
||||
|
||||
def load_macros(self, version):
|
||||
vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
|
||||
self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
|
||||
self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
|
||||
net = r"Software\Microsoft\.NETFramework"
|
||||
self.set_macro("FrameworkDir", net, "installroot")
|
||||
if version > 7.0:
|
||||
self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
|
||||
else:
|
||||
self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
|
||||
|
||||
for p in get_msvc_paths ('path', version_number):
|
||||
fn = os.path.join (os.path.abspath(p), exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
p = r"Software\Microsoft\NET Framework Setup\Product"
|
||||
for base in HKEYS:
|
||||
try:
|
||||
h = RegOpenKeyEx(base, p)
|
||||
except RegError:
|
||||
continue
|
||||
key = RegEnumKey(h, 0)
|
||||
d = read_values(base, r"%s\%s" % (p, key))
|
||||
self.macros["$(FrameworkVersion)"] = d["version"]
|
||||
|
||||
# didn't find it; try existing path
|
||||
for p in string.split (os.environ['Path'],';'):
|
||||
fn = os.path.join(os.path.abspath(p),exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
def sub(self, s):
|
||||
for k, v in self.macros.items():
|
||||
s = string.replace(s, k, v)
|
||||
return s
|
||||
|
||||
return exe # last desperate hope
|
||||
def get_build_version():
|
||||
"""Return the version of MSVC that was used to build Python.
|
||||
|
||||
For Python 2.3 and up, the version number is included in
|
||||
sys.version. For earlier versions, assume the compiler is MSVC 6.
|
||||
"""
|
||||
|
||||
def set_path_env_var (name, version_number):
|
||||
"""Set environment variable 'name' to an MSVC path type value obtained
|
||||
from 'get_msvc_paths()'. This is equivalent to a SET command prior
|
||||
to execution of spawned commands."""
|
||||
|
||||
p = get_msvc_paths (name, version_number)
|
||||
if p:
|
||||
os.environ[name] = string.join (p,';')
|
||||
|
||||
prefix = "MSC v."
|
||||
i = string.find(sys.version, prefix)
|
||||
if i == -1:
|
||||
return 6
|
||||
i = i + len(prefix)
|
||||
s, rest = sys.version[i:].split(" ", 1)
|
||||
majorVersion = int(s[:-2]) - 6
|
||||
minorVersion = int(s[2:3]) / 10.0
|
||||
# I don't think paths are affected by minor version in version 6
|
||||
if majorVersion == 6:
|
||||
minorVersion = 0
|
||||
if majorVersion >= 6:
|
||||
return majorVersion + minorVersion
|
||||
# else we don't know what version of the compiler this is
|
||||
return None
|
||||
|
||||
|
||||
class MSVCCompiler (CCompiler) :
|
||||
"""Concrete class that implements an interface to Microsoft Visual C++,
|
||||
@@ -199,39 +198,37 @@ class MSVCCompiler (CCompiler) :
|
||||
static_lib_format = shared_lib_format = '%s%s'
|
||||
exe_extension = '.exe'
|
||||
|
||||
|
||||
def __init__ (self,
|
||||
verbose=0,
|
||||
dry_run=0,
|
||||
force=0):
|
||||
|
||||
def __init__ (self, verbose=0, dry_run=0, force=0):
|
||||
CCompiler.__init__ (self, verbose, dry_run, force)
|
||||
versions = get_devstudio_versions ()
|
||||
|
||||
if versions:
|
||||
version = versions[0] # highest version
|
||||
|
||||
self.cc = find_exe("cl.exe", version)
|
||||
self.linker = find_exe("link.exe", version)
|
||||
self.lib = find_exe("lib.exe", version)
|
||||
self.rc = find_exe("rc.exe", version) # resource compiler
|
||||
self.mc = find_exe("mc.exe", version) # message compiler
|
||||
set_path_env_var ('lib', version)
|
||||
set_path_env_var ('include', version)
|
||||
path=get_msvc_paths('path', version)
|
||||
try:
|
||||
for p in string.split(os.environ['path'],';'):
|
||||
path.append(p)
|
||||
except KeyError:
|
||||
pass
|
||||
os.environ['path'] = string.join(path,';')
|
||||
self.__version = get_build_version()
|
||||
if self.__version >= 7:
|
||||
self.__root = r"Software\Microsoft\VisualStudio"
|
||||
self.__macros = MacroExpander(self.__version)
|
||||
else:
|
||||
# devstudio not found in the registry
|
||||
self.cc = "cl.exe"
|
||||
self.linker = "link.exe"
|
||||
self.lib = "lib.exe"
|
||||
self.rc = "rc.exe"
|
||||
self.mc = "mc.exe"
|
||||
self.__root = r"Software\Microsoft\Devstudio"
|
||||
self.__paths = self.get_msvc_paths("path")
|
||||
|
||||
if len (self.__paths) == 0:
|
||||
raise DistutilsPlatformError, \
|
||||
("Python was built with version %s of Visual Studio, "
|
||||
"and extensions need to be built with the same "
|
||||
"version of the compiler, but it isn't installed." % self.__version)
|
||||
|
||||
self.cc = self.find_exe("cl.exe")
|
||||
self.linker = self.find_exe("link.exe")
|
||||
self.lib = self.find_exe("lib.exe")
|
||||
self.rc = self.find_exe("rc.exe") # resource compiler
|
||||
self.mc = self.find_exe("mc.exe") # message compiler
|
||||
self.set_path_env_var('lib')
|
||||
self.set_path_env_var('include')
|
||||
|
||||
# extend the MSVC path with the current path
|
||||
try:
|
||||
for p in string.split(os.environ['path'], ';'):
|
||||
self.__paths.append(p)
|
||||
except KeyError:
|
||||
pass
|
||||
os.environ['path'] = string.join(self.__paths, ';')
|
||||
|
||||
self.preprocess_options = None
|
||||
self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
|
||||
@@ -500,4 +497,69 @@ class MSVCCompiler (CCompiler) :
|
||||
|
||||
# find_library_file ()
|
||||
|
||||
# class MSVCCompiler
|
||||
# Helper methods for using the MSVC registry settings
|
||||
|
||||
def find_exe(self, exe):
|
||||
"""Return path to an MSVC executable program.
|
||||
|
||||
Tries to find the program in several places: first, one of the
|
||||
MSVC program search paths from the registry; next, the directories
|
||||
in the PATH environment variable. If any of those work, return an
|
||||
absolute path that is known to exist. If none of them work, just
|
||||
return the original program name, 'exe'.
|
||||
"""
|
||||
|
||||
for p in self.__paths:
|
||||
fn = os.path.join(os.path.abspath(p), exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
|
||||
# didn't find it; try existing path
|
||||
for p in string.split(os.environ['Path'],';'):
|
||||
fn = os.path.join(os.path.abspath(p),exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
|
||||
return exe
|
||||
|
||||
def get_msvc_paths(self, path, platform='x86'):
|
||||
"""Get a list of devstudio directories (include, lib or path).
|
||||
|
||||
Return a list of strings. The list will be empty if unable to
|
||||
access the registry or appropriate registry keys not found.
|
||||
"""
|
||||
|
||||
if not _can_read_reg:
|
||||
return []
|
||||
|
||||
path = path + " dirs"
|
||||
if self.__version >= 7:
|
||||
key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
|
||||
% (self.__root, self.__version))
|
||||
else:
|
||||
key = (r"%s\6.0\Build System\Components\Platforms"
|
||||
r"\Win32 (%s)\Directories" % (self.__root, platform))
|
||||
|
||||
for base in HKEYS:
|
||||
d = read_values(base, key)
|
||||
if d:
|
||||
if self.__version >= 7:
|
||||
return string.split(self.__macros.sub(d[path]), ";")
|
||||
else:
|
||||
return string.split(d[path], ";")
|
||||
return []
|
||||
|
||||
def set_path_env_var(self, name):
|
||||
"""Set environment variable 'name' to an MSVC path type value.
|
||||
|
||||
This is equivalent to a SET command prior to execution of spawned
|
||||
commands.
|
||||
"""
|
||||
|
||||
if name == "lib":
|
||||
p = self.get_msvc_paths("library")
|
||||
else:
|
||||
p = self.get_msvc_paths(name)
|
||||
if p:
|
||||
os.environ[name] = string.join(p, ';')
|
||||
|
||||
|
Reference in New Issue
Block a user