Commits

Anonymous committed 254c3dd

Add MSVS Project file support. (Greg Spencer)

  • Participants
  • Parent commits 1cbc9ba

Comments (0)

Files changed (21)

 ./SCons/Tool/mslib.py
 ./SCons/Tool/mslink.py
 ./SCons/Tool/msvc.py
+./SCons/Tool/msvs.py
 ./SCons/Tool/nasm.py
 ./SCons/Tool/pdflatex.py
 ./SCons/Tool/pdftex.py
 .RE
 .fi
 ..
-.TH SCONS 1 "May 2003"
+.TH SCONS 1 "June 2003"
 .SH NAME
 scons \- a software construction tool
 .SH SYNOPSIS
 mslib
 mslink
 msvc
+msvs
 nasm
 pdflatex
 pdftex
 env.Program(target = 'foo', source = ['foo.o', 'bar.c', 'baz.f'])
 .EE
 
+.IP MSVSProject
+Builds Microsoft Visual Studio project files.
+.B scons
+will detect installed versions of Visual Studio
+up to and including versions 7.x (.NET).
+When one is detected,
+this builder will generate the correct
+project file
+.RI ( .vcproj
+or
+.IR .dsp )
+and solution file
+.RI ( .sln
+or
+.IR .dsw ).
+This builder takes a number of additional
+keyword arguments that supply information
+necessary to build the proper project files.
+Examples:
+
+.ES
+# For Visual Studio 7.0 or later (.NET).
+env.MSVSProject(target = 'Foo.vcproj',
+                slnguid = '{SLNGUID}',
+                srcs = ['foo.cpp'],
+                incs = ['sdk.h'],
+                localincs = ['foo.h'],
+                resources = ['foo.rc'],
+                misc = ['readme.txt'],
+                buildtarget = 'Foo.exe',
+                variant = 'Release')
+
+# For earlier Visual Studio versions.
+env.MSVSProject(target = 'Foo.dsp',
+                srcs = ['foo.cpp'],
+                incs = ['sdk.h'],
+                localincs = ['foo.h'],
+                resources = ['foo.rc'],
+                misc = ['readme.txt'],
+                buildtarget = 'Foo.exe',
+                variant = 'Release')
+.EE
+
 .IP RES
 Builds a Microsoft Visual C++ resource file.
 This builder is only provided
 .IP LINKCOM
 The command line used to link object files into an executable.
 
+.IP MSVSPROJECTCOM
+The action used to generate Microsoft Visual Studio
+project and solution files.
+
+.IP MSVSPROJECTSUFFIX
+The suffix used for Microsoft Visual Studio project (DSP) files.
+The default value is
+.B .vcproj
+when using Visual Studio version 7.x (.NET),
+and
+.B .dsp
+when using earlier versions of Visual Studio.
+
+.IP MSVSSOLUTIONSUFFIX
+The suffix used for Microsoft Visual Studio solution (DSW) files.
+The default value is
+.B .sln
+when using Visual Studio version 7.x (.NET),
+and
+.B .dsw
+when using earlier versions of Visual Studio.
+
 .IP no_import_lib
 When set to non-zero,
 suppresses creation of a corresponding Win32 static import lib by the
 if scons_exec:
     os.environ['SCONS_EXEC'] = '1'
 
+os.environ['SCONS_SCRIPT_DIR'] = scons_script_dir
 os.environ['SCONS_CWD'] = cwd
 
 os.environ['SCONS_VERSION'] = version
 
   - Fix use of the SConf subsystem with SConscriptChdir().
 
+  From Greg Spencer
+
+  - Check for the existence of MS Visual Studio on disk before using it,
+    to avoid getting fooled by leftover junk in the registry.
+
+  - Add support for MSVC++ .NET.
+
+  - Add support for MS Visual Studio project files (DSP, DSW,
+    SLN and VCPROJ files).
+
 
 
 RELEASE 0.14 - Wed, 21 May 2003 05:16:32 -0500
 
   Please note the following important changes since release 0.14:
 
-  -
+  - SCons now tries to verify that Microsoft Visual Studio (including
+    Visual C++) is actually installed before using it, by checking that
+    the program directory exists.  If SCons cannot find your copy of
+    Visual Studio, it is probably because it installed itself itself in
+    a default directory that we have not seen before.  If this is the
+    case, please let us know so that we can update future versions.
 
   Please note the following important changes since release 0.13:
 

src/engine/MANIFEST.in

 SCons/Tool/mslib.py
 SCons/Tool/mslink.py
 SCons/Tool/msvc.py
+SCons/Tool/msvs.py
 SCons/Tool/nasm.py
 SCons/Tool/pdflatex.py
 SCons/Tool/pdftex.py

src/engine/SCons/Environment.py

 """SCons.Environment
 
-XXX
+Base class for construction Environments.  These are
+the primary objects used to communicate dependency and
+construction information to the build engine.
 
+Keyword arguments supplied when the construction Environment
+is created are construction variables used to initialize the
+Environment 
 """
 
 #
 import copy
 import os
 import os.path
+import string
 import re
 import shutil
 from UserDict import UserDict
             else:
                 self._dict[key] = kw[key] + self._dict[key]
 
+    def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
+        """Prepend path elements to the path 'name' in the 'ENV'
+        dictionary for this environment.  Will only add any particular
+        path once, and will normpath and normcase all paths to help
+        assure this.  This can also handle the case where the env
+        variable is a list instead of a string.
+        """
+
+        orig = ''
+        if self._dict.has_key(envname) and self._dict[envname].has_key(name):
+            orig = self._dict[envname][name]
+
+        nv = SCons.Util.PrependPath(orig, newpath, sep)
+            
+        if not self._dict.has_key(envname):
+            self._dict[envname] = {}
+
+        self._dict[envname][name] = nv
+
+    def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
+        """Append path elements to the path 'name' in the 'ENV'
+        dictionary for this environment.  Will only add any particular
+        path once, and will normpath and normcase all paths to help
+        assure this.  This can also handle the case where the env
+        variable is a list instead of a string.
+        """
+
+        orig = ''
+        if self._dict.has_key(envname) and self._dict[envname].has_key(name):
+            orig = self._dict[envname][name]
+
+        nv = SCons.Util.AppendPath(orig, newpath, sep)
+            
+        if not self._dict.has_key(envname):
+            self._dict[envname] = {}
+
+        self._dict[envname][name] = nv
+
+
     def	Depends(self, target, dependency):
 	"""Explicity specify that 'target's depend on 'dependency'."""
         tlist = SCons.Node.arg2nodes(target, self.fs.File)

src/engine/SCons/EnvironmentTests.py

         assert hasattr(env4, 'z1')
         assert hasattr(env4, 'z2')
 
+    def test_PrependENVPath(self):
+        """Test prepending to an ENV path."""
+        env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+                           MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+        # have to include the pathsep here so that the test will work on UNIX too.
+        env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') 
+        env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
+        assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+        assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
+    def test_AppendENVPath(self):
+        """Test appending to an ENV path."""
+        env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+                           MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+        # have to include the pathsep here so that the test will work on UNIX too.
+        env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
+        env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
+        env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
+        env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
+        assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+        assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+
+    def test_AppendENVPath(self):
+        """Test prepending to an ENV path."""
+        env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+                           MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+        # have to include the pathsep here so that the test will work on UNIX too.
+        env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';') 
+        env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
+        env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
+        assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+        assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
+    def test_AppendENVPath(self):
+        """Test appending to an ENV path."""
+        env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+                           MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+        # have to include the pathsep here so that the test will work on UNIX too.
+        env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
+        env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
+        env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
+        env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
+        assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+        assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+
     def test_Depends(self):
 	"""Test the explicit Depends method."""
 	env = Environment()

src/engine/SCons/Platform/win32.py

             # a bug in Win32 that will use a forward slash as a path
             # delimiter.  Win32's link mistakes that for a command line
             # switch and barfs.
-            #
-            # We use the .lnk suffix for the benefit of the Phar Lap
-            # linkloc linker, which likes to append an .lnk suffix if
-            # none is given.
-            tmp = os.path.normpath(tempfile.mktemp('.lnk'))
+            tmp = os.path.normpath(tempfile.mktemp())
             native_tmp = SCons.Util.get_native_path(tmp)
 
             # The sh shell will try to escape the backslashes in the
             sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
         return ret
 
-# Windows does not allow special characters in file names
-# anyway, so no need for an escape function, we will just quote
-# the arg.
-escape = lambda x: '"' + x + '"'
+# We just quote the arg here, but since the escape for a double
+# quote in the command processor (I hesitate to call it a shell :-) is
+# to double it (i.e. '""' => '"' in the command processor), we have to
+# make sure not to double any double quotes on the ends.
+def escape(x):
+    first = '"'
+    last = '"'
+    if x and x[0] == '"':
+        first = '" '
+    if x and x[-1] == '"':
+        last = ' "'
+    return first + x + last
 
 # Get the windows system directory name
 def get_system_root():
                 cmd_interp = os.path.join(val, 'command.com')
             except:
                 pass
+
+    # For the special case of not having access to the registry, we
+    # use a temporary path and pathext to attempt to find the command
+    # interpreter.  If we fail, we try to find the interpreter through
+    # the env's PATH.  The problem with that is that it might not
+    # contain an ENV and a PATH.
+    if not cmd_interp:
+        systemroot = r'C:\Windows'
+        if os.environ.has_key('SYSTEMROOT'):
+            systemroot = os.environ['SYSTEMROOT']
+        tmp_path = systemroot + os.pathsep + \
+                   os.path.join(systemroot,'System32')
+        tmp_pathext = '.com;.exe;.bat;.cmd'
+        if os.environ.has_key('PATHEXT'):
+            tmp_pathext = os.environ['PATHEXT'] 
+        cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
+        if not cmd_interp:
+            cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
+
     if not cmd_interp:
         cmd_interp = env.Detect('cmd')
         if not cmd_interp:
             cmd_interp = env.Detect('command')
+
     
     if not env.has_key('ENV'):
         env['ENV']        = {}

src/engine/SCons/Script/SConscript.py

 
 class Frame:
     """A frame on the SConstruct/SConscript call stack"""
-    def __init__(self, exports):
+    def __init__(self, exports, sconscript):
         self.globals = BuildDefaultGlobals()
         self.retval = None 
         self.prev_dir = SCons.Node.FS.default_fs.getcwd()
         self.exports = compute_exports(exports)  # exports from the calling SConscript
+        # make sure the sconscript attr is a Node.
+        if isinstance(sconscript, SCons.Node.Node):
+            self.sconscript = sconscript
+        else:
+            self.sconscript = SCons.Node.FS.default_fs.File(str(sconscript))
         
 # the SConstruct/SConscript call stack:
 stack = []
     # evaluate each SConscript file
     results = []
     for fn in files:
-        stack.append(Frame(exports))
+        stack.append(Frame(exports,fn))
         old_sys_path = sys.path
         try:
             if fn == "-":

src/engine/SCons/Tool/__init__.py

     other_tools = FindAllTools(['BitKeeper', 'CVS',
                                 'dvipdf', 'dvips', 'gs',
                                 'jar', 'javac', 'javah',
-                                'latex', 'lex', 'midl',
+                                'latex', 'lex', 'midl', 'msvs',
                                 'pdflatex', 'pdftex', 'Perforce',
                                 'RCS', 'rmic', 'SCCS',
                                 # 'Subversion',

src/engine/SCons/Tool/mslib.py

 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 import SCons.Defaults
+import SCons.Tool.msvs
+import SCons.Tool.msvc
 
 def generate(env):
     """Add Builders and construction variables for lib to an Environment."""
     env['BUILDERS']['Library'] = SCons.Defaults.StaticLibrary
     env['BUILDERS']['StaticLibrary'] = SCons.Defaults.StaticLibrary
-    
+
+    version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+
+    if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+        include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(version)
+    else:
+        include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+
+    # since other tools can set this, we just make sure that the
+    # relevant stuff from MSVS is in there somewhere.
+    env.PrependENVPath('PATH', exe_path)
+
     env['AR']          = 'lib'
     env['ARFLAGS']     = '/nologo'
     env['ARCOM']       = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
 
 def exists(env):
-    return env.Detect('lib')
+    if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+        return env.Detect('lib')
+    else:
+        # there's at least one version of MSVS installed.
+        return True

src/engine/SCons/Tool/mslink.py

 import SCons.Defaults
 import SCons.Errors
 import SCons.Util
-import msvc
-
-from SCons.Tool.msvc import get_msdev_paths
+import SCons.Tool.msvs
+import SCons.Tool.msvc
+import SCons.Platform.win32
 
 def pdbGenerator(env, target, source, for_signature):
     if target and env.has_key('PDB') and env['PDB']:
     return listCmd
     
 def win32LibEmitter(target, source, env):
-    msvc.validate_vars(env)
+    SCons.Tool.msvc.validate_vars(env)
     
     dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
     no_import_lib = env.get('no_import_lib', 0)
     return (target, source)
 
 def prog_emitter(target, source, env):
-    msvc.validate_vars(env)
+    SCons.Tool.msvc.validate_vars(env)
     
     if env.has_key('PDB') and env['PDB']:
         env.SideEffect(env['PDB'], target)
     env['WIN32EXPSUFFIX']        = '.exp'
 
     env['REGSVRACTION'] = regServerCheck
-    env['REGSVR'] = 'regsvr32'
+    env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
     env['REGSVRFLAGS'] = '/s '
     env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
 
-    if SCons.Util.can_read_reg:
-        include_path, lib_path, exe_path = get_msdev_paths()
-        env['ENV']['LIB']            = lib_path
-        env['ENV']['PATH']           = exe_path
+    version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+    
+    if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+        include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(version)
+    else:
+        include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+
+    # since other tools can set these, we just make sure that the
+    # relevant stuff from MSVS is in there somewhere.
+    env.PrependENVPath('INCLUDE', include_path)
+    env.PrependENVPath('LIB', lib_path)
+    env.PrependENVPath('PATH', exe_path)
 
 def exists(env):
-    return env.Detect('link')
+    if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+        return env.Detect('link')
+    else:
+        # there's at least one version of MSVS installed.
+        return True

src/engine/SCons/Tool/msvc.py

 
 import os.path
 import string
+import types
+import re
 
 import SCons.Action
 import SCons.Tool
 import SCons.Errors
+import SCons.Warnings
 import SCons.Builder
 import SCons.Util
 import SCons.Platform.win32
+import SCons.Tool.msvs
 
 CSuffixes = ['.c', '.C']
 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
 
-def get_devstudio_versions():
-    """
-    Get list of devstudio versions from the Windows registry.  Return a
-    list of strings containing version numbers; an exception will be raised
-    if we were unable to access the registry (eg. couldn't import
-    a registry-access module) or the appropriate registry keys weren't
-    found.
-    """
-
+def _parse_msvc7_overrides(version):
+    """ Parse any overridden defaults for MSVS directory locations in MSVS .NET. """
+    
+    # First, we get the shell folder for this user:
     if not SCons.Util.can_read_reg:
         raise SCons.Errors.InternalError, "No Windows registry module was found"
 
-    K = 'Software\\Microsoft\\Devstudio'
-    L = []
-    for base in (SCons.Util.HKEY_CLASSES_ROOT,
-                 SCons.Util.HKEY_LOCAL_MACHINE,
-                 SCons.Util.HKEY_CURRENT_USER,
-                 SCons.Util.HKEY_USERS):
+    comps = ""
+    try:
+        (comps, t) = SCons.Util.RegGetValue(SCons.Util.HKEY_CURRENT_USER,
+                                            r'Software\Microsoft\Windows\CurrentVersion' +\
+                                            r'\Explorer\Shell Folders\Local AppData')
+    except SCons.Util.RegError:
+        raise SCons.Errors.InternalError, "The Local AppData directory was not found in the registry."
+
+    comps = comps + '\\Microsoft\\VisualStudio\\' + version + '\\VSComponents.dat'
+    dirs = {}
+
+    if os.path.exists(comps):
+        # now we parse the directories from this file, if it exists.
+        # We only look for entries after: [VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories],
+        # since this file could contain a number of things...
+        f = open(comps,'r')
+        line = f.readline()
+        found = 0
+        while line:
+            line.strip()
+            if found == 1:
+                (key, val) = line.split('=',1)
+                key = key.replace(' Dirs','')
+                dirs[key.upper()] = val
+            if line.find(r'[VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]') >= 0:
+                found = 1
+            if line == '':
+                found = 0
+            line = f.readline()
+        f.close()
+    else:
+        # since the file didn't exist, we have only the defaults in
+        # the registry to work with.
         try:
-            k = SCons.Util.RegOpenKeyEx(base,K)
+            K = 'SOFTWARE\\Microsoft\\VisualStudio\\' + version
+            K = K + r'\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories'
+            k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,K)
             i = 0
             while 1:
                 try:
-                    p = SCons.Util.RegEnumKey(k,i)
-                    if p[0] in '123456789' and p not in L:
-                        L.append(p)
+                    (key,val,t) = SCons.Util.RegEnumValue(k,i)
+                    key = key.replace(' Dirs','')
+                    dirs[key.upper()] = val
+                    i = i + 1
                 except SCons.Util.RegError:
                     break
-                i = i + 1
         except SCons.Util.RegError:
-            pass
+            # if we got here, then we didn't find the registry entries:
+            raise SCons.Errors.InternalError, "Unable to find MSVC paths in the registry."
+    return dirs
 
-    if not L:
-        raise SCons.Errors.InternalError, "DevStudio was not found."
+def _get_msvc7_path(path, version, platform):
+    """
+    Get Visual Studio directories from version 7 (MSVS .NET)
+    (it has a different registry structure than versions before it)
+    """
+    # first, look for a customization of the default values in the
+    # registry: These are sometimes stored in the Local Settings area
+    # for Visual Studio, in a file, so we have to parse it.
+    dirs = _parse_msvc7_overrides(version)
 
-    L.sort()
-    L.reverse()
-    return L
+    if dirs.has_key(path):
+        p = dirs[path]
+    else:
+        raise SCons.Errors.InternalError, "Unable to retrieve the %s path from MS VC++."%path
+
+    # collect some useful information for later expansions...
+    paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+
+    # expand the directory path variables that we support.  If there
+    # is a variable we don't support, then replace that entry with
+    # "---Unknown Location VSInstallDir---" or something similar, to clue
+    # people in that we didn't find something, and so env expansion doesn't
+    # do weird things with the $(xxx)'s
+    s = re.compile('\$\(([a-zA-Z0-9_]+?)\)')
+
+    def repl(match):
+        key = string.upper(match.group(1))
+        if paths.has_key(key):
+            return paths[key]
+        else:
+            return '---Unknown Location %s---' % match.group()
+
+    rv = []
+    for entry in p.split(os.pathsep):
+        entry = s.sub(repl,entry)
+        rv.append(entry)
+
+    return string.join(rv,os.pathsep)
 
 def get_msvc_path (path, version, platform='x86'):
     """
-    Get a list of devstudio directories (include, lib or path).  Return
+    Get a list of visualstudio directories (include, lib or path).  Return
     a string delimited by ';'. An exception will be raised if unable to
     access the registry or appropriate registry keys not found.
     """
     if not SCons.Util.can_read_reg:
         raise SCons.Errors.InternalError, "No Windows registry module was found"
 
-    if path=='lib':
-        path= 'Library'
+    # normalize the case for comparisons (since the registry is case
+    # insensitive)
+    path = string.upper(path)
+
+    if path=='LIB':
+        path= 'LIBRARY'
+
+    if float(version) >= 7.0:
+        return _get_msvc7_path(path, version, platform)
+
     path = string.upper(path + ' Dirs')
     K = ('Software\\Microsoft\\Devstudio\\%s\\' +
          'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
         (version,platform)
-    for base in (SCons.Util.HKEY_CLASSES_ROOT,
-                 SCons.Util.HKEY_LOCAL_MACHINE,
-                 SCons.Util.HKEY_CURRENT_USER,
-                 SCons.Util.HKEY_USERS):
+    for base in (SCons.Util.HKEY_CURRENT_USER,
+                 SCons.Util.HKEY_LOCAL_MACHINE):
         try:
             k = SCons.Util.RegOpenKeyEx(base,K)
             i = 0
             pass
 
     # if we got here, then we didn't find the registry entries:
-    raise SCons.Errors.InternalError, "%s was not found in the registry."%path
+    raise SCons.Errors.InternalError, "The %s path was not found in the registry."%path
 
-def get_msdev_dir(version):
-    """Returns the root directory of the MSDev installation from the
-    registry if it can be found, otherwise we guess."""
-    if SCons.Util.can_read_reg:
-        K = ('Software\\Microsoft\\Devstudio\\%s\\' +
-             'Products\\Microsoft Visual C++') % \
-             version
-        for base in (SCons.Util.HKEY_LOCAL_MACHINE,
-                     SCons.Util.HKEY_CURRENT_USER):
-            try:
-                k = SCons.Util.RegOpenKeyEx(base,K)
-                val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir')
-                return os.path.split(val)[0]
-            except SCons.Util.RegError:
-                pass
+def _get_msvc6_default_paths(version):
+    """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+    three environment variables that should be set in order to execute
+    the MSVC 6.0 tools properly, if the information wasn't available
+    from the registry."""
+    MVSdir = None
+    paths = {}
+    exe_path = ''
+    lib_path = ''
+    include_path = ''
+    try:
+        paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+        MVSdir = paths['VSINSTALLDIR']
+    except (SCons.Util.RegError, SCons.Errors.InternalError):
+        if os.environ.has_key('MSDEVDIR'):
+            MVSdir = os.path.normpath(os.path.join(os.environ['MSDEVDIR'],'..','..'))
+        else:
+            MVSdir = r'C:\Program Files\Microsoft Visual Studio'
+    if MVSdir:
+        if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'):
+            MVSVCdir = paths['VCINSTALLDIR']
+        else:
+            MVSVCdir = os.path.join(MVSdir,'VC98')
 
-def get_msdev_paths(version=None):
+        MVSCommondir = r'%s\Common' % MVSdir
+        include_path = r'%s\ATL\include;%s\MFC\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
+        lib_path = r'%s\MFC\lib;%s\lib' % (MVSVCdir, MVSVCdir)
+        exe_path = r'%s\MSDev98\bin;%s\bin' % (MVSCommondir, MVSVCdir)
+    return (include_path, lib_path, exe_path)
+
+def _get_msvc7_default_paths(version):
+    """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+    three environment variables that should be set in order to execute
+    the MSVC .NET tools properly, if the information wasn't available
+    from the registry."""
+            
+    MVSdir = None
+    paths = {}
+    exe_path = ''
+    lib_path = ''
+    include_path = ''
+    try:
+        paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+        MVSdir = paths['VSINSTALLDIR']
+    except (KeyError, SCons.Util.RegError, SCons.Errors.InternalError):
+        if os.environ.has_key('VSCOMNTOOLS'):
+            MVSdir = os.path.normpath(os.path.join(os.environ['VSCOMNTOOLS'],'..','..'))
+        else:
+            # last resort -- default install location
+            MVSdir = r'C:\Program Files\Microsoft Visual Studio .NET'
+
+    if not MVSdir:
+        if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'):
+            MVSVCdir = paths['VCINSTALLDIR']
+        else:
+            MVSVCdir = os.path.join(MVSdir,'Vc7')
+
+        MVSCommondir = r'%s\Common7' % MVSdir
+        include_path = r'%s\atlmfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
+        lib_path = r'%s\atlmfc\lib;%s\lib' % (MVSVCdir, MVSVCdir)
+        exe_path = r'%s\Tools\bin;%s\Tools;%s\bin' % (MVSCommondir, MVSCommondir, MVSVCdir)
+    return (include_path, lib_path, exe_path)
+
+def get_msvc_paths(version=None):
     """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values
     of those three environment variables that should be set
     in order to execute the MSVC tools properly."""
     exe_path = ''
     lib_path = ''
     include_path = ''
+
+    if not version and not SCons.Util.can_read_reg:
+        version = '6.0'
+            
     try:
         if not version:
-            version = get_devstudio_versions()[0] #use highest version
+            version = get_visualstudio_versions()[0] #use highest version
+
         include_path = get_msvc_path("include", version)
         lib_path = get_msvc_path("lib", version)
-        exe_path = get_msvc_path("path", version) + ";" + os.environ['PATH']
+        exe_path = get_msvc_path("path", version)
+
     except (SCons.Util.RegError, SCons.Errors.InternalError):
-        # Could not get the configured directories from the registry.
-        # However, the configured directories only appear if the user
-        # changes them from the default.  Therefore, we'll see if
-        # we can get the path to the MSDev base installation from
-        # the registry and deduce the default directories.
-        MVSdir = None
-        if version:
-            MVSdir = get_msdev_dir(version)
-        if MVSdir:
-            MVSVCdir = r'%s\VC98' % MVSdir
-            MVSCommondir = r'%s\Common' % MVSdir
-            include_path = r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
-            lib_path = r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir)
-            try:
-                extra_path = os.pathsep + os.environ['PATH']
-            except KeyError:
-                extra_path = ''
-            exe_path = (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path
+        # Could not get all the configured directories from the
+        # registry.  However, some of the configured directories only
+        # appear if the user changes them from the default.
+        # Therefore, we'll see if we can get the path to the MSDev
+        # base installation from the registry and deduce the default
+        # directories.
+        if float(version) >= 7.0:
+            return _get_msvc7_default_paths(version)
         else:
-            # The DevStudio environment variables don't exist,
-            # so just use the variables from the source environment.
-            progfiles = SCons.Platform.win32.get_program_files_dir()
-            MVSdir = os.path.join(progfiles,r'Microsoft Visual Studio')
-            MVSVCdir = r'%s\VC98' % MVSdir
-            MVSCommondir = r'%s\Common' % MVSdir
-            try:
-                include_path = os.environ['INCLUDE']
-            except KeyError:
-                include_path = ''
-            try:
-                lib_path = os.environ['LIB']
-            except KeyError:
-                lib_path = ''
-            try:
-                exe_path = os.environ['PATH']
-            except KeyError:
-                exe_path = ''
+            return _get_msvc6_default_paths(version)
+            
     return (include_path, lib_path, exe_path)
 
+def get_msvc_default_paths(version = None):
+    """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+    three environment variables that should be set in order to execute
+    the MSVC tools properly.  This will only return the default
+    locations for the tools, not the values used by MSVS in their
+    directory setup area.  This can help avoid problems with different
+    developers having different settings, and should allow the tools
+    to run in most cases."""
+
+    if not version and not SCons.Util.can_read_reg:
+        version = '6.0'
+
+    try:
+        if not version:
+            version = get_visualstudio_versions()[0] #use highest version
+    except:
+        pass
+
+    if float(version) >= 7.0:
+        return _get_msvc7_default_paths(version)
+    else:
+        return _get_msvc6_default_paths(version)
+
 def validate_vars(env):
     """Validate the PDB, PCH, and PCHSTOP construction variables."""
     if env.has_key('PCH') and env['PCH']:
         CScan.add_skey('.rc')
     env['BUILDERS']['RES'] = res_builder
 
-    if SCons.Util.can_read_reg:
-        include_path, lib_path, exe_path = get_msdev_paths()
-        env['ENV']['INCLUDE'] = include_path
-        env['ENV']['PATH']    = exe_path
+    version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+
+    if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+        include_path, lib_path, exe_path = get_msvc_default_paths(version)
+    else:
+        include_path, lib_path, exe_path = get_msvc_paths(version)
+
+    # since other tools can set these, we just make sure that the
+    # relevant stuff from MSVS is in there somewhere.
+    env.PrependENVPath('INCLUDE', include_path)
+    env.PrependENVPath('LIB', lib_path)
+    env.PrependENVPath('PATH', exe_path)
 
     env['CFILESUFFIX'] = '.c'
     env['CXXFILESUFFIX'] = '.cc'
     env['BUILDERS']['PCH'] = pch_builder
 
 def exists(env):
-    return env.Detect('cl')
+    if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+        return env.Detect('cl')
+    else:
+        # there's at least one version of MSVS installed.
+        return True

src/engine/SCons/Tool/msvs.py

+"""SCons.Tool.msvs
+
+Tool-specific initialization for Microsoft Visual Studio project files.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import base64
+import md5
+import os.path
+import pickle
+import re
+import string
+import sys
+import types
+
+import SCons.Builder
+import SCons.Node.FS
+import SCons.Platform.win32
+import SCons.Script.SConscript
+import SCons.Util
+import SCons.Warnings
+
+##############################################################################
+# 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 _generateGUID(slnfile, name):
+    """This generates a dummy GUID for the sln file to use.  It is
+    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()
+    # convert most of the signature to GUID form (discard the rest)
+    solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:28] + "}"
+    return solution
+
+class Config:
+    pass
+
+class _DSPGenerator:
+    """ Base class for DSP generators """
+    def __init__(self, dspfile, source, env):
+        if type(dspfile) == types.StringType:
+            self.dspfile = os.path.abspath(dspfile)
+        else:
+            self.dspfile = dspfile.get_abspath()
+
+        try:
+            self.conspath = source[0].attributes.sconstruct.get_abspath()
+        except KeyError:
+            raise SCons.Errors.InternalError, \
+                  "Unable to determine where the SConstruct is"
+
+        self.config = Config()
+        if env.has_key('variant'):
+            self.config.variant = env['variant'].capitalize()
+        else:
+            raise SCons.Errors.InternalError, \
+                  "You must specify a 'variant' argument (i.e. 'Debug' or " +\
+                  "'Release') to create an MSVSProject."
+
+        if env.has_key('buildtarget'):
+            if type(env['buildtarget']) == types.StringType:
+                self.config.buildtarget = os.path.abspath(env['buildtarget'])
+            elif type(env['buildtarget']) == types.ListType:
+                self.config.buildtarget = env['buildtarget'][0].get_abspath()
+            else:
+                self.config.buildtarget = env['buildtarget'].get_abspath()
+        else:
+            raise SCons.Errors.InternalError, \
+                  "You must specify a target 'buildtarget' file argument (such as the target" +\
+                  " executable) to create an MSVSProject."
+
+        self.config.outdir = os.path.dirname(self.config.buildtarget)
+
+        if type(source[0]) == types.StringType:
+            self.source = os.path.abspath(source[0])
+        else:
+            self.source = source[0].get_abspath()
+            
+        self.env = env
+
+        if self.env.has_key('name'):
+            self.name = self.env['name']
+        else:
+            self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+
+        print "Adding '" + self.name + ' - ' + self.config.variant + "' to Visual Studio Project '" + str(dspfile) + "'"
+
+        sourcenames = [
+            ' Source Files',
+            'Header Files',
+            'Local Headers',
+            'Resource Files',
+            'Other Files']
+
+        srcargs = [
+            'srcs',
+            'incs',
+            'localincs',
+            'resources',
+            'misc']
+
+        self.sources = {}
+        for n in sourcenames:
+            self.sources[n] = []
+
+        self.configs = {}
+
+        if os.path.exists(self.dspfile):
+            self.Parse()
+
+        for t in zip(sourcenames,srcargs):
+            if self.env.has_key(t[1]):
+                if type(self.env[t[1]]) == types.ListType:
+                    for i in self.env[t[1]]:
+                        if not i in self.sources[t[0]]:
+                            self.sources[t[0]].append(i)
+                else:
+                    if not self.env[t[1]] in self.sources[t[0]]:
+                        self.sources[t[0]].append(self.env[t[1]])
+
+        for n in sourcenames:
+            self.sources[n].sort()
+
+        self.configs[self.config.variant] = self.config
+
+    def Build(self):
+        pass
+        
+class _GenerateV6DSP(_DSPGenerator):
+    """Generates a Project file for MSVS 6.0"""
+
+    def PrintHeader(self):
+        name = self.name
+        # pick a default config
+        confkeys = self.configs.keys()
+        confkeys.sort()
+
+        self.file.write('# Microsoft Developer Studio Project File - Name="%s" - Package Owner=<4>\n'
+                        '# Microsoft Developer Studio Generated Build File, Format Version 6.00\n'
+                        '# ** DO NOT EDIT **\n\n'
+                        '# TARGTYPE "Win32 (x86) External Target" 0x0106\n\n'
+                        'CFG=%s - Win32 %s\n'
+                        '!MESSAGE This is not a valid makefile. To build this project using NMAKE,\n'
+                        '!MESSAGE use the Export Makefile command and run\n'
+                        '!MESSAGE \n'
+                        '!MESSAGE NMAKE /f "%s.mak".\n'
+                        '!MESSAGE \n'
+                        '!MESSAGE You can specify a configuration when running NMAKE\n'
+                        '!MESSAGE by defining the macro CFG on the command line. For example:\n'
+                        '!MESSAGE \n'
+                        '!MESSAGE NMAKE /f "%s.mak" CFG="%s - Win32 %s"\n'
+                        '!MESSAGE \n'
+                        '!MESSAGE Possible choices for configuration are:\n'
+                        '!MESSAGE \n' % (name,name,confkeys[0],name,name,name,confkeys[0]))
+
+        for kind in confkeys:
+            self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind))
+            
+        self.file.write('!MESSAGE \n\n')
+
+    def PrintProject(self):
+        name = self.name
+        self.file.write('# Begin Project\n'
+                        '# PROP AllowPerConfigDependencies 0\n'
+                        '# PROP Scc_ProjName ""\n'
+                        '# PROP Scc_LocalPath ""\n\n')
+
+        first = 1
+        confkeys = self.configs.keys()
+        confkeys.sort()
+        for kind in confkeys:
+            outdir = self.configs[kind].outdir
+            buildtarget = self.configs[kind].buildtarget
+            if first == 1:
+                self.file.write('!IF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
+                first = 0
+            else:
+                self.file.write('\n!ELSEIF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
+
+            # have to write this twice, once with the BASE settings, and once without
+            for base in ("BASE ",""):
+                self.file.write('# PROP %sUse_MFC 0\n'
+                                '# PROP %sUse_Debug_Libraries ' % (base, base))
+                if kind.lower().find('debug') < 0:
+                    self.file.write('0\n')
+                else:
+                    self.file.write('1\n')
+                self.file.write('# PROP %sOutput_Dir "%s"\n'
+                                '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir))
+                (d,c) = os.path.split(str(self.conspath))
+                cmd = '%s %s -C %s -f %s %s' % (sys.executable, os.path.normpath(sys.argv[0]), d, c, buildtarget)
+                self.file.write('# PROP %sCmd_Line "%s"\n' 
+                                '# PROP %sRebuild_Opt "-c && %s"\n'
+                                '# PROP %sTarget_File "%s"\n'
+                                '# PROP %sBsc_Name ""\n'
+                                '# PROP %sTarget_Dir ""\n'\
+                                %(base,cmd,base,cmd,base,buildtarget,base,base))
+            
+        self.file.write('\n!ENDIF\n\n'
+                        '# Begin Target\n\n')
+        for kind in confkeys:
+            self.file.write('# Name "%s - Win32 %s"\n' % (name,kind))
+        self.file.write('\n')
+        first = 0
+        for kind in confkeys:
+            if first == 0:
+                self.file.write('!IF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
+                first = 1
+            else:
+                self.file.write('!ELSEIF  "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
+        self.file.write('!ENDIF \n\n')
+        self.PrintSourceFiles()
+        self.file.write('# End Target\n'
+                        '# End Project\n')
+        
+        # now we pickle some data and add it to the file -- MSDEV will ignore it.
+        pdata = pickle.dumps(self.configs,True)
+        pdata = base64.encodestring(pdata)
+        self.file.write(pdata + '\n')
+        pdata = pickle.dumps(self.sources,True)
+        pdata = base64.encodestring(pdata)
+        self.file.write(pdata + '\n')
+  
+    def PrintSourceFiles(self):
+        categories = {' Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat',
+                      'Header Files': 'h|hpp|hxx|hm|inl',
+                      'Local Headers': 'h|hpp|hxx|hm|inl',
+                      'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe',
+                      'Other Files': ''}
+
+        cats = categories.keys()
+        cats.sort()
+        for kind in cats:
+            if not self.sources[kind]:
+                continue # skip empty groups
+            
+            self.file.write('# Begin Group "' + kind + '"\n\n')
+            typelist = categories[kind].replace('|',';')
+            self.file.write('# PROP Default_Filter "' + typelist + '"\n')
+            
+            for file in self.sources[kind]:
+                file = os.path.normpath(file)
+                self.file.write('# Begin Source File\n\n'
+                                'SOURCE="' + file + '"\n'
+                                '# End Source File\n')
+            self.file.write('# End Group\n')
+
+        # add the Conscript file outside of the groups
+        self.file.write('# Begin Source File\n\n'
+                        'SOURCE="' + str(self.source) + '"\n'
+                        '# End Source File\n')
+
+    def Parse(self):
+        try:
+            dspfile = file(self.dspfile,'r')
+        except IOError:
+            return # doesn't exist yet, so can't add anything to configs.
+
+        line = dspfile.readline()
+        while line:
+            if line.find("# End Project") > -1:
+                break
+            line = dspfile.readline()
+
+        line = dspfile.readline()
+        datas = line
+        while line and line != '\n':
+            line = dspfile.readline()
+            datas = datas + line
+
+        # OK, we've found our little pickled cache of data.
+        try:
+            datas = base64.decodestring(datas)
+            data = pickle.loads(datas)
+        except:
+            return # unable to unpickle any data for some reason
+
+        self.configs.update(data)
+
+        data = None
+        line = dspfile.readline()
+        datas = line
+        while line and line != '\n':
+            line = dspfile.readline()
+            datas = datas + line
+
+        # OK, we've found our little pickled cache of data.
+        # it has a "# " in front of it, so we strip that.
+        try:
+            datas = base64.decodestring(datas)
+            data = pickle.loads(datas)
+        except:
+            return # unable to unpickle any data for some reason
+
+        self.sources.update(data)
+    
+    def Build(self):
+        try:
+            self.file = file(self.dspfile,'w')
+        except IOError, detail:
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+        else:
+            self.PrintHeader()
+            self.PrintProject()
+            self.file.close()
+
+class _GenerateV7DSP(_DSPGenerator):
+    """Generates a Project file for MSVS .NET"""
+
+    def PrintHeader(self):
+        self.file.write('<?xml version="1.0" encoding = "Windows-1252"?>\n'
+                        '<VisualStudioProject\n'
+                        '	ProjectType="Visual C++"\n'
+                        '	Version="7.00"\n'
+                        '	Name="%s"\n'
+                        '	SccProjectName=""\n'
+                        '	SccLocalPath=""\n'
+                        '	Keyword="MakeFileProj">\n'
+                        '	<Platforms>\n'
+                        '		<Platform\n'
+                        '			Name="Win32"/>\n'
+                        '	</Platforms>\n' % self.name)
+
+    def PrintProject(self):
+        
+
+        self.file.write('	<Configurations>\n')
+
+        first = 1
+        confkeys = self.configs.keys()
+        confkeys.sort()
+        for kind in confkeys:
+            outdir = self.configs[kind].outdir
+            buildtarget = self.configs[kind].buildtarget
+
+            (d,c) = os.path.split(str(self.conspath))
+            cmd = '%s %s -C %s -f %s %s\n' % (sys.executable,\
+                                              os.path.normpath(sys.argv[0]),\
+                                              d,c,buildtarget)
+
+            cleancmd = '%s %s -C %s -f %s -c %s' % (sys.executable,\
+                                                    os.path.normpath(sys.argv[0]),\
+                                                    d,c,buildtarget)
+
+            self.file.write('		<Configuration\n'
+                            '			Name="%s|Win32"\n'
+                            '			OutputDirectory="%s"\n'
+                            '			IntermediateDirectory="%s"\n'
+                            '			ConfigurationType="0"\n'
+                            '			UseOfMFC="0"\n'
+                            '			ATLMinimizesCRunTimeLibraryUsage="FALSE">\n'
+                            '			<Tool\n'
+                            '				Name="VCNMakeTool"\n'
+                            '				BuildCommandLine="%s"\n'
+                            '				CleanCommandLine="%s"\n'
+                            '				RebuildCommandLine="%s"\n'
+                            '				Output="%s"/>\n'
+                            '		</Configuration>\n' % (kind.capitalize(),outdir,outdir,\
+                                                               cmd,cleancmd,cmd,buildtarget))
+            
+        self.file.write('	</Configurations>\n')
+
+        self.PrintSourceFiles()
+
+        self.file.write('</VisualStudioProject>\n')
+
+        # now we pickle some data and add it to the file -- MSDEV will ignore it.
+        pdata = pickle.dumps(self.configs,True)
+        pdata = base64.encodestring(pdata)
+        self.file.write('<!-- SCons Data:\n' + pdata + '\n')
+        pdata = pickle.dumps(self.sources,True)
+        pdata = base64.encodestring(pdata)
+        self.file.write(pdata + '-->\n')
+  
+    def PrintSourceFiles(self):
+        categories = {' Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
+                      'Header Files': 'h;hpp;hxx;hm;inl',
+                      'Local Headers': 'h;hpp;hxx;hm;inl',
+                      'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe',
+                      'Other Files': ''}
+
+        self.file.write('	<Files>\n')
+        
+        cats = categories.keys()
+        cats.sort()
+        for kind in cats:
+            if not self.sources[kind]:
+                continue # skip empty groups
+
+            self.file.write('		<Filter\n'
+                            '			Name="%s"\n'
+                            '			Filter="%s">\n' % (kind, categories[kind]))
+            
+            for file in self.sources[kind]:
+                file = os.path.normpath(file)
+                self.file.write('			<File\n'
+                                '				RelativePath="%s">\n'
+                                '			</File>\n' % file)
+
+            self.file.write('		</Filter>\n')
+
+        # add the Conscript file outside of the groups
+        self.file.write('		<File\n'
+                        '			RelativePath="%s">\n'
+                        '		</File>\n'
+                        '	</Files>\n'
+                        '	<Globals>\n'
+                        '	</Globals>\n' % str(self.source))
+
+    def Parse(self):
+        try:
+            dspfile = file(self.dspfile,'r')
+        except IOError:
+            return # doesn't exist yet, so can't add anything to configs.
+
+        line = dspfile.readline()
+        while line:
+            if line.find('<!-- SCons Data:') > -1:
+                break
+            line = dspfile.readline()
+
+        line = dspfile.readline()
+        datas = line
+        while line and line != '\n':
+            line = dspfile.readline()
+            datas = datas + line
+
+        # OK, we've found our little pickled cache of data.
+        try:
+            datas = base64.decodestring(datas)
+            data = pickle.loads(datas)
+        except:
+            return # unable to unpickle any data for some reason
+
+        self.configs.update(data)
+
+        data = None
+        line = dspfile.readline()
+        datas = line
+        while line and line != '\n':
+            line = dspfile.readline()
+            datas = datas + line
+
+        # OK, we've found our little pickled cache of data.
+        try:
+            datas = base64.decodestring(datas)
+            data = pickle.loads(datas)
+        except:
+            return # unable to unpickle any data for some reason
+
+        self.sources.update(data)
+    
+    def Build(self):
+        try:
+            self.file = file(self.dspfile,'w')
+        except IOError, detail:
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+        else:
+            self.PrintHeader()
+            self.PrintProject()
+            self.file.close()
+
+class _DSWGenerator:
+    """ Base class for DSW generators """
+    def __init__(self, dswfile, dspfile, source, env):
+        self.dswfile = os.path.normpath(str(dswfile))
+        self.dspfile = os.path.abspath(str(dspfile))
+        self.env = env
+
+        if self.env.has_key('name'):
+            self.name = self.env['name']
+        else:
+            self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+
+    def Build(self):
+        pass
+
+class _GenerateV7DSW(_DSWGenerator):
+    """Generates a Solution file for MSVS .NET"""
+    def __init__(self, dswfile, dspfile, source, env):
+        _DSWGenerator.__init__(self, dswfile,dspfile,source,env)
+
+        if env.has_key('slnguid') and env['slnguid']:
+            self.slnguid = env['slnguid']
+        else:
+            self.slnguid = _generateGUID(dswfile, self.name)
+
+        self.config = Config()
+        if env.has_key('variant'):
+            self.config.variant = env['variant'].capitalize()
+        else:
+            raise SCons.Errors.InternalError, \
+                  "You must specify a 'variant' argument (i.e. 'Debug' or " +\
+                  "'Release') to create an MSVS Solution File."
+
+        self.configs = {}
+
+        if os.path.exists(self.dswfile):
+            self.Parse()
+
+        self.configs[self.config.variant] = self.config
+
+    def Parse(self):
+        try:
+            dswfile = file(self.dswfile,'r')
+        except IOError:
+            return # doesn't exist yet, so can't add anything to configs.
+
+        line = dswfile.readline()
+        while line:
+            if line[:9] == "EndGlobal":
+                break
+            line = dswfile.readline()
+
+        line = dswfile.readline()
+        datas = line
+        while line:
+            line = dswfile.readline()
+            datas = datas + line
+
+        # OK, we've found our little pickled cache of data.
+        try:
+            datas = base64.decodestring(datas)
+            data = pickle.loads(datas)
+        except:
+            return # unable to unpickle any data for some reason
+
+        self.configs.update(data)
+
+    def PrintSolution(self):
+        """Writes a solution file"""
+        self.file.write('Microsoft Visual Studio Solution File, Format Version 7.00\n'
+        # the next line has the GUID for an external makefile project.
+                        'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%s", "%s", "%s"\n'
+                        'EndProject\n'
+                        'Global\n'
+                        '	GlobalSection(SolutionConfiguration) = preSolution\n'\
+                         % (self.name, os.path.basename(self.dspfile), self.slnguid))
+        confkeys = self.configs.keys()
+        confkeys.sort()
+        cnt = 0
+        for name in confkeys:
+            self.file.write('		ConfigName.%d = %s\n' % (cnt, name.capitalize()))
+            cnt = cnt + 1
+        self.file.write('	EndGlobalSection\n'
+                        '	GlobalSection(ProjectDependencies) = postSolution\n'
+                        '	EndGlobalSection\n'
+                        '	GlobalSection(ProjectConfiguration) = postSolution\n')
+        for name in confkeys:
+            name = name.capitalize()
+            self.file.write('		%s.%s.ActiveCfg = %s|Win32\n'
+                            '		%s.%s.Build.0 = %s|Win32\n'  %(self.slnguid,name,name,self.slnguid,name,name))
+        self.file.write('	EndGlobalSection\n'
+                        '	GlobalSection(ExtensibilityGlobals) = postSolution\n'
+                        '	EndGlobalSection\n'
+                        '	GlobalSection(ExtensibilityAddIns) = postSolution\n'
+                        '	EndGlobalSection\n'
+                        'EndGlobal\n')
+        pdata = pickle.dumps(self.configs,True)
+        pdata = base64.encodestring(pdata)
+        self.file.write(pdata + '\n')
+
+    def Build(self):
+        try:
+            self.file = file(self.dswfile,'w')
+        except IOError, detail:
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+        else:
+            self.PrintSolution()
+            self.file.close()
+
+class _GenerateV6DSW(_DSWGenerator):
+    """Generates a Workspace file for MSVS 6.0"""
+
+    def PrintWorkspace(self):
+        """ writes a DSW file """
+        self.file.write('Microsoft Developer Studio Workspace File, Format Version 6.00\n'
+                        '# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n'
+                        '\n'
+                        '###############################################################################\n'
+                        '\n'
+                        'Project: "%s"="%s" - Package Owner=<4>\n'
+                        '\n'
+                        'Package=<5>\n'
+                        '{{{\n'
+                        '}}}\n'
+                        '\n'
+                        'Package=<4>\n'
+                        '{{{\n'
+                        '}}}\n'
+                        '\n'
+                        '###############################################################################\n'
+                        '\n'
+                        'Global:\n'
+                        '\n'
+                        'Package=<5>\n'
+                        '{{{\n'
+                        '}}}\n'
+                        '\n'
+                        'Package=<3>\n'
+                        '{{{\n'
+                        '}}}\n'
+                        '\n'
+                        '###############################################################################\n'\
+                         %(self.name,self.dspfile))
+
+    def Build(self):
+        try:
+            self.file = file(self.dswfile,'w')
+        except IOError, detail:
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+        else:
+            self.PrintWorkspace()
+            self.file.close()
+
+
+def GenerateDSP(dspfile, source, env):
+    """Generates a Project file based on the version of MSVS that is being used"""
+
+    if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+        g = _GenerateV7DSP(dspfile, source, env)
+        g.Build()
+    else:
+        g = _GenerateV6DSP(dspfile, source, env)
+        g.Build()
+
+def GenerateDSW(dswfile, dspfile, source, env):
+    """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
+    
+    if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+        g = _GenerateV7DSW(dswfile, dspfile, source, env)
+        g.Build()
+    else:
+        g = _GenerateV6DSW(dswfile, dspfile, source, env)
+        g.Build()
+
+
+##############################################################################
+# Above here are the classes and functions for generation of
+# 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 type(env['MSVS']) != types.DictType:
+        env['MSVS'] = {}
+
+    if env.has_key('MSVS_VERSION'):
+        version = env['MSVS_VERSION']
+        versions = [version]
+    else:
+        if SCons.Util.can_read_reg:
+            versions = get_visualstudio_versions()
+            version = versions[0] #use highest version by default
+
+    env['MSVS_VERSION'] = version
+    env['MSVS']['VERSIONS'] = versions
+    env['MSVS']['VERSION'] = version
+    
+    return version
+
+def get_visualstudio_versions():
+    """
+    Get list of visualstudio versions from the Windows registry.  Return a
+    list of strings containing version numbers; an exception will be raised
+    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 SCons.Util.can_read_reg:
+        raise SCons.Errors.InternalError, "No Windows registry module was found"
+
+    HLM = SCons.Util.HKEY_LOCAL_MACHINE
+    K = r'Software\Microsoft\VisualStudio'
+    L = []
+    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:
+                tst = 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.
+            if not id or not id[0]:
+                files_dir = SCons.Platform.win32.get_program_files_dir()
+                if float(p) < 7.0:
+                    vs = r'Microsoft Visual Studio\Common\MSDev98'
+                else:
+                    vs = r'Microsoft Visual Studio .NET\Common7\IDE'
+                id = [ os.path.join(files_dir, vs) ]
+            if os.path.exists(id[0]):
+                L.append(p)
+    except SCons.Util.RegError:
+        pass
+
+    if not L:
+        raise SCons.Errors.InternalError, "Microsoft Visual Studio was not found."
+
+    L.sort()
+    L.reverse()
+
+    return L
+
+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:
+        raise SCons.Errors.InternalError, "No Windows registry module was found"
+
+    if not version:
+        version = get_visualstudio_versions()[0] #use highest version by default
+
+    K = 'Software\\Microsoft\\VisualStudio\\' + version
+
+    # vc++ install dir
+    rv = {}
+    try:
+        if (float(version) < 7.0):
+            (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+                                                             K + r'\Setup\Microsoft Visual C++\ProductDir')
+        else:
+            (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+                                                             K + r'\Setup\VC\ProductDir')
+    except SCons.Util.RegError:
+        pass
+
+    # visual studio install dir
+    if (float(version) < 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:
+        (rv['FRAMEWORKSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+            r'Software\Microsoft\.NETFramework\sdkInstallRoot')
+    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 GenerateProject(target, source, env):
+    # generate the dsp file, according to the version of MSVS.
+    builddspfile = target[0]
+    builddswfile = target[1]
+    dswfile = builddswfile.srcnode()
+    dspfile = builddspfile.srcnode()
+
+#     print "SConscript    :",str(source[0])
+#     print "DSW file      :",dswfile
+#     print "DSP file      :",dspfile
+#     print "Build DSW file:",builddswfile
+#     print "Build DSP file:",builddspfile
+
+    # this detects whether or not we're using a BuildDir
+    if os.path.abspath(os.path.normcase(str(dspfile))) != \
+           os.path.abspath(os.path.normcase(str(builddspfile))):
+        try:
+            bdsp = file(str(builddspfile), "w+")
+        except IOError, detail:
+            print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
+            raise
+
+        bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
+
+        try:
+            bdsw = file(str(builddswfile), "w+")
+        except IOError, detail:
+            print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
+            raise
+
+        bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
+
+    GenerateDSP(dspfile, source, env)
+    GenerateDSW(dswfile, dspfile, source, env) 
+
+def projectEmitter(target, source, env):
+    """Sets up the DSP and DSW dependencies for an SConscript file."""
+
+    if source[0] == target[0]:
+        source = []
+
+    # make sure the suffix is correct for the version of MSVS we're running.
+    (base, suff) = os.path.splitext(str(target[0]))
+    suff = env['MSVSPROJECTSUFFIX']
+    target[0] = base + suff
+
+    dspfile = SCons.Node.FS.default_fs.File(target[0]).srcnode()
+    dswfile = SCons.Node.FS.default_fs.File(os.path.splitext(str(dspfile))[0] + env['MSVSSOLUTIONSUFFIX'])
+
+    if not source:
+        source = [SCons.Script.SConscript.stack[-1].sconscript.srcnode()]
+
+    source[0].attributes.sconstruct = SCons.Script.SConscript.stack[0].sconscript
+
+    bdswpath = os.path.splitext(str(target[0]))[0] + env['MSVSSOLUTIONSUFFIX']
+    bdswfile = SCons.Node.FS.default_fs.File(bdswpath)
+
+    # only make these side effects if they're
+    # not the same file.
+    if os.path.abspath(os.path.normcase(str(dspfile))) != \
+           os.path.abspath(os.path.normcase(str(target[0]))):
+        env.SideEffect(dspfile, target[0])
+        env.Precious(dspfile)
+        # dswfile isn't precious -- it can be blown away and rewritten each time.
+        env.SideEffect(dswfile, target[0])
+    
+    return ([target[0],bdswfile], source)
+
+projectGeneratorAction = SCons.Action.Action(GenerateProject, None)
+
+projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM',
+                                       suffix = '$MSVSPROJECTSUFFIX',
+                                       emitter = projectEmitter)
+
+def generate(env):
+    """Add Builders and construction variables for Microsoft Visual
+    Studio project files to an Environment."""
+    try:
+        bld = env['BUILDERS']['MSVSProject']
+    except KeyError:
+        env['BUILDERS']['MSVSProject'] = projectBuilder
+
+    env['MSVSPROJECTCOM']     = projectGeneratorAction
+
+    version = get_default_visualstudio_version(env)
+
+    # keep a record of some of the MSVS info so the user can use it.
+    try:
+        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
+
+    if (float(env['MSVS_VERSION']) < 7.0):
+        env['MSVSPROJECTSUFFIX']  = '.dsp'
+        env['MSVSSOLUTIONSUFFIX'] = '.dsw'
+    else:
+        env['MSVSPROJECTSUFFIX']  = '.vcproj'
+        env['MSVSSOLUTIONSUFFIX'] = '.sln'
+
+def exists(env):
+    if not SCons.Util.can_read_reg or not get_visualstudio_versions():
+        if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+            return env.Detect('devenv')
+        else:
+            return env.Detect('msdev')
+    else:
+        # there's at least one version of MSVS installed.
+        return True
+

src/engine/SCons/Tool/msvsTests.py

+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import string
+import sys
+import TestCmd
+import unittest
+
+from SCons.Tool.msvs import *
+import SCons.Util
+import SCons.Warnings
+
+regdata_6a = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\ServicePacks]
+"sp3"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup]
+"VsCommonDir"="C:\Program Files\Microsoft Visual Studio\Common"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Developer Network Library - Visual Studio 6.0a]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio\MSDN98\98VSa\1033"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio\VC98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+regdata_6b = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0]
+"InstallDir"="C:\VS6\Common\IDE\IDE98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\ServicePacks]
+"sp5"=""
+"latest"=dword:00000005
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup]
+"VsCommonDir"="C:\VS6\Common"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Basic]
+"ProductDir"="C:\VS6\VB98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++]
+"ProductDir"="C:\VS6\VC98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio]
+"ProductDir"="C:\VS6"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft VSEE Client]
+"ProductDir"="C:\VS6\Common\Tools"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Visual Studio 98]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+regdata_7 = string.split(r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0]
+"InstallDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"