http://scons.tigris.org/issues/show_bug.cgi?id=2345
[scons.git] / src / engine / SCons / Tool / msvs.py
index e17dcfd894ae473952b3f21dd0900fe3281e2ca2..304c35ea863bc78f9dd3eb40c106076837156ec1 100644 (file)
@@ -30,15 +30,19 @@ selection method.
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #
+from __future__ import generators  ### KEEP FOR COMPATIBILITY FIXERS
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import SCons.compat
+
 import base64
 import base64
-import md5
-import os.path
+import hashlib
+import ntpath
+import os
+# compat layer imports "cPickle" for us if it's available.
 import pickle
 import re
 import pickle
 import re
-import string
 import sys
 
 import SCons.Builder
 import sys
 
 import SCons.Builder
@@ -48,28 +52,18 @@ import SCons.Script.SConscript
 import SCons.Util
 import SCons.Warnings
 
 import SCons.Util
 import SCons.Warnings
 
+from MSCommon import msvc_exists, msvc_setup_env_once
+from SCons.Defaults import processDefines
+
 ##############################################################################
 # Below here are the classes and functions for generation of
 # DSP/DSW/SLN/VCPROJ files.
 ##############################################################################
 
 ##############################################################################
 # Below here are the classes and functions for generation of
 # DSP/DSW/SLN/VCPROJ files.
 ##############################################################################
 
-def _hexdigest(s):
-    """Return a string as a string of hex characters.
-    """
-    # NOTE:  This routine is a method in the Python 2.0 interface
-    # of the native md5 module, but we want SCons to operate all
-    # the way back to at least Python 1.5.2, which doesn't have it.
-    h = string.hexdigits
-    r = ''
-    for c in s:
-        i = ord(c)
-        r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
-    return r
-
 def xmlify(s):
 def xmlify(s):
-    s = string.replace(s, "&", "&") # do this first
-    s = string.replace(s, "'", "'")
-    s = string.replace(s, '"', """)
+    s = s.replace("&", "&") # do this first
+    s = s.replace("'", "'")
+    s = s.replace('"', """)
     return s
 
 external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}'
     return s
 
 external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}'
@@ -79,7 +73,12 @@ def _generateGUID(slnfile, name):
     based on the MD5 signatures of the sln filename plus the name of
     the project.  It basically just needs to be unique, and not
     change with each invocation."""
     based on the MD5 signatures of the sln filename plus the name of
     the project.  It basically just needs to be unique, and not
     change with each invocation."""
-    solution = _hexdigest(md5.new(str(slnfile)+str(name)).digest()).upper()
+    m = hashlib.md5()
+    # Normalize the slnfile path to a Windows path (\ separators) so
+    # the generated file has a consistent GUID even if we generate
+    # it on a non-Windows platform.
+    m.update(ntpath.normpath(str(slnfile)) + str(name))
+    solution = m.hexdigest().upper()
     # convert most of the signature to GUID form (discard the rest)
     solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}"
     return solution
     # convert most of the signature to GUID form (discard the rest)
     solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}"
     return solution
@@ -105,7 +104,7 @@ def msvs_parse_version(s):
 # which works regardless of how we were invoked.
 def getExecScriptMain(env, xml=None):
     scons_home = env.get('SCONS_HOME')
 # which works regardless of how we were invoked.
 def getExecScriptMain(env, xml=None):
     scons_home = env.get('SCONS_HOME')
-    if not scons_home and os.environ.has_key('SCONS_LIB_DIR'):
+    if not scons_home and 'SCONS_LIB_DIR' in os.environ:
         scons_home = os.environ['SCONS_LIB_DIR']
     if scons_home:
         exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home
         scons_home = os.environ['SCONS_LIB_DIR']
     if scons_home:
         exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home
@@ -150,7 +149,7 @@ def makeHierarchy(sources):
         if len(path):
             dict = hierarchy
             for part in path[:-1]:
         if len(path):
             dict = hierarchy
             for part in path[:-1]:
-                if not dict.has_key(part):
+                if part not in dict:
                     dict[part] = {}
                 dict = dict[part]
             dict[path[-1]] = file
                     dict[part] = {}
                 dict = dict[part]
             dict[path[-1]] = file
@@ -177,23 +176,21 @@ class _DSPGenerator:
         else:
             self.dspabs = get_abspath()
 
         else:
             self.dspabs = get_abspath()
 
-        if not env.has_key('variant'):
-            raise SCons.Errors.InternalError, \
-                  "You must specify a 'variant' argument (i.e. 'Debug' or " +\
-                  "'Release') to create an MSVSProject."
+        if 'variant' not in env:
+            raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\
+                  "'Release') to create an MSVSProject.")
         elif SCons.Util.is_String(env['variant']):
             variants = [env['variant']]
         elif SCons.Util.is_List(env['variant']):
             variants = env['variant']
 
         elif SCons.Util.is_String(env['variant']):
             variants = [env['variant']]
         elif SCons.Util.is_List(env['variant']):
             variants = env['variant']
 
-        if not env.has_key('buildtarget') or env['buildtarget'] == None:
+        if 'buildtarget' not in env or env['buildtarget'] == None:
             buildtarget = ['']
         elif SCons.Util.is_String(env['buildtarget']):
             buildtarget = [env['buildtarget']]
         elif SCons.Util.is_List(env['buildtarget']):
             if len(env['buildtarget']) != len(variants):
             buildtarget = ['']
         elif SCons.Util.is_String(env['buildtarget']):
             buildtarget = [env['buildtarget']]
         elif SCons.Util.is_List(env['buildtarget']):
             if len(env['buildtarget']) != len(variants):
-                raise SCons.Errors.InternalError, \
-                    "Sizes of 'buildtarget' and 'variant' lists must be the same."
+                raise SCons.Errors.InternalError("Sizes of 'buildtarget' and 'variant' lists must be the same.")
             buildtarget = []
             for bt in env['buildtarget']:
                 if SCons.Util.is_String(bt):
             buildtarget = []
             for bt in env['buildtarget']:
                 if SCons.Util.is_String(bt):
@@ -205,17 +202,16 @@ class _DSPGenerator:
         if len(buildtarget) == 1:
             bt = buildtarget[0]
             buildtarget = []
         if len(buildtarget) == 1:
             bt = buildtarget[0]
             buildtarget = []
-            for v in variants:
+            for _ in variants:
                 buildtarget.append(bt)
 
                 buildtarget.append(bt)
 
-        if not env.has_key('outdir') or env['outdir'] == None:
+        if 'outdir' not in env or env['outdir'] == None:
             outdir = ['']
         elif SCons.Util.is_String(env['outdir']):
             outdir = [env['outdir']]
         elif SCons.Util.is_List(env['outdir']):
             if len(env['outdir']) != len(variants):
             outdir = ['']
         elif SCons.Util.is_String(env['outdir']):
             outdir = [env['outdir']]
         elif SCons.Util.is_List(env['outdir']):
             if len(env['outdir']) != len(variants):
-                raise SCons.Errors.InternalError, \
-                    "Sizes of 'outdir' and 'variant' lists must be the same."
+                raise SCons.Errors.InternalError("Sizes of 'outdir' and 'variant' lists must be the same.")
             outdir = []
             for s in env['outdir']:
                 if SCons.Util.is_String(s):
             outdir = []
             for s in env['outdir']:
                 if SCons.Util.is_String(s):
@@ -230,14 +226,13 @@ class _DSPGenerator:
             for v in variants:
                 outdir.append(s)
 
             for v in variants:
                 outdir.append(s)
 
-        if not env.has_key('runfile') or env['runfile'] == None:
+        if 'runfile' not in env or env['runfile'] == None:
             runfile = buildtarget[-1:]
         elif SCons.Util.is_String(env['runfile']):
             runfile = [env['runfile']]
         elif SCons.Util.is_List(env['runfile']):
             if len(env['runfile']) != len(variants):
             runfile = buildtarget[-1:]
         elif SCons.Util.is_String(env['runfile']):
             runfile = [env['runfile']]
         elif SCons.Util.is_List(env['runfile']):
             if len(env['runfile']) != len(variants):
-                raise SCons.Errors.InternalError, \
-                    "Sizes of 'runfile' and 'variant' lists must be the same."
+                raise SCons.Errors.InternalError("Sizes of 'runfile' and 'variant' lists must be the same.")
             runfile = []
             for s in env['runfile']:
                 if SCons.Util.is_String(s):
             runfile = []
             for s in env['runfile']:
                 if SCons.Util.is_String(s):
@@ -258,7 +253,7 @@ class _DSPGenerator:
 
         self.env = env
 
 
         self.env = env
 
-        if self.env.has_key('name'):
+        if 'name' in self.env:
             self.name = self.env['name']
         else:
             self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
             self.name = self.env['name']
         else:
             self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
@@ -278,14 +273,14 @@ class _DSPGenerator:
         self.configs = {}
 
         self.nokeep = 0
         self.configs = {}
 
         self.nokeep = 0
-        if env.has_key('nokeep') and env['variant'] != 0:
+        if 'nokeep' in env and env['variant'] != 0:
             self.nokeep = 1
 
         if self.nokeep == 0 and os.path.exists(self.dspabs):
             self.Parse()
 
         for t in zip(sourcenames,self.srcargs):
             self.nokeep = 1
 
         if self.nokeep == 0 and os.path.exists(self.dspabs):
             self.Parse()
 
         for t in zip(sourcenames,self.srcargs):
-            if self.env.has_key(t[1]):
+            if t[1] in self.env:
                 if SCons.Util.is_List(self.env[t[1]]):
                     for i in self.env[t[1]]:
                         if not i in self.sources[t[0]]:
                 if SCons.Util.is_List(self.env[t[1]]):
                     for i in self.env[t[1]]:
                         if not i in self.sources[t[0]]:
@@ -297,7 +292,7 @@ class _DSPGenerator:
         for n in sourcenames:
             self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
 
         for n in sourcenames:
             self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
 
-        def AddConfig(variant, buildtarget, outdir, runfile, cmdargs):
+        def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspfile=dspfile):
             config = Config()
             config.buildtarget = buildtarget
             config.outdir = outdir
             config = Config()
             config.buildtarget = buildtarget
             config.outdir = outdir
@@ -316,7 +311,7 @@ class _DSPGenerator:
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
 
         for i in range(len(variants)):
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
 
         for i in range(len(variants)):
-            AddConfig(variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs)
+            AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs)
 
         self.platforms = []
         for key in self.configs.keys():
 
         self.platforms = []
         for key in self.configs.keys():
@@ -354,8 +349,7 @@ class _GenerateV6DSP(_DSPGenerator):
 
     def PrintHeader(self):
         # pick a default config
 
     def PrintHeader(self):
         # pick a default config
-        confkeys = self.configs.keys()
-        confkeys.sort()
+        confkeys = sorted(self.configs.keys())
 
         name = self.name
         confkey = confkeys[0]
 
         name = self.name
         confkey = confkeys[0]
@@ -375,8 +369,7 @@ class _GenerateV6DSP(_DSPGenerator):
                         '# PROP Scc_LocalPath ""\n\n')
 
         first = 1
                         '# PROP Scc_LocalPath ""\n\n')
 
         first = 1
-        confkeys = self.configs.keys()
-        confkeys.sort()
+        confkeys = sorted(self.configs.keys())
         for kind in confkeys:
             outdir = self.configs[kind].outdir
             buildtarget = self.configs[kind].buildtarget
         for kind in confkeys:
             outdir = self.configs[kind].outdir
             buildtarget = self.configs[kind].buildtarget
@@ -386,7 +379,7 @@ class _GenerateV6DSP(_DSPGenerator):
             else:
                 self.file.write('\n!ELSEIF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
 
             else:
                 self.file.write('\n!ELSEIF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
 
-            env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
+            env_has_buildtarget = 'MSVSBUILDTARGET' in self.env
             if not env_has_buildtarget:
                 self.env['MSVSBUILDTARGET'] = buildtarget
 
             if not env_has_buildtarget:
                 self.env['MSVSBUILDTARGET'] = buildtarget
 
@@ -394,6 +387,8 @@ class _GenerateV6DSP(_DSPGenerator):
             for base in ("BASE ",""):
                 self.file.write('# PROP %sUse_MFC 0\n'
                                 '# PROP %sUse_Debug_Libraries ' % (base, base))
             for base in ("BASE ",""):
                 self.file.write('# PROP %sUse_MFC 0\n'
                                 '# PROP %sUse_Debug_Libraries ' % (base, base))
+                # TODO(1.5):
+                #if kind.lower().find('debug') < 0:
                 if kind.lower().find('debug') < 0:
                     self.file.write('0\n')
                 else:
                 if kind.lower().find('debug') < 0:
                     self.file.write('0\n')
                 else:
@@ -451,7 +446,9 @@ class _GenerateV6DSP(_DSPGenerator):
                 continue # skip empty groups
 
             self.file.write('# Begin Group "' + kind + '"\n\n')
                 continue # skip empty groups
 
             self.file.write('# Begin Group "' + kind + '"\n\n')
-            typelist = categories[kind].replace('|',';')
+            # TODO(1.5)
+            #typelist = categories[kind].replace('|', ';')
+            typelist = categories[kind].replace('|', ';')
             self.file.write('# PROP Default_Filter "' + typelist + '"\n')
 
             for file in self.sources[kind]:
             self.file.write('# PROP Default_Filter "' + typelist + '"\n')
 
             for file in self.sources[kind]:
@@ -474,6 +471,8 @@ class _GenerateV6DSP(_DSPGenerator):
 
         line = dspfile.readline()
         while line:
 
         line = dspfile.readline()
         while line:
+            # TODO(1.5):
+            #if line.find("# End Project") > -1:
             if line.find("# End Project") > -1:
                 break
             line = dspfile.readline()
             if line.find("# End Project") > -1:
                 break
             line = dspfile.readline()
@@ -518,7 +517,7 @@ class _GenerateV6DSP(_DSPGenerator):
         try:
             self.file = open(self.dspabs,'w')
         except IOError, detail:
         try:
             self.file = open(self.dspabs,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail))
         else:
             self.PrintHeader()
             self.PrintProject()
         else:
             self.PrintHeader()
             self.PrintProject()
@@ -564,7 +563,7 @@ V8DSPHeader = """\
 
 V8DSPConfiguration = """\
 \t\t<Configuration
 
 V8DSPConfiguration = """\
 \t\t<Configuration
-\t\t\tName="%(variant)s|Win32"
+\t\t\tName="%(variant)s|%(platform)s"
 \t\t\tConfigurationType="0"
 \t\t\tUseOfMFC="0"
 \t\t\tATLMinimizesCRunTimeLibraryUsage="false"
 \t\t\tConfigurationType="0"
 \t\t\tUseOfMFC="0"
 \t\t\tATLMinimizesCRunTimeLibraryUsage="false"
@@ -575,8 +574,8 @@ V8DSPConfiguration = """\
 \t\t\t\tReBuildCommandLine="%(rebuildcmd)s"
 \t\t\t\tCleanCommandLine="%(cleancmd)s"
 \t\t\t\tOutput="%(runfile)s"
 \t\t\t\tReBuildCommandLine="%(rebuildcmd)s"
 \t\t\t\tCleanCommandLine="%(cleancmd)s"
 \t\t\t\tOutput="%(runfile)s"
-\t\t\t\tPreprocessorDefinitions=""
-\t\t\t\tIncludeSearchPath=""
+\t\t\t\tPreprocessorDefinitions="%(preprocdefs)s"
+\t\t\t\tIncludeSearchPath="%(includepath)s"
 \t\t\t\tForcedIncludes=""
 \t\t\t\tAssemblySearchPath=""
 \t\t\t\tForcedUsingAssemblies=""
 \t\t\t\tForcedIncludes=""
 \t\t\t\tAssemblySearchPath=""
 \t\t\t\tForcedUsingAssemblies=""
@@ -643,8 +642,7 @@ class _GenerateV7DSP(_DSPGenerator):
     def PrintProject(self):
         self.file.write('\t<Configurations>\n')
 
     def PrintProject(self):
         self.file.write('\t<Configurations>\n')
 
-        confkeys = self.configs.keys()
-        confkeys.sort()
+        confkeys = sorted(self.configs.keys())
         for kind in confkeys:
             variant = self.configs[kind].variant
             platform = self.configs[kind].platform
         for kind in confkeys:
             variant = self.configs[kind].variant
             platform = self.configs[kind].platform
@@ -653,7 +651,7 @@ class _GenerateV7DSP(_DSPGenerator):
             runfile     = self.configs[kind].runfile
             cmdargs = self.configs[kind].cmdargs
 
             runfile     = self.configs[kind].runfile
             cmdargs = self.configs[kind].cmdargs
 
-            env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
+            env_has_buildtarget = 'MSVSBUILDTARGET' in self.env
             if not env_has_buildtarget:
                 self.env['MSVSBUILDTARGET'] = buildtarget
 
             if not env_has_buildtarget:
                 self.env['MSVSBUILDTARGET'] = buildtarget
 
@@ -666,6 +664,12 @@ class _GenerateV7DSP(_DSPGenerator):
             rebuildcmd  = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs)
             cleancmd    = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs)
 
             rebuildcmd  = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs)
             cleancmd    = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs)
 
+            # TODO(1.5)
+            #preprocdefs = xmlify(';'.join(self.env.get('CPPDEFINES', [])))
+            #includepath = xmlify(';'.join(self.env.get('CPPPATH', [])))
+            preprocdefs = xmlify(';'.join(processDefines(self.env.get('CPPDEFINES', []))))
+            includepath = xmlify(';'.join(self.env.get('CPPPATH', [])))
+
             if not env_has_buildtarget:
                 del self.env['MSVSBUILDTARGET']
 
             if not env_has_buildtarget:
                 del self.env['MSVSBUILDTARGET']
 
@@ -690,6 +694,29 @@ class _GenerateV7DSP(_DSPGenerator):
             pdata = base64.encodestring(pdata)
             self.file.write(pdata + '-->\n')
 
             pdata = base64.encodestring(pdata)
             self.file.write(pdata + '-->\n')
 
+    def printSources(self, hierarchy, commonprefix):
+        sorteditems = hierarchy.items()
+        sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
+
+        # First folders, then files
+        for key, value in sorteditems:
+            if SCons.Util.is_Dict(value):
+                self.file.write('\t\t\t<Filter\n'
+                                '\t\t\t\tName="%s"\n'
+                                '\t\t\t\tFilter="">\n' % (key))
+                self.printSources(value, commonprefix)
+                self.file.write('\t\t\t</Filter>\n')
+
+        for key, value in sorteditems:
+            if SCons.Util.is_String(value):
+                file = value
+                if commonprefix:
+                    file = os.path.join(commonprefix, value)
+                file = os.path.normpath(file)
+                self.file.write('\t\t\t<File\n'
+                                '\t\t\t\tRelativePath="%s">\n'
+                                '\t\t\t</File>\n' % (file))
+
     def PrintSourceFiles(self):
         categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
                       'Header Files': 'h;hpp;hxx;hm;inl',
     def PrintSourceFiles(self):
         categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
                       'Header Files': 'h;hpp;hxx;hm;inl',
@@ -701,50 +728,33 @@ class _GenerateV7DSP(_DSPGenerator):
 
         cats = categories.keys()
         cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
 
         cats = categories.keys()
         cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
-        cats = filter(lambda k, s=self: s.sources[k], cats)
+        cats = [k for k in cats if self.sources[k]]
         for kind in cats:
             if len(cats) > 1:
                 self.file.write('\t\t<Filter\n'
                                 '\t\t\tName="%s"\n'
                                 '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
 
         for kind in cats:
             if len(cats) > 1:
                 self.file.write('\t\t<Filter\n'
                                 '\t\t\tName="%s"\n'
                                 '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
 
-
-            def printSources(hierarchy, commonprefix):
-                sorteditems = hierarchy.items()
-                sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
-
-                # First folders, then files
-                for key, value in sorteditems:
-                    if SCons.Util.is_Dict(value):
-                        self.file.write('\t\t\t<Filter\n'
-                                        '\t\t\t\tName="%s"\n'
-                                        '\t\t\t\tFilter="">\n' % (key))
-                        printSources(value, commonprefix)
-                        self.file.write('\t\t\t</Filter>\n')
-
-                for key, value in sorteditems:
-                    if SCons.Util.is_String(value):
-                        file = value
-                        if commonprefix:
-                            file = os.path.join(commonprefix, value)
-                        file = os.path.normpath(file)
-                        self.file.write('\t\t\t<File\n'
-                                        '\t\t\t\tRelativePath="%s">\n'
-                                        '\t\t\t</File>\n' % (file))
-
             sources = self.sources[kind]
 
             # First remove any common prefix
             commonprefix = None
             if len(sources) > 1:
             sources = self.sources[kind]
 
             # First remove any common prefix
             commonprefix = None
             if len(sources) > 1:
-                s = map(os.path.normpath, sources)
-                cp = os.path.commonprefix(s)
+                s = list(map(os.path.normpath, sources))
+                # take the dirname because the prefix may include parts
+                # of the filenames (e.g. if you have 'dir\abcd' and
+                # 'dir\acde' then the cp will be 'dir\a' )
+                cp = os.path.dirname( os.path.commonprefix(s) )
                 if cp and s[0][len(cp)] == os.sep:
                 if cp and s[0][len(cp)] == os.sep:
-                    sources = map(lambda s, l=len(cp): s[l:], sources)
+                    # +1 because the filename starts after the separator
+                    sources = [s[len(cp)+1:] for s in sources]
                     commonprefix = cp
                     commonprefix = cp
+            elif len(sources) == 1:
+                commonprefix = os.path.dirname( sources[0] )
+                sources[0] = os.path.basename( sources[0] )
 
             hierarchy = makeHierarchy(sources)
 
             hierarchy = makeHierarchy(sources)
-            printSources(hierarchy, commonprefix=commonprefix)
+            self.printSources(hierarchy, commonprefix=commonprefix)
 
             if len(cats)>1:
                 self.file.write('\t\t</Filter>\n')
 
             if len(cats)>1:
                 self.file.write('\t\t</Filter>\n')
@@ -766,6 +776,8 @@ class _GenerateV7DSP(_DSPGenerator):
 
         line = dspfile.readline()
         while line:
 
         line = dspfile.readline()
         while line:
+            # TODO(1.5)
+            #if line.find('<!-- SCons Data:') > -1:
             if line.find('<!-- SCons Data:') > -1:
                 break
             line = dspfile.readline()
             if line.find('<!-- SCons Data:') > -1:
                 break
             line = dspfile.readline()
@@ -809,7 +821,7 @@ class _GenerateV7DSP(_DSPGenerator):
         try:
             self.file = open(self.dspabs,'w')
         except IOError, detail:
         try:
             self.file = open(self.dspabs,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError('Unable to open "' + self.dspabs + '" for writing:' + str(detail))
         else:
             self.PrintHeader()
             self.PrintProject()
         else:
             self.PrintHeader()
             self.PrintProject()
@@ -821,20 +833,17 @@ class _DSWGenerator:
         self.dswfile = os.path.normpath(str(dswfile))
         self.env = env
 
         self.dswfile = os.path.normpath(str(dswfile))
         self.env = env
 
-        if not env.has_key('projects'):
-            raise SCons.Errors.UserError, \
-                "You must specify a 'projects' argument to create an MSVSSolution."
+        if 'projects' not in env:
+            raise SCons.Errors.UserError("You must specify a 'projects' argument to create an MSVSSolution.")
         projects = env['projects']
         if not SCons.Util.is_List(projects):
         projects = env['projects']
         if not SCons.Util.is_List(projects):
-            raise SCons.Errors.InternalError, \
-                "The 'projects' argument must be a list of nodes."
+            raise SCons.Errors.InternalError("The 'projects' argument must be a list of nodes.")
         projects = SCons.Util.flatten(projects)
         if len(projects) < 1:
         projects = SCons.Util.flatten(projects)
         if len(projects) < 1:
-            raise SCons.Errors.UserError, \
-                "You must specify at least one project to create an MSVSSolution."
-        self.dspfiles = map(str, projects)
+            raise SCons.Errors.UserError("You must specify at least one project to create an MSVSSolution.")
+        self.dspfiles = list(map(str, projects))
 
 
-        if self.env.has_key('name'):
+        if 'name' in self.env:
             self.name = self.env['name']
         else:
             self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0])
             self.name = self.env['name']
         else:
             self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0])
@@ -859,7 +868,7 @@ class _GenerateV7DSW(_DSWGenerator):
         if self.version_num >= 8.0:
             self.versionstr = '9.00'
 
         if self.version_num >= 8.0:
             self.versionstr = '9.00'
 
-        if env.has_key('slnguid') and env['slnguid']:
+        if 'slnguid' in env and env['slnguid']:
             self.slnguid = env['slnguid']
         else:
             self.slnguid = _generateGUID(dswfile, self.name)
             self.slnguid = env['slnguid']
         else:
             self.slnguid = _generateGUID(dswfile, self.name)
@@ -867,13 +876,13 @@ class _GenerateV7DSW(_DSWGenerator):
         self.configs = {}
 
         self.nokeep = 0
         self.configs = {}
 
         self.nokeep = 0
-        if env.has_key('nokeep') and env['variant'] != 0:
+        if 'nokeep' in env and env['variant'] != 0:
             self.nokeep = 1
 
         if self.nokeep == 0 and os.path.exists(self.dswfile):
             self.Parse()
 
             self.nokeep = 1
 
         if self.nokeep == 0 and os.path.exists(self.dswfile):
             self.Parse()
 
-        def AddConfig(variant):
+        def AddConfig(self, variant, dswfile=dswfile):
             config = Config()
 
             match = re.match('(.*)\|(.*)', variant)
             config = Config()
 
             match = re.match('(.*)\|(.*)', variant)
@@ -887,15 +896,14 @@ class _GenerateV7DSW(_DSWGenerator):
             self.configs[variant] = config
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
 
             self.configs[variant] = config
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
 
-        if not env.has_key('variant'):
-            raise SCons.Errors.InternalError, \
-                  "You must specify a 'variant' argument (i.e. 'Debug' or " +\
-                  "'Release') to create an MSVS Solution File."
+        if 'variant' not in env:
+            raise SCons.Errors.InternalError("You must specify a 'variant' argument (i.e. 'Debug' or " +\
+                  "'Release') to create an MSVS Solution File.")
         elif SCons.Util.is_String(env['variant']):
         elif SCons.Util.is_String(env['variant']):
-            AddConfig(env['variant'])
+            AddConfig(self, env['variant'])
         elif SCons.Util.is_List(env['variant']):
             for variant in env['variant']:
         elif SCons.Util.is_List(env['variant']):
             for variant in env['variant']:
-                AddConfig(variant)
+                AddConfig(self, variant)
 
         self.platforms = []
         for key in self.configs.keys():
 
         self.platforms = []
         for key in self.configs.keys():
@@ -953,11 +961,11 @@ class _GenerateV7DSW(_DSWGenerator):
         self.file.write('Global\n')
 
         env = self.env
         self.file.write('Global\n')
 
         env = self.env
-        if env.has_key('MSVS_SCC_PROVIDER'):
+        if 'MSVS_SCC_PROVIDER' in env:
             dspfile_base = os.path.basename(self.dspfile)
             slnguid = self.slnguid
             scc_provider = env.get('MSVS_SCC_PROVIDER', '')
             dspfile_base = os.path.basename(self.dspfile)
             slnguid = self.slnguid
             scc_provider = env.get('MSVS_SCC_PROVIDER', '')
-            scc_provider = string.replace(scc_provider, ' ', r'\u0020')
+            scc_provider = scc_provider.replace(' ', r'\u0020')
             scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
             # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
             scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
             scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
             # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
             scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
@@ -983,8 +991,7 @@ class _GenerateV7DSW(_DSWGenerator):
         else:
             self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
 
         else:
             self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
 
-        confkeys = self.configs.keys()
-        confkeys.sort()
+        confkeys = sorted(self.configs.keys())
         cnt = 0
         for name in confkeys:
             variant = self.configs[name].variant
         cnt = 0
         for name in confkeys:
             variant = self.configs[name].variant
@@ -1004,7 +1011,6 @@ class _GenerateV7DSW(_DSWGenerator):
             self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
 
         for name in confkeys:
             self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
 
         for name in confkeys:
-            name = name
             variant = self.configs[name].variant
             platform = self.configs[name].platform
             if self.version_num >= 8.0:
             variant = self.configs[name].variant
             platform = self.configs[name].platform
             if self.version_num >= 8.0:
@@ -1013,8 +1019,10 @@ class _GenerateV7DSW(_DSWGenerator):
                     self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
                                     '\t\t%s.%s|%s.Build.0 = %s|%s\n'  % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
             else:
                     self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
                                     '\t\t%s.%s|%s.Build.0 = %s|%s\n'  % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
             else:
-                self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
-                                '\t\t%s.%s.Build.0 = %s|%s\n'  %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform))
+                for p in self.dspfiles:
+                    guid = _generateGUID(p, '')
+                    self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
+                                    '\t\t%s.%s.Build.0 = %s|%s\n'  %(guid,variant,variant,platform,guid,variant,variant,platform))
 
         self.file.write('\tEndGlobalSection\n')
 
 
         self.file.write('\tEndGlobalSection\n')
 
@@ -1037,7 +1045,7 @@ class _GenerateV7DSW(_DSWGenerator):
         try:
             self.file = open(self.dswfile,'w')
         except IOError, detail:
         try:
             self.file = open(self.dswfile,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail))
         else:
             self.PrintSolution()
             self.file.close()
         else:
             self.PrintSolution()
             self.file.close()
@@ -1086,7 +1094,7 @@ class _GenerateV6DSW(_DSWGenerator):
         try:
             self.file = open(self.dswfile,'w')
         except IOError, detail:
         try:
             self.file = open(self.dswfile,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError('Unable to open "' + self.dswfile + '" for writing:' + str(detail))
         else:
             self.PrintWorkspace()
             self.file.close()
         else:
             self.PrintWorkspace()
             self.file.close()
@@ -1096,7 +1104,7 @@ def GenerateDSP(dspfile, source, env):
     """Generates a Project file based on the version of MSVS that is being used"""
 
     version_num = 6.0
     """Generates a Project file based on the version of MSVS that is being used"""
 
     version_num = 6.0
-    if env.has_key('MSVS_VERSION'):
+    if 'MSVS_VERSION' in env:
         version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
     if version_num >= 7.0:
         g = _GenerateV7DSP(dspfile, source, env)
         version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
     if version_num >= 7.0:
         g = _GenerateV7DSP(dspfile, source, env)
@@ -1109,7 +1117,7 @@ def GenerateDSW(dswfile, source, env):
     """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
 
     version_num = 6.0
     """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
 
     version_num = 6.0
-    if env.has_key('MSVS_VERSION'):
+    if 'MSVS_VERSION' in env:
         version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
     if version_num >= 7.0:
         g = _GenerateV7DSW(dswfile, source, env)
         version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
     if version_num >= 7.0:
         g = _GenerateV7DSW(dswfile, source, env)
@@ -1124,346 +1132,6 @@ def GenerateDSW(dswfile, source, env):
 # DSP/DSW/SLN/VCPROJ files.
 ##############################################################################
 
 # DSP/DSW/SLN/VCPROJ files.
 ##############################################################################
 
-def get_default_visualstudio_version(env):
-    """Returns the version set in the env, or the latest version
-    installed, if it can find it, or '6.0' if all else fails.  Also
-    updated the environment with what it found."""
-
-    version = '6.0'
-    versions = [version]
-
-    if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
-        env['MSVS'] = {}    
-
-        if env['MSVS'].has_key('VERSIONS'):
-            versions = env['MSVS']['VERSIONS']
-        elif SCons.Util.can_read_reg:
-            v = get_visualstudio_versions()
-            if v:
-                versions = v
-        if env.has_key('MSVS_VERSION'):
-            version = env['MSVS_VERSION']
-        else:
-            version = versions[0] #use highest version by default
-
-        env['MSVS_VERSION'] = version
-        env['MSVS']['VERSIONS'] = versions
-        env['MSVS']['VERSION'] = version
-    else:
-        version = env['MSVS']['VERSION']
-
-    return version
-
-def get_visualstudio_versions():
-    """
-    Get list of visualstudio versions from the Windows registry.
-    Returns a list of strings containing version numbers.  An empty list
-    is returned if we were unable to accees the register (for example,
-    we couldn't import the registry-access module) or the appropriate
-    registry keys weren't found.
-    """
-
-    if not SCons.Util.can_read_reg:
-        return []
-
-    HLM = SCons.Util.HKEY_LOCAL_MACHINE
-    KEYS = {
-        r'Software\Microsoft\VisualStudio'      : '',
-        r'Software\Microsoft\VCExpress'         : 'Exp',
-    }
-    L = []
-    for K, suite_suffix in KEYS.items():
-        try:
-            k = SCons.Util.RegOpenKeyEx(HLM, K)
-            i = 0
-            while 1:
-                try:
-                    p = SCons.Util.RegEnumKey(k,i)
-                except SCons.Util.RegError:
-                    break
-                i = i + 1
-                if not p[0] in '123456789' or p in L:
-                    continue
-                # Only add this version number if there is a valid
-                # registry structure (includes the "Setup" key),
-                # and at least some of the correct directories
-                # exist.  Sometimes VS uninstall leaves around
-                # some registry/filesystem turds that we don't
-                # want to trip over.  Also, some valid registry
-                # entries are MSDN entries, not MSVS ('7.1',
-                # notably), and we want to skip those too.
-                try:
-                    SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p + '\\Setup')
-                except SCons.Util.RegError:
-                    continue
-
-                id = []
-                idk = SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p)
-                # This is not always here -- it only exists if the
-                # user installed into a non-standard location (at
-                # least in VS6 it works that way -- VS7 seems to
-                # always write it)
-                try:
-                    id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
-                except SCons.Util.RegError:
-                    pass
-
-                # If the InstallDir key doesn't exist,
-                # then we check the default locations.
-                # Note: The IDE's executable is not devenv.exe for VS8 Express.
-                if not id or not id[0]:
-                    files_dir = SCons.Platform.win32.get_program_files_dir()
-                    version_num, suite = msvs_parse_version(p)
-                    if version_num < 7.0:
-                        vs = r'Microsoft Visual Studio\Common\MSDev98'
-                    elif version_num < 8.0:
-                        vs = r'Microsoft Visual Studio .NET\Common7\IDE'
-                    else:
-                        vs = r'Microsoft Visual Studio 8\Common7\IDE'
-                    id = [ os.path.join(files_dir, vs) ]
-                if os.path.exists(id[0]):
-                    L.append(p + suite_suffix)
-        except SCons.Util.RegError:
-            pass
-
-    if not L:
-        return []
-
-    # This is a hack to get around the fact that certain Visual Studio
-    # patches place a "6.1" version in the registry, which does not have
-    # any of the keys we need to find include paths, install directories,
-    # etc.  Therefore we ignore it if it is there, since it throws all
-    # other logic off.
-    try:
-        L.remove("6.1")
-    except ValueError:
-        pass
-
-    L.sort()
-    L.reverse()
-
-    return L
-
-def get_default_visualstudio8_suite(env):
-    """
-    Returns the Visual Studio 2005 suite identifier set in the env, or the
-    highest suite installed.
-    """
-    if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
-        env['MSVS'] = {}
-
-    if env.has_key('MSVS_SUITE'):
-        suite = env['MSVS_SUITE'].upper()
-        suites = [suite]
-    else:
-        suite = 'EXPRESS'
-        suites = [suite]
-        if SCons.Util.can_read_reg:
-            suites = get_visualstudio8_suites()
-            if suites:
-                suite = suites[0] #use best suite by default
-
-    env['MSVS_SUITE'] = suite
-    env['MSVS']['SUITES'] = suites
-    env['MSVS']['SUITE'] = suite
-
-    return suite
-
-def get_visualstudio8_suites():
-    """
-    Returns a sorted list of all installed Visual Studio 2005 suites found
-    in the registry. The highest version should be the first entry in the list.
-    """
-
-    suites = []
-
-    # Detect Standard, Professional and Team edition
-    try:
-        idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
-            r'Software\Microsoft\VisualStudio\8.0')
-        id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
-        editions = { 'PRO': r'Setup\VS\Pro' }       # ToDo: add standard and team editions
-        edition_name = 'STD'
-        for name, key_suffix in editions.items():
-            try:
-                idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
-                    r'Software\Microsoft\VisualStudio\8.0' + '\\' + key_suffix )
-                edition_name = name
-            except SCons.Util.RegError:
-                pass
-            suites.append(edition_name)
-    except SCons.Util.RegError:
-        pass
-
-    # Detect Expression edition
-    try:
-        idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
-            r'Software\Microsoft\VCExpress\8.0')
-        id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
-        suites.append('EXPRESS')
-    except SCons.Util.RegError:
-        pass
-
-    return suites
-
-def is_msvs_installed():
-    """
-    Check the registry for an installed visual studio.
-    """
-    try:
-        v = SCons.Tool.msvs.get_visualstudio_versions()
-        return v
-    except (SCons.Util.RegError, SCons.Errors.InternalError):
-        return 0
-
-def get_msvs_install_dirs(version = None):
-    """
-    Get installed locations for various msvc-related products, like the .NET SDK
-    and the Platform SDK.
-    """
-
-    if not SCons.Util.can_read_reg:
-        return {}
-
-    if not version:
-        versions = get_visualstudio_versions()
-        if versions:
-            version = versions[0] #use highest version by default
-        else:
-            return {}
-
-    version_num, suite = msvs_parse_version(version)
-
-    K = 'Software\\Microsoft\\VisualStudio\\' + str(version_num)
-    if (version_num >= 8.0):
-        try:
-            SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, K )
-        except SCons.Util.RegError:
-            K = 'Software\\Microsoft\\VCExpress\\' + str(version_num)
-
-    # vc++ install dir
-    rv = {}
-    if (version_num < 7.0):
-        key = K + r'\Setup\Microsoft Visual C++\ProductDir'
-    else:
-        key = K + r'\Setup\VC\ProductDir'
-    try:
-        (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, key)
-    except SCons.Util.RegError:
-        pass
-
-    # visual studio install dir
-    if (version_num < 7.0):
-        try:
-            (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
-                                                             K + r'\Setup\Microsoft Visual Studio\ProductDir')
-        except SCons.Util.RegError:
-            pass
-
-        if not rv.has_key('VSINSTALLDIR') or not rv['VSINSTALLDIR']:
-            if rv.has_key('VCINSTALLDIR') and rv['VCINSTALLDIR']:
-                rv['VSINSTALLDIR'] = os.path.dirname(rv['VCINSTALLDIR'])
-            else:
-                rv['VSINSTALLDIR'] = os.path.join(SCons.Platform.win32.get_program_files_dir(),'Microsoft Visual Studio')
-    else:
-        try:
-            (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
-                                                             K + r'\Setup\VS\ProductDir')
-        except SCons.Util.RegError:
-            pass
-
-    # .NET framework install dir
-    try:
-        (rv['FRAMEWORKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
-            r'Software\Microsoft\.NETFramework\InstallRoot')
-    except SCons.Util.RegError:
-        pass
-
-    if rv.has_key('FRAMEWORKDIR'):
-        # try and enumerate the installed versions of the .NET framework.
-        contents = os.listdir(rv['FRAMEWORKDIR'])
-        l = re.compile('v[0-9]+.*')
-        versions = []
-        for entry in contents:
-            if l.match(entry):
-                versions.append(entry)
-
-        def versrt(a,b):
-            # since version numbers aren't really floats...
-            aa = a[1:]
-            bb = b[1:]
-            aal = aa.split('.')
-            bbl = bb.split('.')
-            c = int(bbl[0]) - int(aal[0])
-            if c == 0:
-                c = int(bbl[1]) - int(aal[1])
-                if c == 0:
-                    c = int(bbl[2]) - int(aal[2])
-            return c
-
-        versions.sort(versrt)
-
-        rv['FRAMEWORKVERSIONS'] = versions
-        # assume that the highest version is the latest version installed
-        rv['FRAMEWORKVERSION'] = versions[0]
-
-    # .NET framework SDK install dir
-    try:
-        if rv.has_key('FRAMEWORKVERSION') and rv['FRAMEWORKVERSION'][:4] == 'v1.1':
-            key = r'Software\Microsoft\.NETFramework\sdkInstallRootv1.1'
-        else:
-            key = r'Software\Microsoft\.NETFramework\sdkInstallRoot'
-
-        (rv['FRAMEWORKSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,key)
-
-    except SCons.Util.RegError:
-        pass
-
-    # MS Platform SDK dir
-    try:
-        (rv['PLATFORMSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
-            r'Software\Microsoft\MicrosoftSDK\Directories\Install Dir')
-    except SCons.Util.RegError:
-        pass
-
-    if rv.has_key('PLATFORMSDKDIR'):
-        # if we have a platform SDK, try and get some info on it.
-        vers = {}
-        try:
-            loc = r'Software\Microsoft\MicrosoftSDK\InstalledSDKs'
-            k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,loc)
-            i = 0
-            while 1:
-                try:
-                    key = SCons.Util.RegEnumKey(k,i)
-                    sdk = SCons.Util.RegOpenKeyEx(k,key)
-                    j = 0
-                    name = ''
-                    date = ''
-                    version = ''
-                    while 1:
-                        try:
-                            (vk,vv,t) = SCons.Util.RegEnumValue(sdk,j)
-                            if vk.lower() == 'keyword':
-                                name = vv
-                            if vk.lower() == 'propagation_date':
-                                date = vv
-                            if vk.lower() == 'version':
-                                version = vv
-                            j = j + 1
-                        except SCons.Util.RegError:
-                            break
-                    if name:
-                        vers[name] = (date, version)
-                    i = i + 1
-                except SCons.Util.RegError:
-                    break
-            rv['PLATFORMSDK_MODULES'] = vers
-        except SCons.Util.RegError:
-            pass
-
-    return rv
-
 def GetMSVSProjectSuffix(target, source, env, for_signature):
      return env['MSVS']['PROJECTSUFFIX']
 
 def GetMSVSProjectSuffix(target, source, env, for_signature):
      return env['MSVS']['PROJECTSUFFIX']
 
@@ -1475,7 +1143,7 @@ def GenerateProject(target, source, env):
     builddspfile = target[0]
     dspfile = builddspfile.srcnode()
 
     builddspfile = target[0]
     dspfile = builddspfile.srcnode()
 
-    # this detects whether or not we're using a BuildDir
+    # this detects whether or not we're using a VariantDir
     if not dspfile is builddspfile:
         try:
             bdsp = open(str(builddspfile), "w+")
     if not dspfile is builddspfile:
         try:
             bdsp = open(str(builddspfile), "w+")
@@ -1525,7 +1193,7 @@ def projectEmitter(target, source, env):
         source = source + env.subst('$MSVSSCONSCOM', 1)
         source = source + env.subst('$MSVSENCODING', 1)
 
         source = source + env.subst('$MSVSSCONSCOM', 1)
         source = source + env.subst('$MSVSENCODING', 1)
 
-        if env.has_key('buildtarget') and env['buildtarget'] != None:
+        if 'buildtarget' in env and env['buildtarget'] != None:
             if SCons.Util.is_String(env['buildtarget']):
                 source = source + ' "%s"' % env['buildtarget']
             elif SCons.Util.is_List(env['buildtarget']):
             if SCons.Util.is_String(env['buildtarget']):
                 source = source + ' "%s"' % env['buildtarget']
             elif SCons.Util.is_List(env['buildtarget']):
@@ -1534,14 +1202,12 @@ def projectEmitter(target, source, env):
                         source = source + ' "%s"' % bt
                     else:
                         try: source = source + ' "%s"' % bt.get_abspath()
                         source = source + ' "%s"' % bt
                     else:
                         try: source = source + ' "%s"' % bt.get_abspath()
-                        except AttributeError: raise SCons.Errors.InternalError, \
-                            "buildtarget can be a string, a node, a list of strings or nodes, or None"
+                        except AttributeError: raise SCons.Errors.InternalError("buildtarget can be a string, a node, a list of strings or nodes, or None")
             else:
                 try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
             else:
                 try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
-                except AttributeError: raise SCons.Errors.InternalError, \
-                    "buildtarget can be a string, a node, a list of strings or nodes, or None"
+                except AttributeError: raise SCons.Errors.InternalError("buildtarget can be a string, a node, a list of strings or nodes, or None")
 
 
-        if env.has_key('outdir') and env['outdir'] != None:
+        if 'outdir' in env and env['outdir'] != None:
             if SCons.Util.is_String(env['outdir']):
                 source = source + ' "%s"' % env['outdir']
             elif SCons.Util.is_List(env['outdir']):
             if SCons.Util.is_String(env['outdir']):
                 source = source + ' "%s"' % env['outdir']
             elif SCons.Util.is_List(env['outdir']):
@@ -1550,20 +1216,18 @@ def projectEmitter(target, source, env):
                         source = source + ' "%s"' % s
                     else:
                         try: source = source + ' "%s"' % s.get_abspath()
                         source = source + ' "%s"' % s
                     else:
                         try: source = source + ' "%s"' % s.get_abspath()
-                        except AttributeError: raise SCons.Errors.InternalError, \
-                            "outdir can be a string, a node, a list of strings or nodes, or None"
+                        except AttributeError: raise SCons.Errors.InternalError("outdir can be a string, a node, a list of strings or nodes, or None")
             else:
                 try: source = source + ' "%s"' % env['outdir'].get_abspath()
             else:
                 try: source = source + ' "%s"' % env['outdir'].get_abspath()
-                except AttributeError: raise SCons.Errors.InternalError, \
-                    "outdir can be a string, a node, a list of strings or nodes, or None"
+                except AttributeError: raise SCons.Errors.InternalError("outdir can be a string, a node, a list of strings or nodes, or None")
 
 
-        if env.has_key('name'):
+        if 'name' in env:
             if SCons.Util.is_String(env['name']):
                 source = source + ' "%s"' % env['name']
             else:
             if SCons.Util.is_String(env['name']):
                 source = source + ' "%s"' % env['name']
             else:
-                raise SCons.Errors.InternalError, "name must be a string"
+                raise SCons.Errors.InternalError("name must be a string")
 
 
-        if env.has_key('variant'):
+        if 'variant' in env:
             if SCons.Util.is_String(env['variant']):
                 source = source + ' "%s"' % env['variant']
             elif SCons.Util.is_List(env['variant']):
             if SCons.Util.is_String(env['variant']):
                 source = source + ' "%s"' % env['variant']
             elif SCons.Util.is_List(env['variant']):
@@ -1571,14 +1235,14 @@ def projectEmitter(target, source, env):
                     if SCons.Util.is_String(variant):
                         source = source + ' "%s"' % variant
                     else:
                     if SCons.Util.is_String(variant):
                         source = source + ' "%s"' % variant
                     else:
-                        raise SCons.Errors.InternalError, "name must be a string or a list of strings"
+                        raise SCons.Errors.InternalError("name must be a string or a list of strings")
             else:
             else:
-                raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
+                raise SCons.Errors.InternalError("variant must be a string or a list of strings")
         else:
         else:
-            raise SCons.Errors.InternalError, "variant must be specified"
+            raise SCons.Errors.InternalError("variant must be specified")
 
         for s in _DSPGenerator.srcargs:
 
         for s in _DSPGenerator.srcargs:
-            if env.has_key(s):
+            if s in env:
                 if SCons.Util.is_String(env[s]):
                     source = source + ' "%s' % env[s]
                 elif SCons.Util.is_List(env[s]):
                 if SCons.Util.is_String(env[s]):
                     source = source + ' "%s' % env[s]
                 elif SCons.Util.is_List(env[s]):
@@ -1586,9 +1250,9 @@ def projectEmitter(target, source, env):
                         if SCons.Util.is_String(t):
                             source = source + ' "%s"' % t
                         else:
                         if SCons.Util.is_String(t):
                             source = source + ' "%s"' % t
                         else:
-                            raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
+                            raise SCons.Errors.InternalError(s + " must be a string or a list of strings")
                 else:
                 else:
-                    raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
+                    raise SCons.Errors.InternalError(s + " must be a string or a list of strings")
 
         source = source + ' "%s"' % str(target[0])
         source = [SCons.Node.Python.Value(source)]
 
         source = source + ' "%s"' % str(target[0])
         source = [SCons.Node.Python.Value(source)]
@@ -1620,13 +1284,13 @@ def solutionEmitter(target, source, env):
     if not source:
         source = 'sln_inputs:'
 
     if not source:
         source = 'sln_inputs:'
 
-        if env.has_key('name'):
+        if 'name' in env:
             if SCons.Util.is_String(env['name']):
                 source = source + ' "%s"' % env['name']
             else:
             if SCons.Util.is_String(env['name']):
                 source = source + ' "%s"' % env['name']
             else:
-                raise SCons.Errors.InternalError, "name must be a string"
+                raise SCons.Errors.InternalError("name must be a string")
 
 
-        if env.has_key('variant'):
+        if 'variant' in env:
             if SCons.Util.is_String(env['variant']):
                 source = source + ' "%s"' % env['variant']
             elif SCons.Util.is_List(env['variant']):
             if SCons.Util.is_String(env['variant']):
                 source = source + ' "%s"' % env['variant']
             elif SCons.Util.is_List(env['variant']):
@@ -1634,19 +1298,19 @@ def solutionEmitter(target, source, env):
                     if SCons.Util.is_String(variant):
                         source = source + ' "%s"' % variant
                     else:
                     if SCons.Util.is_String(variant):
                         source = source + ' "%s"' % variant
                     else:
-                        raise SCons.Errors.InternalError, "name must be a string or a list of strings"
+                        raise SCons.Errors.InternalError("name must be a string or a list of strings")
             else:
             else:
-                raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
+                raise SCons.Errors.InternalError("variant must be a string or a list of strings")
         else:
         else:
-            raise SCons.Errors.InternalError, "variant must be specified"
+            raise SCons.Errors.InternalError("variant must be specified")
 
 
-        if env.has_key('slnguid'):
+        if 'slnguid' in env:
             if SCons.Util.is_String(env['slnguid']):
                 source = source + ' "%s"' % env['slnguid']
             else:
             if SCons.Util.is_String(env['slnguid']):
                 source = source + ' "%s"' % env['slnguid']
             else:
-                raise SCons.Errors.InternalError, "slnguid must be a string"
+                raise SCons.Errors.InternalError("slnguid must be a string")
 
 
-        if env.has_key('projects'):
+        if 'projects' in env:
             if SCons.Util.is_String(env['projects']):
                 source = source + ' "%s"' % env['projects']
             elif SCons.Util.is_List(env['projects']):
             if SCons.Util.is_String(env['projects']):
                 source = source + ' "%s"' % env['projects']
             elif SCons.Util.is_List(env['projects']):
@@ -1702,24 +1366,20 @@ def generate(env):
     env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
     env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.abspath}" -f ${MSVSSCONSCRIPT.name}'
     env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
     env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
     env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.abspath}" -f ${MSVSSCONSCRIPT.name}'
     env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
-    env['MSVSBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
-    env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
-    env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c $MSVSBUILDTARGET'
+    env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
+    env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
+    env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"'
     env['MSVSENCODING'] = 'Windows-1252'
 
     env['MSVSENCODING'] = 'Windows-1252'
 
-    try:
-        version = get_default_visualstudio_version(env)
-        # keep a record of some of the MSVS info so the user can use it.
-        dirs = get_msvs_install_dirs(version)
-        env['MSVS'].update(dirs)
-    except (SCons.Util.RegError, SCons.Errors.InternalError):
-        # we don't care if we can't do this -- if we can't, it's
-        # because we don't have access to the registry, or because the
-        # tools aren't installed.  In either case, the user will have to
-        # find them on their own.
-        pass
+    # Set-up ms tools paths for default version
+    msvc_setup_env_once(env)
 
 
-    version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+    if 'MSVS_VERSION' in env:
+        version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+    else:
+        (version_num, suite) = (7.0, None) # guess at a default
+    if 'MSVS' not in env:
+        env['MSVS'] = {}
     if (version_num < 7.0):
         env['MSVS']['PROJECTSUFFIX']  = '.dsp'
         env['MSVS']['SOLUTIONSUFFIX'] = '.dsw'
     if (version_num < 7.0):
         env['MSVS']['PROJECTSUFFIX']  = '.dsp'
         env['MSVS']['SOLUTIONSUFFIX'] = '.dsw'
@@ -1734,19 +1394,10 @@ def generate(env):
     env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
 
 def exists(env):
     env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
 
 def exists(env):
-    try:
-        v = SCons.Tool.msvs.get_visualstudio_versions()
-    except (SCons.Util.RegError, SCons.Errors.InternalError):
-        pass
+    return msvc_exists()
 
 
-    if not v:
-        version_num = 6.0
-        if env.has_key('MSVS_VERSION'):
-            version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
-        if version_num >= 7.0:
-            return env.Detect('devenv')
-        else:
-            return env.Detect('msdev')
-    else:
-        # there's at least one version of MSVS installed.
-        return 1
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4: