Add support for Visual Studio 8, and multiple project files in a solution file. ...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 20 Jan 2006 06:09:04 +0000 (06:09 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 20 Jan 2006 06:09:04 +0000 (06:09 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1410 fdb21ef1-2011-0410-befe-b5e4ea1792b1

etc/TestSCons.py
src/CHANGES.txt
src/engine/SCons/Tool/mslib.py
src/engine/SCons/Tool/mslink.py
src/engine/SCons/Tool/mslink.xml
src/engine/SCons/Tool/msvc.py
src/engine/SCons/Tool/msvs.py
src/engine/SCons/Tool/msvsTests.py
test/MSVS/vs-8.0-exec.py [new file with mode: 0644]
test/MSVS/vs-8.0-files.py [new file with mode: 0644]

index 901c762f75fb67725ab41148491f9471766a56be..87eadfbf38f150be77c681db15b548ac1f967ce7 100644 (file)
@@ -473,7 +473,10 @@ print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
         contents = string.replace(contents, orig, replace)
         self.write(fname, contents)
 
-    def msvs_substitute(self, input, msvs_ver, subdir=None, sconscript=None, python=sys.executable):
+    def msvs_substitute(self, input, msvs_ver,
+                        subdir=None, sconscript=None,
+                        python=sys.executable,
+                        project_guid=None):
         if not hasattr(self, '_msvs_versions'):
             self.msvs_versions()
 
@@ -482,10 +485,16 @@ print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
         else:
             workpath = self.workpath()
 
-        if not sconscript:
+        if sconscript is None:
             sconscript = self.workpath('SConstruct')
 
-        exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%s'), join(sys.prefix, 'scons-%s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % (self._scons_version, self._scons_version)
+        if project_guid is None:
+            project_guid = "{E5466E26-0003-F18B-8F8A-BCD76C86388D}"
+
+        if os.environ.has_key('SCONS_LIB_DIR'):
+            exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % os.environ['SCONS_LIB_DIR']
+        else:
+            exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%s'), join(sys.prefix, 'scons-%s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % (self._scons_version, self._scons_version)
         exec_script_main_xml = string.replace(exec_script_main, "'", "&apos;")
 
         result = string.replace(input, r'<WORKPATH>', workpath)
@@ -493,6 +502,7 @@ print "self._msvs_versions =", str(env['MSVS']['VERSIONS'])
         result = string.replace(result, r'<SCONSCRIPT>', sconscript)
         result = string.replace(result, r'<SCONS_SCRIPT_MAIN>', exec_script_main)
         result = string.replace(result, r'<SCONS_SCRIPT_MAIN_XML>', exec_script_main_xml)
+        result = string.replace(result, r'<PROJECT_GUID>', project_guid)
         return result
 
 # In some environments, $AR will generate a warning message to stderr
index 1153922f43752bb06158328c70b5ea1679c8dbf9..481f6f3f2c069bf5fd3683bf3209587d90cce6b3 100644 (file)
@@ -22,6 +22,14 @@ RELEASE 0.97 - XXX
 
   - Set $CCVERSION when using gcc.
 
+  From Matthias:
+
+  - Support generating project and solution files for Microsoft
+    Visual Studio version 8.
+
+  - Support generating more than one project file for a Microsoft
+    Visual Studio solution file.
+
   From Erling Andersen:
 
   - Fix interpretation of Node.FS objects wrapped in Proxy instances,
@@ -417,6 +425,8 @@ RELEASE 0.97 - XXX
 
   - Handle Visual Studio project and solution files in Unicode.
 
+  - Add x64 support for Microsoft Visual Studio 8.
+
   From Wayne Lee:
 
   - Avoid "maximum recursion limit" errors when removing $(-$) pairs
@@ -427,6 +437,16 @@ RELEASE 0.97 - XXX
   - Make ParseConfig() recognize and add -mno-cygwin to $LINKFLAGS and
     $CCFLAGS, and -mwindows to $LINKFLAGS.
 
+  From Christian Maaser:
+
+  - Add support for Visual Studio Express Editions.
+
+  - Add support for Visual Studio 8 *.manifest files, includng
+    new $WIN32_INSERT_MANIFEST, $WIN32PROGMANIFESTSUFFIX,
+    $WIN32PROGMANIFESTPREFIX, $WIN32PROGMANIFESTSUFFIX,
+    $WIN32SHLIBMANIFESTPREFIX and $WIN32SHLIBMANIFESTSUFFIX construction
+    variables.
+
   From Sanjoy Mahajan:
 
   - Correct TeX-related command lines to just $SOURCE, not $SOURCES
index 45712dc78b83ea2e4c666e9643f9868617777ac8..ee4ee862ce9f392a7f7d51f11fc0b42ad85ee9e6 100644 (file)
@@ -47,9 +47,9 @@ def generate(env):
         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)
+            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(env,version)
         else:
-            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(env,version)
 
         # since other tools can set this, we just make sure that the
         # relevant stuff from MSVS is in there somewhere.
@@ -68,7 +68,7 @@ def exists(env):
         v = SCons.Tool.msvs.get_visualstudio_versions()
     except (SCons.Util.RegError, SCons.Errors.InternalError):
         pass
-    
+
     if not v:
         return env.Detect('lib')
     else:
index e05530e84b66992d44f5a5c919c1337c55531686..fe4e394dd9cb4a888bbb89948da1cf75ab4aeb0f 100644 (file)
@@ -72,13 +72,13 @@ def win32ShlinkSources(target, source, env, for_signature):
             # Just treat it as a generic source file.
             listCmd.append(src)
     return listCmd
-    
+
 def win32LibEmitter(target, source, env):
     SCons.Tool.msvc.validate_vars(env)
-    
+
     dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
     no_import_lib = env.get('no_import_lib', 0)
-    
+
     if not dll:
         raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
 
@@ -86,21 +86,28 @@ def win32LibEmitter(target, source, env):
        not env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX"):
 
         # append a def file to the list of sources
-        source.append(env.ReplaceIxes(dll, 
+        source.append(env.ReplaceIxes(dll,
                                       "SHLIBPREFIX", "SHLIBSUFFIX",
                                       "WIN32DEFPREFIX", "WIN32DEFSUFFIX"))
 
+    version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
+    if version_num >= 8.0 and env.get('WIN32_INSERT_MANIFEST', 0):
+        # MSVC 8 automatically generates .manifest files that must be installed
+        target.append(env.ReplaceIxes(dll,
+                                      "SHLIBPREFIX", "SHLIBSUFFIX",
+                                      "WIN32SHLIBMANIFESTPREFIX", "WIN32SHLIBMANIFESTSUFFIX"))
+
     if env.has_key('PDB') and env['PDB']:
         target.append(env['PDB'])
 
     if not no_import_lib and \
        not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
         # Append an import library to the list of targets.
-        target.append(env.ReplaceIxes(dll, 
+        target.append(env.ReplaceIxes(dll,
                                       "SHLIBPREFIX", "SHLIBSUFFIX",
                                       "LIBPREFIX", "LIBSUFFIX"))
         # and .exp file is created if there are exports from a DLL
-        target.append(env.ReplaceIxes(dll, 
+        target.append(env.ReplaceIxes(dll,
                                       "SHLIBPREFIX", "SHLIBSUFFIX",
                                       "WIN32EXPPREFIX", "WIN32EXPSUFFIX"))
 
@@ -108,10 +115,21 @@ def win32LibEmitter(target, source, env):
 
 def prog_emitter(target, source, env):
     SCons.Tool.msvc.validate_vars(env)
-    
+
+    exe = env.FindIxes(target, "PROGPREFIX", "PROGSUFFIX")
+    if not exe:
+        raise SCons.Errors.UserError, "An executable should have exactly one target with the suffix: %s" % env.subst("$PROGSUFFIX")
+
+    version_num, suite = SCons.Tool.msvs.msvs_parse_version(env.get('MSVS_VERSION', '6.0'))
+    if version_num >= 8.0 and env.get('WIN32_INSERT_MANIFEST', 0):
+        # MSVC 8 automatically generates .manifest files that have to be installed
+        target.append(env.ReplaceIxes(exe,
+                                      "PROGPREFIX", "PROGSUFFIX",
+                                      "WIN32PROGMANIFESTPREFIX", "WIN32PROGMANIFESTSUFFIX"))
+
     if env.has_key('PDB') and env['PDB']:
         target.append(env['PDB'])
-        
+
     return (target,source)
 
 def RegServerFunc(target, source, env):
@@ -133,7 +151,7 @@ def generate(env):
     """Add Builders and construction variables for ar to an Environment."""
     SCons.Tool.createSharedLibBuilder(env)
     SCons.Tool.createProgBuilder(env)
-    
+
     env['SHLINK']      = '$LINK'
     env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
     env['_SHLINK_TARGETS'] = win32ShlinkTargets
@@ -157,6 +175,11 @@ def generate(env):
     env['WIN32EXPPREFIX']        = ''
     env['WIN32EXPSUFFIX']        = '.exp'
 
+    env['WIN32SHLIBMANIFESTPREFIX'] = ''
+    env['WIN32SHLIBMANIFESTSUFFIX'] = env['SHLIBSUFFIX'] + '.manifest'
+    env['WIN32PROGMANIFESTPREFIX']  = ''
+    env['WIN32PROGMANIFESTSUFFIX']  = env['PROGSUFFIX'] + '.manifest'
+
     env['REGSVRACTION'] = regServerCheck
     env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
     env['REGSVRFLAGS'] = '/s '
@@ -166,9 +189,9 @@ def generate(env):
         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)
+            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(env,version)
         else:
-            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+            include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(env,version)
 
         # since other tools can set these, we just make sure that the
         # relevant stuff from MSVS is in there somewhere.
@@ -183,8 +206,8 @@ def generate(env):
     # setting them the same means that LoadableModule works everywhere.
     SCons.Tool.createLoadableModuleBuilder(env)
     env['LDMODULE'] = '$SHLINK'
-    env['LDMODULEPREFIX'] = '$SHLIBPREFIX' 
-    env['LDMODULESUFFIX'] = '$SHLIBSUFFIX' 
+    env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
+    env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
     env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
     # We can't use '$SHLINKCOM' here because that will stringify the
     # action list on expansion, and will then try to execute expanded
index 2b901c6e5e31316aa9142c32a1f366f0419bc9c4..6fac54e661e67feee5923bf3c870d0fbcd8aed91 100644 (file)
@@ -86,6 +86,16 @@ The default is 0 (do not build a .def file).
 </summary>
 </cvar>
 
+<cvar name="WIN32_INSERT_MANIFEST">
+<summary>
+When this is set to true,
+&scons;
+will be aware of the
+<filename>.manifest</filename>
+files generated by Microsoft Visua C/C++ 8.
+</summary>
+</cvar>
+
 <cvar name="WIN32DEFPREFIX">
 <summary>
 The prefix used for WIN32 .def file names.
@@ -109,3 +119,31 @@ XXX The prefix used for WIN32 .def file names.
 XXX The suffix used for WIN32 .def file names.
 </summary>
 </cvar>
+
+<cvar name="WIN32PROGMANIFESTPREFIX">
+<summary>
+The prefix used for executable program <filename>.manifest</filename> files
+generated by Microsoft Visual C/C++ .NET 2005.
+</summary>
+</cvar>
+
+<cvar name="WIN32PROGMANIFESTSUFFIX">
+<summary>
+The suffix used for executable program <filename>.manifest</filename> files
+generated by Microsoft Visual C/C++ .NET 2005.
+</summary>
+</cvar>
+
+<cvar name="WIN32SHLIBMANIFESTPREFIX">
+<summary>
+The prefix used for shared library <filename>.manifest</filename> files
+generated by Microsoft Visual C/C++ .NET 2005.
+</summary>
+</cvar>
+
+<cvar name="WIN32SHLIBMANIFESTSUFFIX">
+<summary>
+The suffix used for shared library <filename>.manifest</filename> files
+generated by Microsoft Visual C/C++ .NET 2005.
+</summary>
+</cvar>
index d6ecbfafdcf8a6e5b592a0e8eff2285d308ad6d6..bc50eaaad81b3a4d6622a31e47f0918a62cd839c 100644 (file)
@@ -49,8 +49,9 @@ import SCons.Warnings
 CSuffixes = ['.c', '.C']
 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
 
-def _parse_msvc7_overrides(version):
-    """ Parse any overridden defaults for MSVS directory locations in MSVS .NET. """
+def _parse_msvc7_overrides(version,platform):
+    """ 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:
@@ -62,14 +63,16 @@ def _parse_msvc7_overrides(version):
                                             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."
+        raise SCons.Errors.InternalError, \
+              "The Local AppData directory was not found in the registry."
 
     comps = comps + '\\Microsoft\\VisualStudio\\' + version + '\\VCComponents.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],
+        # We only look for entries after:
+        # [VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories],
         # since this file could contain a number of things...
         lines = None
         try:
@@ -85,11 +88,12 @@ def _parse_msvc7_overrides(version):
                 lines = codecs.open(comps, 'r', 'utf8').readlines()
         if lines is None:
             lines = open(comps, 'r').readlines()
-            
+        if 'x86' == platform: platform = 'Win32'
+
         found = 0
         for line in lines:
             line.strip()
-            if line.find(r'[VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]') >= 0:
+            if line.find(r'[VC\VC_OBJECTS_PLATFORM_INFO\%s\Directories]'%platform) >= 0:
                 found = 1
             elif line == '' or line[:1] == '[':
                 found = 0
@@ -103,9 +107,12 @@ def _parse_msvc7_overrides(version):
     else:
         # since the file didn't exist, we have only the defaults in
         # the registry to work with.
+
+        if 'x86' == platform: platform = 'Win32'
+
         try:
             K = 'SOFTWARE\\Microsoft\\VisualStudio\\' + version
-            K = K + r'\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories'
+            K = K + r'\VC\VC_OBJECTS_PLATFORM_INFO\%s\Directories'%platform
             k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,K)
             i = 0
             while 1:
@@ -121,6 +128,115 @@ def _parse_msvc7_overrides(version):
             raise SCons.Errors.InternalError, "Unable to find MSVC paths in the registry."
     return dirs
 
+def _parse_msvc8_overrides(version,platform,suite):
+    """ Parse any overridden defaults for MSVC directory locations
+    in MSVC 2005. """
+
+    # In VS8 the user can change the location of the settings file that
+    # contains the include, lib and binary paths. Try to get the location
+    # from registry
+    if not SCons.Util.can_read_reg:
+        raise SCons.Errors.InternalError, "No Windows registry module was found"
+
+    s = ''
+    if suite == 'EXPRESS':
+        s = '\\VCExpress\\'
+
+    # ToDo: add registry key strings for the other versions of visual
+    # studio 2005.
+    settings_path = ""
+    try:
+        (settings_path, t) = SCons.Util.RegGetValue(SCons.Util.HKEY_CURRENT_USER,
+                                                    r'Software\Microsoft' + s + version +\
+                                                    r'\Profile\AutoSaveFile')
+        settings_path = settings_path.upper()
+    except SCons.Util.RegError:
+        raise SCons.Errors.InternalError, \
+              "The VS8 settings file location was not found in the registry."
+
+    # Look for potential environment variables in the settings path
+    if settings_path.find('%VSSPV_VISUALSTUDIO_DIR%') >= 0:
+        # First replace a special variable named %vsspv_visualstudio_dir%
+        # that is not found in the OSs environment variables...
+        try:
+            (value, t) = SCons.Util.RegGetValue(SCons.Util.HKEY_CURRENT_USER,
+                                                r'Software\Microsoft' + s + version +\
+                                                r'\VisualStudioLocation')
+            settings_path = settings_path.replace('%VSSPV_VISUALSTUDIO_DIR%', value)
+        except SCons.Util.RegError:
+            raise SCons.Errors.InternalError, "The VS8 settings file location was not found in the registry."
+
+    if settings_path.find('%') >= 0:
+        # Collect global environment variables
+        env_vars = {}
+
+        # Read all the global environment variables of the current user
+        k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_CURRENT_USER, r'Environment')
+        i = 0
+        while 1:
+            try:
+                (key,val,t) = SCons.Util.RegEnumValue(k,i)
+                env_vars[key.upper()] = val.upper()
+                i = i + 1
+            except SCons.Util.RegError:
+                break
+
+        # And some more variables that are not found in the registry
+        env_vars['USERPROFILE'] = os.getenv('USERPROFILE')
+        env_vars['SystemDrive'] = os.getenv('SystemDrive')
+
+        found_var = 1
+        while found_var:
+            found_var = 0
+            for env_var in env_vars:
+                if settings_path.find(r'%' + env_var + r'%') >= 0:
+                    settings_path = settings_path.replace(r'%' + env_var + r'%', env_vars[env_var])
+                    found_var = 1
+
+    dirs = {}
+
+    if os.path.exists(settings_path):
+        # now we parse the directories from this file, if it exists.
+        import xml.dom.minidom
+        doc = xml.dom.minidom.parse(settings_path)
+        user_settings = doc.getElementsByTagName('UserSettings')[0]
+        tool_options = user_settings.getElementsByTagName('ToolsOptions')[0]
+        tool_options_categories = tool_options.getElementsByTagName('ToolsOptionsCategory')
+        for category in tool_options_categories:
+            category_name = category.attributes.get('name')
+            if category_name is not None and category_name.value == 'Projects':
+                subcategories = category.getElementsByTagName('ToolsOptionsSubCategory')
+                for subcategory in subcategories:
+                    subcategory_name = subcategory.attributes.get('name')
+                    if subcategory_name is not None and subcategory_name.value == 'VCDirectories':
+                        properties = subcategory.getElementsByTagName('PropertyValue')
+                        for property in properties:
+                            property_name = property.attributes.get('name')
+                            if property_name is None:
+                                continue
+                            elif property_name.value == 'IncludeDirectories':
+                                include_dirs = property.childNodes[0].data
+                                # ToDo: Support for other destinations than Win32
+                                include_dirs = include_dirs.replace('Win32|', '')
+                                dirs['INCLUDE'] = include_dirs
+                            elif property_name.value == 'LibraryDirectories':
+                                lib_dirs = property.childNodes[0].data.replace('Win32|', '')
+                                # ToDo: Support for other destinations than Win32
+                                lib_dirs = lib_dirs.replace('Win32|', '')
+                                dirs['LIBRARY'] = lib_dirs
+                            elif property_name.value == 'ExecutableDirectories':
+                                path_dirs = property.childNodes[0].data.replace('Win32|', '')
+                                # ToDo: Support for other destinations than Win32
+                                path_dirs = path_dirs.replace('Win32|', '')
+                                dirs['PATH'] = path_dirs
+
+        dirs['VCINSTALLDIR'] = os.getenv('VCInstallDir')
+        dirs['VSINSTALLDIR'] = os.getenv('VSInstallDir')
+    else:
+        # There are no default directories in the registry for VS8 Express :(
+        raise SCons.Errors.InternalError, "Unable to find MSVC paths in the registry."
+    return dirs
+
 def _get_msvc7_path(path, version, platform):
     """
     Get Visual Studio directories from version 7 (MSVS .NET)
@@ -129,12 +245,13 @@ def _get_msvc7_path(path, version, platform):
     # 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)
+    dirs = _parse_msvc7_overrides(version,platform)
 
     if dirs.has_key(path):
         p = dirs[path]
     else:
-        raise SCons.Errors.InternalError, "Unable to retrieve the %s path from MS VC++."%path
+        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)
@@ -160,7 +277,47 @@ def _get_msvc7_path(path, version, platform):
 
     return string.join(rv,os.pathsep)
 
-def get_msvc_path (path, version, platform='x86'):
+def _get_msvc8_path(path, version, platform, suite):
+    """
+    Get Visual Studio directories from version 8 (MSVS 2005)
+    (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_msvc8_overrides(version, platform, suite)
+
+    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, paths=paths):
+        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).rstrip('\n\r')
+        rv.append(entry)
+
+    return string.join(rv,os.pathsep)
+
+def get_msvc_path(env, path, version):
     """
     Get a list of visualstudio directories (include, lib or path).  Return
     a string delimited by ';'. An exception will be raised if unable to
@@ -177,13 +334,22 @@ def get_msvc_path (path, version, platform='x86'):
     if path=='LIB':
         path= 'LIBRARY'
 
-    if float(version) >= 7.0:
+    version_num, suite = SCons.Tool.msvs.msvs_parse_version(version)
+    if version_num >= 8.0:
+        platform = env.get('MSVS8_PLATFORM', 'x86')
+        suite = SCons.Tool.msvs.get_default_visualstudio8_suite(env)
+    else:
+        platform = 'x86'
+
+    if version_num >= 8.0:
+        return _get_msvc8_path(path, version, platform, suite)
+    elif version_num >= 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)
+         'Build System\\Components\\Platforms\\Win32 (x86)\\Directories') % \
+        (version)
     for base in (SCons.Util.HKEY_CURRENT_USER,
                  SCons.Util.HKEY_LOCAL_MACHINE):
         try:
@@ -245,7 +411,7 @@ def _get_msvc6_default_paths(version, use_mfc_dirs):
         exe_path = r'%s\tools\%s;%s\MSDev98\bin;%s\tools;%s\bin' % (MVSCommondir, osdir, MVSCommondir,  MVSCommondir, MVSVCdir)
     return (include_path, lib_path, exe_path)
 
-def _get_msvc7_default_paths(version, use_mfc_dirs):
+def _get_msvc7_default_paths(env, version, use_mfc_dirs):
     """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
@@ -293,7 +459,61 @@ def _get_msvc7_default_paths(version, use_mfc_dirs):
 
     return (include_path, lib_path, exe_path)
 
-def get_msvc_paths(version=None, use_mfc_dirs=0):
+def _get_msvc8_default_paths(env, version, suite, use_mfc_dirs):
+    """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 8 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 = os.getenv('ProgramFiles') + r'\Microsoft Visual Studio 8'
+
+    if MVSdir:
+        if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'):
+            MVSVCdir = paths['VCINSTALLDIR']
+        else:
+            MVSVCdir = os.path.join(MVSdir,'VC')
+
+        MVSCommondir = r'%s\Common7' % MVSdir
+        include_path = r'%s\include' % (MVSVCdir)
+        lib_path = r'%s\lib' % (MVSVCdir)
+        exe_path = r'%s\IDE;%s\bin;%s\Tools;%s\Tools\bin' % (MVSCommondir,MVSVCdir, MVSCommondir, MVSCommondir)
+
+        if paths.has_key('PLATFORMSDKDIR'):
+            PlatformSdkDir = paths['PLATFORMSDKDIR']
+            include_path = include_path + r';%sInclude' % PlatformSdkDir
+            lib_path = lib_path + r';%s\lib' % PlatformSdkDir
+            if use_mfc_dirs:
+                include_path = include_path + r';%sInclude\mfc;%sInclude\atl' % (PlatformSdkDir, PlatformSdkDir)
+            lib_path = lib_path + r';%s\lib' % paths['PLATFORMSDKDIR']
+
+        envvar = 'include'
+        SCons.Util.get_environment_var(envvar)
+        include_path = include_path + envvar
+
+        if SCons.Util.can_read_reg and paths.has_key('FRAMEWORKSDKDIR'):
+            include_path = include_path + r';%s\include'%paths['FRAMEWORKSDKDIR']
+            lib_path = lib_path + r';%s\lib'%paths['FRAMEWORKSDKDIR']
+            exe_path = exe_path + r';%s\bin'%paths['FRAMEWORKSDKDIR']
+
+        if SCons.Util.can_read_reg and paths.has_key('FRAMEWORKDIR') and paths.has_key('FRAMEWORKVERSION'):
+            exe_path = exe_path + r';%s\%s'%(paths['FRAMEWORKDIR'],paths['FRAMEWORKVERSION'])
+
+    return (include_path, lib_path, exe_path)
+
+def get_msvc_paths(env, version=None, use_mfc_dirs=0):
     """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."""
@@ -313,29 +533,33 @@ def get_msvc_paths(version=None, use_mfc_dirs=0):
     # 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:
-        defpaths = _get_msvc7_default_paths(version, use_mfc_dirs)
+    version_num, suite = SCons.Tool.msvs.msvs_parse_version(version)
+    if version_num >= 8.0:
+        suite = SCons.Tool.msvs.get_default_visualstudio8_suite(env)
+        defpaths = _get_msvc8_default_paths(env, version, suite, use_mfc_dirs)
+    elif version_num >= 7.0:
+        defpaths = _get_msvc7_default_paths(env, version, use_mfc_dirs)
     else:
         defpaths = _get_msvc6_default_paths(version, use_mfc_dirs)
 
     try:
-        include_path = get_msvc_path("include", version)
+        include_path = get_msvc_path(env, "include", version)
     except (SCons.Util.RegError, SCons.Errors.InternalError):
         include_path = defpaths[0]
 
     try:
-        lib_path = get_msvc_path("lib", version)
+        lib_path = get_msvc_path(env, "lib", version)
     except (SCons.Util.RegError, SCons.Errors.InternalError):
         lib_path = defpaths[1]
 
     try:
-        exe_path = get_msvc_path("path", version)
+        exe_path = get_msvc_path(env, "path", version)
     except (SCons.Util.RegError, SCons.Errors.InternalError):
         exe_path = defpaths[2]
 
     return (include_path, lib_path, exe_path)
 
-def get_msvc_default_paths(version=None, use_mfc_dirs=0):
+def get_msvc_default_paths(env, version=None, use_mfc_dirs=0):
     """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
@@ -355,8 +579,12 @@ def get_msvc_default_paths(version=None, use_mfc_dirs=0):
     except:
         pass
 
-    if float(version) >= 7.0:
-        return _get_msvc7_default_paths(version, use_mfc_dirs)
+    version_num, suite = SCons.Tool.msvs.msvs_parse_version(version)
+    if version_num >= 8.0:
+        suite = SCons.Tool.msvs.get_default_visualstudio8_suite(env)
+        defpaths = _get_msvc8_default_paths(env, version, suite, use_mfc_dirs)
+    elif version_num >= 7.0:
+        return _get_msvc7_default_paths(env, version, use_mfc_dirs)
     else:
         return _get_msvc6_default_paths(version, use_mfc_dirs)
 
@@ -468,13 +696,16 @@ def generate(env):
 
     try:
         version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+        version_num, suite = SCons.Tool.msvs.msvs_parse_version(version)
+        if version_num == 8.0:
+            suite = SCons.Tool.msvs.get_default_visualstudio8_suite(env)
 
         use_mfc_dirs = env.get('MSVS_USE_MFC_DIRS', 0)
         if env.get('MSVS_IGNORE_IDE_PATHS', 0):
             _get_paths = get_msvc_default_paths
         else:
             _get_paths = get_msvc_paths
-        include_path, lib_path, exe_path = _get_paths(version, use_mfc_dirs)
+        include_path, lib_path, exe_path = _get_paths(env, version, use_mfc_dirs)
 
         # since other tools can set these, we just make sure that the
         # relevant stuff from MSVS is in there somewhere.
index c2bd20e40732eb7e2e5d1bea7c53336c39032130..6747d54751ed1841d1a190c38aea4634c546b29d 100644 (file)
@@ -82,6 +82,17 @@ def _generateGUID(slnfile, name):
     solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}"
     return solution
 
+version_re = re.compile(r'(\d+\.\d+)(.*)')
+
+def msvs_parse_version(s):
+    """
+    Split a Visual Studio version, which may in fact be something like
+    '7.0Exp', into is version number (returned as a float) and trailing
+    "suite" portion.
+    """
+    num, suite = version_re.match(s).groups()
+    return float(num), suite
+
 # This is how we re-invoke SCons from inside MSVS Project files.
 # The problem is that we might have been invoked as either scons.bat
 # or scons.py.  If we were invoked directly as scons.py, then we could
@@ -92,10 +103,13 @@ def _generateGUID(slnfile, name):
 # which works regardless of how we were invoked.
 def getExecScriptMain(env, xml=None):
     scons_home = env.get('SCONS_HOME')
-    if scons_home:        
+    if not scons_home and os.environ.has_key('SCONS_LIB_DIR'):
+        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
     else:
-        exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()"
+        version = SCons.__version__
+        exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%(version)s'), join(sys.prefix, 'scons-%(version)s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % locals()
     if xml:
         exec_script_main = xmlify(exec_script_main)
     return exec_script_main
@@ -140,7 +154,7 @@ def makeHierarchy(sources):
             dict[path[-1]] = file
         #else:
         #    print 'Warning: failed to decompose path for '+str(file)
-    return hierarchy    
+    return hierarchy
 
 class _DSPGenerator:
     """ Base class for DSP generators """
@@ -153,10 +167,13 @@ class _DSPGenerator:
         'misc']
 
     def __init__(self, dspfile, source, env):
-        if SCons.Util.is_String(dspfile):
-            self.dspfile = os.path.abspath(dspfile)
+        self.dspfile = str(dspfile)
+        try:
+            get_abspath = dspfile.get_abspath
+        except AttributeError:
+            self.dspabs = os.path.abspath(dspfile)
         else:
-            self.dspfile = dspfile.get_abspath()
+            self.dspabs = get_abspath()
 
         if not env.has_key('variant'):
             raise SCons.Errors.InternalError, \
@@ -213,6 +230,8 @@ class _DSPGenerator:
 
         self.sconscript = env['MSVSSCONSCRIPT']
 
+        cmdargs = env.get('cmdargs', '')
+
         self.env = env
 
         if self.env.has_key('name'):
@@ -237,7 +256,7 @@ class _DSPGenerator:
         if env.has_key('nokeep') and env['variant'] != 0:
             self.nokeep = 1
 
-        if self.nokeep == 0 and os.path.exists(self.dspfile):
+        if self.nokeep == 0 and os.path.exists(self.dspabs):
             self.Parse()
 
         for t in zip(sourcenames,self.srcargs):
@@ -253,10 +272,11 @@ class _DSPGenerator:
         for n in sourcenames:
             self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
 
-        def AddConfig(variant, buildtarget, outdir):
+        def AddConfig(variant, buildtarget, outdir, cmdargs):
             config = Config()
             config.buildtarget = buildtarget
             config.outdir = outdir
+            config.cmdargs = cmdargs
 
             match = re.match('(.*)\|(.*)', variant)
             if match:
@@ -264,13 +284,13 @@ class _DSPGenerator:
                 config.platform = match.group(2)
             else:
                 config.variant = variant
-                config.platform = 'Win32';
+                config.platform = 'Win32'
 
             self.configs[variant] = config
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
 
         for i in range(len(variants)):
-            AddConfig(variants[i], buildtarget[i], outdir[i])
+            AddConfig(variants[i], buildtarget[i], outdir[i],cmdargs)
 
         self.platforms = []
         for key in self.configs.keys():
@@ -355,7 +375,7 @@ class _GenerateV6DSP(_DSPGenerator):
                 self.file.write('# PROP %sOutput_Dir "%s"\n'
                                 '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir))
                 cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1)
-                self.file.write('# PROP %sCmd_Line "%s"\n' 
+                self.file.write('# PROP %sCmd_Line "%s"\n'
                                 '# PROP %sRebuild_Opt "-c && %s"\n'
                                 '# PROP %sTarget_File "%s"\n'
                                 '# PROP %sBsc_Name ""\n'
@@ -422,7 +442,7 @@ class _GenerateV6DSP(_DSPGenerator):
 
     def Parse(self):
         try:
-            dspfile = open(self.dspfile,'r')
+            dspfile = open(self.dspabs,'r')
         except IOError:
             return # doesn't exist yet, so can't add anything to configs.
 
@@ -470,9 +490,9 @@ class _GenerateV6DSP(_DSPGenerator):
 
     def Build(self):
         try:
-            self.file = open(self.dspfile,'w')
+            self.file = open(self.dspabs,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
         else:
             self.PrintHeader()
             self.PrintProject()
@@ -490,7 +510,7 @@ V7DSPHeader = """\
 
 V7DSPConfiguration = """\
 \t\t<Configuration
-\t\t\tName="%(variant)s|Win32"
+\t\t\tName="%(variant)s|%(platform)s"
 \t\t\tOutputDirectory="%(outdir)s"
 \t\t\tIntermediateDirectory="%(outdir)s"
 \t\t\tConfigurationType="0"
@@ -505,15 +525,57 @@ V7DSPConfiguration = """\
 \t\t</Configuration>
 """
 
+V8DSPHeader = """\
+<?xml version="1.0" encoding="%(encoding)s"?>
+<VisualStudioProject
+\tProjectType="Visual C++"
+\tVersion="%(versionstr)s"
+\tName="%(name)s"
+%(scc_attrs)s
+\tRootNamespace="%(name)s"
+\tKeyword="MakeFileProj">
+"""
+
+V8DSPConfiguration = """\
+\t\t<Configuration
+\t\t\tName="%(variant)s|Win32"
+\t\t\tConfigurationType="0"
+\t\t\tUseOfMFC="0"
+\t\t\tATLMinimizesCRunTimeLibraryUsage="false"
+\t\t\t>
+\t\t\t<Tool
+\t\t\t\tName="VCNMakeTool"
+\t\t\t\tBuildCommandLine="%(buildcmd)s"
+\t\t\t\tReBuildCommandLine="%(rebuildcmd)s"
+\t\t\t\tCleanCommandLine="%(cleancmd)s"
+\t\t\t\tOutput="%(buildtarget)s"
+\t\t\t\tPreprocessorDefinitions=""
+\t\t\t\tIncludeSearchPath=""
+\t\t\t\tForcedIncludes=""
+\t\t\t\tAssemblySearchPath=""
+\t\t\t\tForcedUsingAssemblies=""
+\t\t\t\tCompileAsManaged=""
+\t\t\t/>
+\t\t</Configuration>
+"""
 class _GenerateV7DSP(_DSPGenerator):
     """Generates a Project file for MSVS .NET"""
 
     def __init__(self, dspfile, source, env):
         _DSPGenerator.__init__(self, dspfile, source, env)
-        self.version = float(env['MSVS_VERSION'])
-        self.versionstr = '7.00'
-        if self.version >= 7.1:
-            self.versionstr = '7.10'
+        self.version = env['MSVS_VERSION']
+        self.version_num, self.suite = msvs_parse_version(self.version)
+        if self.version_num >= 8.0:
+            self.versionstr = '8.00'
+            self.dspheader = V8DSPHeader
+            self.dspconfiguration = V8DSPConfiguration
+        else:
+            if self.version_num >= 7.1:
+                self.versionstr = '7.10'
+            else:
+                self.versionstr = '7.00'
+            self.dspheader = V7DSPHeader
+            self.dspconfiguration = V7DSPConfiguration
         self.file = None
 
     def PrintHeader(self):
@@ -526,6 +588,8 @@ class _GenerateV7DSP(_DSPGenerator):
         scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
         scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
         project_guid = env.get('MSVS_PROJECT_GUID', '')
+        if self.version_num >= 8.0 and not project_guid:
+            project_guid = _generateGUID(self.dspfile, '')
         if scc_provider != '':
             scc_attrs = ('\tProjectGUID="%s"\n'
                          '\tSccProjectName="%s"\n'
@@ -537,7 +601,7 @@ class _GenerateV7DSP(_DSPGenerator):
                          '\tSccProjectName="%s"\n'
                          '\tSccLocalPath="%s"' % (project_guid, scc_project_name, scc_local_path))
 
-        self.file.write(V7DSPHeader % locals())
+        self.file.write(self.dspheader % locals())
 
         self.file.write('\t<Platforms>\n')
         for platform in self.platforms:
@@ -546,6 +610,10 @@ class _GenerateV7DSP(_DSPGenerator):
                         '\t\t\tName="%s"/>\n' % platform)
         self.file.write('\t</Platforms>\n')
 
+        if self.version_num >= 8.0:
+            self.file.write('\t<ToolFiles>\n'
+                            '\t</ToolFiles>\n')
+
     def PrintProject(self):
         self.file.write('\t<Configurations>\n')
 
@@ -556,25 +624,30 @@ class _GenerateV7DSP(_DSPGenerator):
             platform = self.configs[kind].platform
             outdir = self.configs[kind].outdir
             buildtarget = self.configs[kind].buildtarget
+            cmdargs = self.configs[kind].cmdargs
 
             env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
             if not env_has_buildtarget:
                 self.env['MSVSBUILDTARGET'] = buildtarget
 
             starting = 'echo Starting SCons && '
-            buildcmd    = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1))
-            rebuildcmd  = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1))
-            cleancmd    = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1))
+            if cmdargs:
+                cmdargs = ' ' + cmdargs
+            else:
+                cmdargs = ''
+            buildcmd    = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) + cmdargs)
+            rebuildcmd  = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs)
+            cleancmd    = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs)
 
             if not env_has_buildtarget:
                 del self.env['MSVSBUILDTARGET']
 
-            self.file.write(V7DSPConfiguration % locals())
+            self.file.write(self.dspconfiguration % locals())
 
         self.file.write('\t</Configurations>\n')
 
-        if self.version >= 7.1:
-            self.file.write('\t<References>\n' 
+        if self.version_num >= 7.1:
+            self.file.write('\t<References>\n'
                             '\t</References>\n')
 
         self.PrintSourceFiles()
@@ -659,7 +732,7 @@ class _GenerateV7DSP(_DSPGenerator):
 
     def Parse(self):
         try:
-            dspfile = open(self.dspfile,'r')
+            dspfile = open(self.dspabs,'r')
         except IOError:
             return # doesn't exist yet, so can't add anything to configs.
 
@@ -706,9 +779,9 @@ class _GenerateV7DSP(_DSPGenerator):
 
     def Build(self):
         try:
-            self.file = open(self.dspfile,'w')
+            self.file = open(self.dspabs,'w')
         except IOError, detail:
-            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+            raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
         else:
             self.PrintHeader()
             self.PrintProject()
@@ -731,15 +804,12 @@ class _DSWGenerator:
         if len(projects) < 1:
             raise SCons.Errors.UserError, \
                 "You must specify at least one project to create an MSVSSolution."
-        if len(projects) > 1:
-            raise SCons.Errors.UserError, \
-                "Currently you can specify at most one project to create an MSVSSolution."
-        self.dspfile = str(projects[0])
+        self.dspfiles = map(str, projects)
 
         if self.env.has_key('name'):
             self.name = self.env['name']
         else:
-            self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
+            self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0])
 
     def Build(self):
         pass
@@ -750,10 +820,15 @@ class _GenerateV7DSW(_DSWGenerator):
         _DSWGenerator.__init__(self, dswfile, source, env)
 
         self.file = None
-        self.version = float(self.env['MSVS_VERSION'])
+        self.version = self.env['MSVS_VERSION']
+        self.version_num, self.suite = msvs_parse_version(self.version)
         self.versionstr = '7.00'
-        if self.version >= 7.1:
+        if self.version_num >= 8.0:
+            self.versionstr = '9.00'
+        elif self.version_num >= 7.1:
             self.versionstr = '8.00'
+        if self.version_num >= 8.0:
+            self.versionstr = '9.00'
 
         if env.has_key('slnguid') and env['slnguid']:
             self.slnguid = env['slnguid']
@@ -778,7 +853,7 @@ class _GenerateV7DSW(_DSWGenerator):
                 config.platform = match.group(2)
             else:
                 config.variant = variant
-                config.platform = 'Win32';
+                config.platform = 'Win32'
 
             self.configs[variant] = config
             print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
@@ -830,15 +905,24 @@ class _GenerateV7DSW(_DSWGenerator):
 
     def PrintSolution(self):
         """Writes a solution file"""
-        self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n'
-                        # the next line has the GUID for an external makefile project.
-                        'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%s", "%s", "%s"\n'
-                        % (self.versionstr, self.name, os.path.basename(self.dspfile), self.slnguid))
-        if self.version >= 7.1:
-            self.file.write('\tProjectSection(ProjectDependencies) = postProject\n'
-                            '\tEndProjectSection\n')
-        self.file.write('EndProject\n'
-                        'Global\n')
+        self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr )
+        if self.version_num >= 8.0:
+            self.file.write('# Visual Studio 2005\n')
+        for p in self.dspfiles:
+            name = os.path.basename(p)
+            base, suffix = SCons.Util.splitext(name)
+            if suffix == '.vcproj':
+                name = base
+            # the next line has the GUID for an external makefile project.
+            self.file.write('Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%s", "%s", "%s"\n'
+                            % ( name, p, self.slnguid ) )
+            if self.version_num >= 7.1 and self.version_num < 8.0:
+                self.file.write('\tProjectSection(ProjectDependencies) = postProject\n'
+                                '\tEndProjectSection\n')
+            self.file.write('EndProject\n')
+
+        self.file.write('Global\n')
+
         env = self.env
         if env.has_key('MSVS_SCC_PROVIDER'):
             dspfile_base = os.path.basename(self.dspfile)
@@ -850,7 +934,7 @@ class _GenerateV7DSW(_DSWGenerator):
             scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
             scc_project_base_path = env.get('MSVS_SCC_PROJECT_BASE_PATH', '')
             # project_guid = env.get('MSVS_PROJECT_GUID', '')
-            
+
             self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n'
                             '\t\tSccNumberOfProjects = 2\n'
                             '\t\tSccProjectUniqueName0 = %(dspfile_base)s\n'
@@ -864,32 +948,57 @@ class _GenerateV7DSW(_DSWGenerator):
                             '\t\tSccProjectFilePathRelativizedFromConnection1 = %(scc_project_base_path)s\n'
                             '\t\tSolutionUniqueID = %(slnguid)s\n'
                             '\tEndGlobalSection\n' % locals())
-                        
-        self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
+
+        if self.version_num >= 8.0:
+            self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
+        else:
+            self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
+
         confkeys = self.configs.keys()
         confkeys.sort()
         cnt = 0
         for name in confkeys:
             variant = self.configs[name].variant
-            self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant))
+            platform = self.configs[name].platform
+            if self.version_num >= 8.0:
+                self.file.write('\t\t%s|%s = %s|%s\n' % (variant, platform, variant, platform))
+            else:
+                self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant))
             cnt = cnt + 1
         self.file.write('\tEndGlobalSection\n')
-        if self.version < 7.1:
+        if self.version_num < 7.1:
             self.file.write('\tGlobalSection(ProjectDependencies) = postSolution\n'
                             '\tEndGlobalSection\n')
-        self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
+        if self.version_num >= 8.0:
+            self.file.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
+        else:
+            self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
+
         for name in confkeys:
             name = name
             variant = self.configs[name].variant
             platform = self.configs[name].platform
-            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))
-        self.file.write('\tEndGlobalSection\n'
-                        '\tGlobalSection(ExtensibilityGlobals) = postSolution\n'
-                        '\tEndGlobalSection\n'
-                        '\tGlobalSection(ExtensibilityAddIns) = postSolution\n'
-                        '\tEndGlobalSection\n'
-                        'EndGlobal\n')
+            if self.version_num >= 8.0:
+                for p in self.dspfiles:
+                    guid = _generateGUID(p, '')
+                    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))
+
+        self.file.write('\tEndGlobalSection\n')
+
+        if self.version_num >= 8.0:
+            self.file.write('\tGlobalSection(SolutionProperties) = preSolution\n'
+                            '\t\tHideSolutionNode = FALSE\n'
+                            '\tEndGlobalSection\n')
+        else:
+            self.file.write('\tGlobalSection(ExtensibilityGlobals) = postSolution\n'
+                            '\tEndGlobalSection\n'
+                            '\tGlobalSection(ExtensibilityAddIns) = postSolution\n'
+                            '\tEndGlobalSection\n')
+        self.file.write('EndGlobal\n')
         if self.nokeep == 0:
             pdata = pickle.dumps(self.configs,1)
             pdata = base64.encodestring(pdata)
@@ -941,7 +1050,7 @@ class _GenerateV6DSW(_DSWGenerator):
     def PrintWorkspace(self):
         """ writes a DSW file """
         name = self.name
-        dspfile = self.dspfile
+        dspfile = self.dspfiles[0]
         self.file.write(V6DSWHeader % locals())
 
     def Build(self):
@@ -957,7 +1066,10 @@ class _GenerateV6DSW(_DSWGenerator):
 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:
+    version_num = 6.0
+    if env.has_key('MSVS_VERSION'):
+        version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+    if version_num >= 7.0:
         g = _GenerateV7DSP(dspfile, source, env)
         g.Build()
     else:
@@ -967,7 +1079,10 @@ def GenerateDSP(dspfile, source, env):
 def GenerateDSW(dswfile, 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:
+    version_num = 6.0
+    if env.has_key('MSVS_VERSION'):
+        version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+    if version_num >= 7.0:
         g = _GenerateV7DSW(dswfile, source, env)
         g.Build()
     else:
@@ -1018,56 +1133,64 @@ def get_visualstudio_versions():
         return []
 
     HLM = SCons.Util.HKEY_LOCAL_MACHINE
-    K = r'Software\Microsoft\VisualStudio'
+    KEYS = {
+        r'Software\Microsoft\VisualStudio'      : '',
+        r'Software\Microsoft\VCExpress'         : 'Exp',
+    }
     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:
-                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, 'devenv.exe') ]
-            if os.path.exists(id[0]):
-                L.append(p)
-    except SCons.Util.RegError:
-        pass
+    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 []
@@ -1087,6 +1210,51 @@ def get_visualstudio_versions():
 
     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 = []
+
+    # ToDo: add tests for better suits than VS8 Express here.
+
+    idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
+        r'Software\Microsoft\VCExpress\8.0')
+    try:
+        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.
@@ -1113,22 +1281,26 @@ def get_msvs_install_dirs(version = None):
         else:
             return {}
 
-    K = 'Software\\Microsoft\\VisualStudio\\' + version
+    version_num, suite = msvs_parse_version(version)
+
+    if (version_num >= 8.0):
+        K = 'Software\\Microsoft\\VCExpress\\' + str(version_num)
+    else:
+        K = 'Software\\Microsoft\\VisualStudio\\' + 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:
-        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')
+        (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, key)
     except SCons.Util.RegError:
         pass
 
     # visual studio install dir
-    if (float(version) < 7.0):
+    if (version_num < 7.0):
         try:
             (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
                                                              K + r'\Setup\Microsoft Visual Studio\ProductDir')
@@ -1237,13 +1409,13 @@ def get_msvs_install_dirs(version = None):
         except SCons.Util.RegError:
             pass
 
-    return rv;
+    return rv
 
 def GetMSVSProjectSuffix(target, source, env, for_signature):
-     return env['MSVS']['PROJECTSUFFIX'];
+     return env['MSVS']['PROJECTSUFFIX']
 
 def GetMSVSSolutionSuffix(target, source, env, for_signature):
-     return env['MSVS']['SOLUTIONSUFFIX'];
+     return env['MSVS']['SOLUTIONSUFFIX']
 
 def GenerateProject(target, source, env):
     # generate the dsp file, according to the version of MSVS.
@@ -1494,7 +1666,8 @@ def generate(env):
         # find them on their own.
         pass
 
-    if (float(env['MSVS_VERSION']) < 7.0):
+    version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
+    if (version_num < 7.0):
         env['MSVS']['PROJECTSUFFIX']  = '.dsp'
         env['MSVS']['SOLUTIONSUFFIX'] = '.dsw'
     else:
@@ -1514,7 +1687,10 @@ def exists(env):
         pass
 
     if not v:
-        if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+        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')
index 53198d45b32909f8fc1a4650038d1868481d3d56..6095dff6e648f35a030d730bb685bc5696aea4a9 100644 (file)
@@ -43,10 +43,6 @@ regdata_6a = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudi
 "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]
@@ -66,10 +62,6 @@ regdata_6b = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudi
 [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'''
@@ -136,93 +128,159 @@ regdata_7 = string.split(r'''
 "Include Dirs"="$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include\prerelease;$(VCInstallDir)PlatformSDK\include;$(FrameworkSDKDir)include"
 "Source Dirs"="$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src"
 "Reference Dirs"=""
-[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
-"ProgramFilesDir"="C:\Program Files"
-"CommonFilesDir"="C:\Program Files\Common Files"
-"MediaPath"="C:\WINDOWS\Media"
 ''','\n')
 
-regdata_67 = string.split(r'''
-[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\VisualStudio\7.0]
-"InstallDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
-"Source Directories"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\crt\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\mfc\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\atl\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts]
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\CrystalReports]
-@="#15007"
-"Package"="{F05E92C6-8346-11D3-B4AD-00A0C9B04E7B}"
-"ProductDetails"="#15009"
-"LogoID"="0"
-"PID"="#15008"
-"UseInterface"=dword:00000001
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual Basic.NET]
+regdata_7_1 = string.split(r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1]
 @=""
-"DefaultProductAttribute"="VB"
+"Source Directories"="C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\;C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\mfc\;C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\atl\"
+"ThisVersionSolutionCLSID"="{246C57AE-40DD-4d6b-9E8D-B0F5757BB2A8}"
+"ThisVersionDTECLSID"="{8CD2DD97-4EC1-4bc4-9359-89A3EEDD57A6}"
+"InstallDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\"
+"CLR Version"="v1.1.4322"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts\Smart Device Extensions]
+"UseInterface"=dword:00000001
+"VS7InstallDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\"
+"VBDeviceInstallDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\VB7\"
+"CSharpDeviceInstallDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts\Visual Basic.NET]
+"UseInterface"=dword:00000001
 "Package"="{164B10B9-B200-11D0-8C61-00A0C91E29D5}"
+"DefaultProductAttribute"="VB"
+@=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts\Visual C#]
+"DefaultProductAttribute"="C#"
 "UseInterface"=dword:00000001
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual C#]
+"Package"="{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}"
 @=""
-"Package"="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts\Visual JSharp]
+@=""
+"Package"="{E6FDF8B0-F3D1-11D4-8576-0002A516ECE8}"
 "UseInterface"=dword:00000001
-"DefaultProductAttribute"="C#"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\VisualC++]
+"DefaultProductAttribute"="Visual JSharp"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\InstalledProducts\VisualC++]
 "UseInterface"=dword:00000001
 "Package"="{F1C25864-3097-11D2-A5C5-00C04F7968B4}"
 "DefaultProductAttribute"="VC"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup]
-"Dbghelp_path"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
-"dw_dir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\MSDN]
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Msdn\1033\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Servicing\SKU]
-"Visual Studio .NET Professional - English"="{D0610409-7D65-11D5-A54F-0090278A1BB8}"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VB]
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vb7\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC]
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC#]
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\VC#\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Visual Studio .NET Professional - English]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup]
+"Dbghelp_path"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\"
+"dw_dir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\CSDPROJ]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\JSHPROJ]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\VJ#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\Servicing]
+"CurrentSULevel"=dword:00000000
+"CurrentSPLevel"=dword:00000000
+"Server Path"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\Servicing\Package]
+"FxSDK"=""
+"VB"=""
+"VC"=""
+"VCS"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\Servicing\SKU]
+"Visual Studio .NET Professional 2003 - English"="{20610409-CA18-41A6-9E21-A93AE82EE7C5}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VB]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VBDPROJ]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Vb7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VC]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VC#]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\VC#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\Visual Studio .NET Professional 2003 - English]
 "InstallSuccess"=dword:00000001
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS]
-"EnvironmentDirectory"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
-"EnvironmentPath"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
-"VS7EnvironmentLocation"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VS]
+"EnvironmentDirectory"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\"
+"EnvironmentPath"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.exe"
+"VS7EnvironmentLocation"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.exe"
 "MSMDir"="C:\Program Files\Common Files\Merge Modules\"
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
-"VS7CommonBinDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\Tools\"
-"VS7CommonDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\"
-"VSUpdateDir"="C:\Program Files\Microsoft Visual Studio .NET\Setup\VSUpdate\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\BuildNumber]
-"1033"="7.0.9466"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\Pro]
-"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC]
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO]
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32]
-@="{A54AAE91-30C2-11D3-87BF-A04A4CC10000}"
-[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]
-"Path Dirs"="$(VCInstallDir)bin;$(VSInstallDir)Common7\Tools\bin\prerelease;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;C:\Program Files\HTML Help Workshop\;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);C:\perl\bin;C:\cygwin\bin;c:\cygwin\usr\bin;C:\bin;C:\program files\perforce;C:\cygwin\usr\local\bin\i686-pc-cygwin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem"
+"VS7CommonBinDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\"
+"VS7CommonDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\"
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\"
+"VSUpdateDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\Setup\VSUpdate\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VS\BuildNumber]
+"1033"="7.1.3088"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\Setup\VS\Pro]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET 2003\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\VC]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\VC\VC_OBJECTS_PLATFORM_INFO]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\VC\VC_OBJECTS_PLATFORM_INFO\Win32]
+@="{759354D0-6B42-4705-AFFB-56E34D2BC3D4}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]
+"Path Dirs"="$(VCInstallDir)bin;$(VSInstallDir)Common7\Tools\bin\prerelease;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;C:\Program Files\HTML Help Workshop\;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);C:\Perl\bin\;c:\bin;c:\cygwin\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Common Files\Avid;C:\Program Files\backburner 2\;C:\Program Files\cvsnt;C:\Program Files\Subversion\bin;C:\Program Files\Common Files\Adobe\AGL;C:\Program Files\HTMLDoc"
 "Library Dirs"="$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)PlatformSDK\lib\prerelease;$(VCInstallDir)PlatformSDK\lib;$(FrameworkSDKDir)lib"
 "Include Dirs"="$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include\prerelease;$(VCInstallDir)PlatformSDK\include;$(FrameworkSDKDir)include"
 "Source Dirs"="$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src"
-"Reference Dirs"=""
-[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"Reference Dirs"="$(FrameWorkDir)$(FrameWorkVersion)"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\VC\VC_OBJECTS_PLATFORM_INFO\Win32\ToolDefaultExtensionLists]
+"VCCLCompilerTool"="*.cpp;*.cxx;*.cc;*.c"
+"VCLinkerTool"="*.obj;*.res;*.lib;*.rsc"
+"VCLibrarianTool"="*.obj;*.res;*.lib;*.rsc"
+"VCMIDLTool"="*.idl;*.odl"
+"VCCustomBuildTool"="*.bat"
+"VCResourceCompilerTool"="*.rc"
+"VCPreBuildEventTool"="*.bat"
+"VCPreLinkEventTool"="*.bat"
+"VCPostBuildEventTool"="*.bat"
+"VCBscMakeTool"="*.sbr"
+"VCNMakeTool"=""
+"VCWebServiceProxyGeneratorTool"="*.discomap"
+"VCWebDeploymentTool"=""
+"VCALinkTool"="*.resources"
+"VCManagedResourceCompilerTool"="*.resx"
+"VCXMLDataGeneratorTool"="*.xsd"
+"VCManagedWrapperGeneratorTool"=""
+"VCAuxiliaryManagedWrapperGeneratorTool"=""
+"VCPrimaryInteropTool"=""
+''','\n')
+
+regdata_8exp = string.split(r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0]
+"CLR Version"="v2.0.50727"
+"ApplicationID"="VCExpress"
+"SecurityAppID"="{741726F6-1EAE-4680-86A6-6085E8872CF8}"
+"InstallDir"="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\"
+"EnablePreloadCLR"=dword:00000001
+"RestoreAppPath"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\InstalledProducts]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\InstalledProducts\Microsoft Visual C++]
+"UseInterface"=dword:00000001
+"Package"="{F1C25864-3097-11D2-A5C5-00C04F7968B4}"
+"DefaultProductAttribute"="VC"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\Setup]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\Setup\VC]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio 8\VC\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\Setup\VS]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio 8\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\VC]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\VC\VC_OBJECTS_PLATFORM_INFO]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32]
+@="{72f11281-2429-11d7-8bf6-00b0d03daa06}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VCExpress\8.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32\ToolDefaultExtensionLists]
+"VCCLCompilerTool"="*.cpp;*.cxx;*.cc;*.c"
+"VCLinkerTool"="*.obj;*.res;*.lib;*.rsc;*.licenses"
+"VCLibrarianTool"="*.obj;*.res;*.lib;*.rsc"
+"VCMIDLTool"="*.idl;*.odl"
+"VCCustomBuildTool"="*.bat"
+"VCResourceCompilerTool"="*.rc"
+"VCPreBuildEventTool"="*.bat"
+"VCPreLinkEventTool"="*.bat"
+"VCPostBuildEventTool"="*.bat"
+"VCBscMakeTool"="*.sbr"
+"VCFxCopTool"="*.dll;*.exe"
+"VCNMakeTool"=""
+"VCWebServiceProxyGeneratorTool"="*.discomap"
+"VCWebDeploymentTool"=""
+"VCALinkTool"="*.resources"
+"VCManagedResourceCompilerTool"="*.resx"
+"VCXMLDataGeneratorTool"="*.xsd"
+"VCManifestTool"="*.manifest"
+"VCXDCMakeTool"="*.xdc"
+''','\n')
+
+regdata_cv = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
 "ProgramFilesDir"="C:\Program Files"
 "CommonFilesDir"="C:\Program Files\Common Files"
 "MediaPath"="C:\WINDOWS\Media"
@@ -270,7 +328,7 @@ class RegNode:
             return (self.valdict[val],1)
         else:
             raise SCons.Util.RegError
-    
+
     def addValue(self,name,val):
         self.valdict[name] = val
         self.valarray.append(name)
@@ -299,13 +357,13 @@ class RegNode:
             raise SCons.Util.RegError
 
     def addKey(self,name,sep = '\\'):
-        if name.find(sep) != -1:
-            keyname, subkeys = name.split(sep,1)
+        if string.find(name, sep) != -1:
+            keyname, subkeys = string.split(name, sep, 1)
         else:
             keyname = name
             subkeys = ""
 
-        if not self.keydict.has_key(keyname):       
+        if not self.keydict.has_key(keyname):
             self.keydict[keyname] = RegNode(keyname)
             self.keyarray.append(keyname)
 
@@ -340,9 +398,9 @@ class DummyRegistry:
         self.root.addKey('HKEY_CURRENT_USER')
         self.root.addKey('HKEY_USERS')
         self.root.addKey('HKEY_CLASSES_ROOT')
-        
+
         self.parse(data)
-        
+
     def parse(self, data):
         parent = self.root
         keymatch = re.compile('^\[(.*)\]$')
@@ -368,7 +426,7 @@ class DummyRegistry:
             mykey = 'HKEY_LOCAL_MACHINE\\' + key
         #print "Open Key",mykey
         return self.root.key(mykey)
-        
+
 def DummyOpenKeyEx(root, key):
     return registry.OpenKeyEx(root,key)
 
@@ -395,98 +453,171 @@ def DummyExists(path):
     return 1
 
 class msvsTestCase(unittest.TestCase):
+    def setUp(self):
+        global registry
+        registry = self.registry
+
     def test_get_default_visual_studio_version(self):
         """Test retrieval of the default visual studio version"""
         env = DummyEnv()
         v1 = get_default_visualstudio_version(env)
-        assert env['MSVS_VERSION'] == default_version
-        assert env['MSVS']['VERSION'] == default_version
-        assert v1 == default_version
+        assert env['MSVS_VERSION'] == self.default_version, env['MSVS_VERSION']
+        assert env['MSVS']['VERSION'] == self.default_version, env['MSVS']['VERSION']
+        assert v1 == self.default_version, v1
 
         env = DummyEnv({'MSVS_VERSION':'7.0'})
         v2 = get_default_visualstudio_version(env)
-        assert env['MSVS_VERSION'] == '7.0'
-        assert env['MSVS']['VERSION'] == '7.0'
-        assert v2 == '7.0'
+        assert env['MSVS_VERSION'] == '7.0', env['MSVS_VERSION']
+        assert env['MSVS']['VERSION'] == '7.0', env['MSVS']['VERSION']
+        assert v2 == '7.0', v2
 
     def test_get_visual_studio_versions(self):
         """Test retrieval of the list of visual studio versions"""
         v1 = get_visualstudio_versions()
-        assert not v1 or v1[0] == highest_version
-        assert len(v1) == number_of_versions
+        assert not v1 or v1[0] == self.highest_version, v1
+        assert len(v1) == self.number_of_versions, v1
 
     def test_get_msvs_install_dirs(self):
         """Test retrieval of the list of visual studio installed locations"""
         v1 = get_msvs_install_dirs()
-        v2 = get_msvs_install_dirs('7.0')
-        assert v1 == install_location1
-        assert v2 == install_location2
-        
-if __name__ == "__main__":
-
-    # only makes sense to test this on win32
-    if sys.platform != 'win32':
-        sys.exit(0)
-    
-    SCons.Util.RegOpenKeyEx = DummyOpenKeyEx
-    SCons.Util.RegEnumKey = DummyEnumKey
-    SCons.Util.RegEnumValue = DummyEnumValue
-    SCons.Util.RegQueryValueEx = DummyQueryValue
-    os.path.exists = DummyExists # make sure all files exist :-)
-
-    # try it for each possible setup.
-    suite = unittest.makeSuite(msvsTestCase, 'test_')
-    registry = DummyRegistry(regdata_6a)
+        assert v1 == self.default_install_loc, v1
+        for key, loc in self.install_locs.items():
+            v2 = get_msvs_install_dirs(key)
+            assert v2 == loc, key + ': ' + str(v2)
+
+class msvs6aTestCase(msvsTestCase):
+    """Test MSVS 6 Registry"""
+    registry = DummyRegistry(regdata_6a + regdata_cv)
     default_version = '6.0'
     highest_version = '6.0'
     number_of_versions = 1
-    install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio\\VC98'}
-    install_location2 = {}
-    print "Test MSVS 6 Registry"
-    # print str(registry.root)
-    if not unittest.TextTestRunner().run(suite).wasSuccessful():
-        sys.exit(1)
-
-    registry = DummyRegistry(regdata_6b)
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio\\VC98'},
+        '7.0' : {},
+        '7.1' : {},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['6.0']
+
+class msvs6bTestCase(msvsTestCase):
+    """Test Other MSVS 6 Registry"""
+    registry = DummyRegistry(regdata_6b + regdata_cv)
     default_version = '6.0'
     highest_version = '6.0'
     number_of_versions = 1
-    install_location1 = {'VSINSTALLDIR': 'C:\\VS6', 'VCINSTALLDIR': 'C:\\VS6\\VC98'}
-    install_location2 = {}        
-    print "Test Other MSVS 6 Registry"
-    # print str(registry.root)
-    if not unittest.TextTestRunner().run(suite).wasSuccessful():
-        sys.exit(1)
-
-    registry = DummyRegistry(regdata_67)
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\VS6', 'VCINSTALLDIR': 'C:\\VS6\\VC98'},
+        '7.0' : {},
+        '7.1' : {},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['6.0']
+
+class msvs6and7TestCase(msvsTestCase):
+    """Test MSVS 6 & 7 Registry"""
+    registry = DummyRegistry(regdata_6b + regdata_7 + regdata_cv)
     default_version = '7.0'
     highest_version = '7.0'
     number_of_versions = 2
-    install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
-    install_location2 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
-    # print str(registry.root)
-    print "Test MSVS 6 & 7 Registry"
-    if not unittest.TextTestRunner().run(suite).wasSuccessful():
-        sys.exit(1)
-
-    registry = DummyRegistry(regdata_7)
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\VS6', 'VCINSTALLDIR': 'C:\\VS6\\VC98'},
+        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'},
+        '7.1' : {},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['7.0']
+
+class msvs7TestCase(msvsTestCase):
+    """Test MSVS 7 Registry"""
+    registry = DummyRegistry(regdata_7 + regdata_cv)
     default_version = '7.0'
     highest_version = '7.0'
     number_of_versions = 1
-    install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
-    install_location2 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
-    # print str(registry.root)
-    print "Test MSVS 7 Registry"
-    if not unittest.TextTestRunner().run(suite).wasSuccessful():
-        sys.exit(1)
-
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio'},
+        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'},
+        '7.1' : {},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['7.0']
+
+class msvs71TestCase(msvsTestCase):
+    """Test MSVS 7.1 Registry"""
+    registry = DummyRegistry(regdata_7_1 + regdata_cv)
+    default_version = '7.1'
+    highest_version = '7.1'
+    number_of_versions = 1
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio'},
+        '7.0' : {},
+        '7.1' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\Vc7\\'},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['7.1']
+
+class msvs8ExpTestCase(msvsTestCase):
+    """Test MSVS 8 Express Registry"""
+    registry = DummyRegistry(regdata_8exp + regdata_cv)
+    default_version = '8.0Exp'
+    highest_version = '8.0Exp'
+    number_of_versions = 1
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio'},
+        '7.0' : {},
+        '7.1' : {},
+        '8.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\'},
+        '8.0Exp' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\VC\\'},
+    }
+    default_install_loc = install_locs['8.0Exp']
+
+class msvsEmptyTestCase(msvsTestCase):
+    """Test Empty Registry"""
     registry = DummyRegistry(regdata_none)
     default_version = '6.0'
     highest_version = None
     number_of_versions = 0
-    install_location1 = {}
-    install_location2 = {}
-    # print str(registry.root)
-    print "Test Empty Registry"
-    if not unittest.TextTestRunner().run(suite).wasSuccessful():
-        sys.exit(1)
+    install_locs = {
+        '6.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio'},
+        '7.0' : {},
+        '7.1' : {},
+        '8.0' : {},
+        '8.0Exp' : {},
+    }
+    default_install_loc = install_locs['8.0Exp']
+
+if __name__ == "__main__":
+
+    # only makes sense to test this on win32
+    if sys.platform != 'win32':
+        sys.exit(0)
+
+    SCons.Util.RegOpenKeyEx = DummyOpenKeyEx
+    SCons.Util.RegEnumKey = DummyEnumKey
+    SCons.Util.RegEnumValue = DummyEnumValue
+    SCons.Util.RegQueryValueEx = DummyQueryValue
+    os.path.exists = DummyExists # make sure all files exist :-)
+
+    exit_val = 0
+
+    test_classes = [
+        msvs6aTestCase,
+        msvs6bTestCase,
+        msvs6and7TestCase,
+        msvs7TestCase,
+        msvs71TestCase,
+        msvs8ExpTestCase,
+        msvsEmptyTestCase,
+    ]
+
+    for test_class in test_classes:
+        print test_class.__doc__
+        suite = unittest.makeSuite(test_class, 'test_')
+        if not unittest.TextTestRunner().run(suite).wasSuccessful():
+            exit_val = 1
+
+    sys.exit(exit_val)
diff --git a/test/MSVS/vs-8.0-exec.py b/test/MSVS/vs-8.0-exec.py
new file mode 100644 (file)
index 0000000..4554904
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#
+# __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__"
+
+"""
+Test that we can actually build a simple program using our generated
+Visual Studio 8.0 project (.vcproj) and solution (.sln) files.
+"""
+
+import os
+import sys
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+    msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
+    test.skip_test(msg)
+
+if not '8.0' in test.msvs_versions():
+    msg = "Visual Studio 8.0 not installed; skipping test.\n"
+    test.skip_test(msg)
+
+
+
+# Let SCons figure out the Visual Studio environment variables for us and
+# print out a statement that we can exec to suck them into our external
+# environment so we can execute devenv and really try to build something.
+
+test.run(arguments = '-n -q -Q -f -', stdin = """\
+env = Environment(tools = ['msvc'])
+print "os.environ.update(%s)" % repr(env['ENV'])
+""")
+
+exec(test.stdout())
+
+
+
+test.subdir('sub dir')
+
+test.write(['sub dir', 'SConstruct'], """\
+env=Environment(MSVS_VERSION = '8.0')
+
+env.MSVSProject(target = 'foo.vcproj',
+                srcs = ['foo.c'],
+                buildtarget = 'foo.exe',
+                variant = 'Release')
+
+env.Program('foo.c')
+""")
+
+test.write(['sub dir', 'foo.c'], r"""
+int
+main(int argc, char *argv)
+{
+    printf("foo.c\n");
+    exit (0);
+}
+""")
+
+test.run(chdir='sub dir', arguments='.')
+
+test.vcproj_sys_path(test.workpath('sub dir', 'foo.vcproj'))
+
+test.run(chdir='sub dir',
+         program=['devenv'],
+         arguments=['foo.sln', '/build', 'Release'])
+
+test.run(program=test.workpath('sub dir', 'foo'), stdout="foo.c\n")
+
+
+
+test.pass_test()
diff --git a/test/MSVS/vs-8.0-files.py b/test/MSVS/vs-8.0-files.py
new file mode 100644 (file)
index 0000000..65d8246
--- /dev/null
@@ -0,0 +1,332 @@
+#!/usr/bin/env python
+#
+# __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__"
+
+"""
+Test that we can generate Visual Studio 8.0 project (.vcproj) and
+solution (.sln) files that look correct.
+"""
+
+import os
+import os.path
+import sys
+
+import TestCmd
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+if sys.platform != 'win32':
+    msg = "Skipping Visual Studio test on non-Windows platform '%s'\n" % sys.platform
+    test.skip_test(msg)
+
+expected_slnfile = """\
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcproj", "{SLNGUID}"
+EndProject
+Global
+\tGlobalSection(SolutionConfigurationPlatforms) = preSolution
+\t\tRelease|Win32 = Release|Win32
+\tEndGlobalSection
+\tGlobalSection(ProjectConfigurationPlatforms) = postSolution
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release|Win32.ActiveCfg = Release|Win32
+\t\t{E5466E26-0003-F18B-8F8A-BCD76C86388D}.Release|Win32.Build.0 = Release|Win32
+\tEndGlobalSection
+\tGlobalSection(SolutionProperties) = preSolution
+\t\tHideSolutionNode = FALSE
+\tEndGlobalSection
+EndGlobal
+"""
+
+expected_vcprojfile = """\
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+\tProjectType="Visual C++"
+\tVersion="8.00"
+\tName="Test"
+\tProjectGUID="<PROJECT_GUID>"
+\tSccProjectName=""
+\tSccLocalPath=""
+\tRootNamespace="Test"
+\tKeyword="MakeFileProj">
+\t<Platforms>
+\t\t<Platform
+\t\t\tName="Win32"/>
+\t</Platforms>
+\t<ToolFiles>
+\t</ToolFiles>
+\t<Configurations>
+\t\t<Configuration
+\t\t\tName="Release|Win32"
+\t\t\tConfigurationType="0"
+\t\t\tUseOfMFC="0"
+\t\t\tATLMinimizesCRunTimeLibraryUsage="false"
+\t\t\t>
+\t\t\t<Tool
+\t\t\t\tName="VCNMakeTool"
+\t\t\t\tBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C &quot;<WORKPATH>&quot; -f SConstruct Test.exe"
+\t\t\t\tReBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C &quot;<WORKPATH>&quot; -f SConstruct Test.exe"
+\t\t\t\tCleanCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C &quot;<WORKPATH>&quot; -f SConstruct -c Test.exe"
+\t\t\t\tOutput="Test.exe"
+\t\t\t\tPreprocessorDefinitions=""
+\t\t\t\tIncludeSearchPath=""
+\t\t\t\tForcedIncludes=""
+\t\t\t\tAssemblySearchPath=""
+\t\t\t\tForcedUsingAssemblies=""
+\t\t\t\tCompileAsManaged=""
+\t\t\t/>
+\t\t</Configuration>
+\t</Configurations>
+\t<References>
+\t</References>
+\t<Files>
+\t\t<Filter
+\t\t\tName="Header Files"
+\t\t\tFilter="h;hpp;hxx;hm;inl">
+\t\t\t<File
+\t\t\t\tRelativePath="sdk.h">
+\t\t\t</File>
+\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Local Headers"
+\t\t\tFilter="h;hpp;hxx;hm;inl">
+\t\t\t<File
+\t\t\t\tRelativePath="test.h">
+\t\t\t</File>
+\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Other Files"
+\t\t\tFilter="">
+\t\t\t<File
+\t\t\t\tRelativePath="readme.txt">
+\t\t\t</File>
+\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Resource Files"
+\t\t\tFilter="r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">
+\t\t\t<File
+\t\t\t\tRelativePath="test.rc">
+\t\t\t</File>
+\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Source Files"
+\t\t\tFilter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
+\t\t\t<File
+\t\t\t\tRelativePath="test.cpp">
+\t\t\t</File>
+\t\t</Filter>
+\t\t<File
+\t\t\tRelativePath="<SCONSCRIPT>">
+\t\t</File>
+\t</Files>
+\t<Globals>
+\t</Globals>
+</VisualStudioProject>
+"""
+
+
+
+SConscript_contents = """\
+env=Environment(MSVS_VERSION = '8.0')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+env.MSVSProject(target = 'Test.vcproj',
+                slnguid = '{SLNGUID}',
+                srcs = testsrc,
+                incs = testincs,
+                localincs = testlocalincs,
+                resources = testresources,
+                misc = testmisc,
+                buildtarget = 'Test.exe',
+                variant = 'Release')
+"""
+
+
+
+test.subdir('work1')
+
+test.write(['work1', 'SConstruct'], SConscript_contents)
+
+test.run(chdir='work1', arguments="Test.vcproj")
+
+test.must_exist(test.workpath('work1', 'Test.vcproj'))
+vcproj = test.read(['work1', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work1', 'Test.sln'))
+sln = test.read(['work1', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '8.0', 'work1', 'SConstruct')
+# don't compare the pickled data
+assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+
+test.run(chdir='work1', arguments='-c .')
+
+test.must_not_exist(test.workpath('work1', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work1', 'Test.sln'))
+
+test.run(chdir='work1', arguments='Test.vcproj')
+
+test.must_exist(test.workpath('work1', 'Test.vcproj'))
+test.must_exist(test.workpath('work1', 'Test.sln'))
+
+test.run(chdir='work1', arguments='-c Test.sln')
+
+test.must_not_exist(test.workpath('work1', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work1', 'Test.sln'))
+
+
+
+# Test that running SCons with $PYTHON_ROOT in the environment
+# changes the .vcproj output as expected.
+os.environ['PYTHON_ROOT'] = 'xyzzy'
+
+test.run(chdir='work1', arguments='Test.vcproj')
+
+python = os.path.join('$(PYTHON_ROOT)', os.path.split(sys.executable)[1])
+
+test.must_exist(test.workpath('work1', 'Test.vcproj'))
+vcproj = test.read(['work1', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work1', 'SConstruct',
+                              python=python)
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+os.environ['PYTHON_ROOT'] = ''
+
+
+
+test.subdir('work2', ['work2', 'src'])
+
+test.write(['work2', 'SConstruct'], """\
+SConscript('src/SConscript', build_dir='build')
+""")
+
+test.write(['work2', 'src', 'SConscript'], SConscript_contents)
+
+test.run(chdir='work2', arguments=".")
+
+vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile,
+                              '7.0',
+                              'work2',
+                              'SConstruct',
+                              project_guid="{25F6CE89-8E22-2910-8B6E-FFE6DC1E2792}")
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
+sln = test.read(['work2', 'src', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '7.0',
+                              os.path.join('work2', 'src'))
+# don't compare the pickled data
+assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+
+test.must_match(['work2', 'build', 'Test.vcproj'], """\
+This is just a placeholder file.
+The real project file is here:
+%s
+""" % test.workpath('work2', 'src', 'Test.vcproj'),
+                mode='r')
+
+test.must_match(['work2', 'build', 'Test.sln'], """\
+This is just a placeholder file.
+The real workspace file is here:
+%s
+""" % test.workpath('work2', 'src', 'Test.sln'),
+                mode='r')
+
+
+
+test.subdir('work3')
+
+test.write(['work3', 'SConstruct'], """\
+env=Environment(MSVS_VERSION = '8.0')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+p = env.MSVSProject(target = 'Test.vcproj',
+                    srcs = testsrc,
+                    incs = testincs,
+                    localincs = testlocalincs,
+                    resources = testresources,
+                    misc = testmisc,
+                    buildtarget = 'Test.exe',
+                    variant = 'Release',
+                    auto_build_solution = 0)
+
+env.MSVSSolution(target = 'Test.sln',
+                 slnguid = '{SLNGUID}',
+                 projects = [p],
+                 variant = 'Release')
+""")
+
+test.run(chdir='work3', arguments=".")
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+vcproj = test.read(['work3', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '8.0', 'work3', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work3', 'Test.sln'))
+sln = test.read(['work3', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '8.0', 'work3', 'SConstruct')
+# don't compare the pickled data
+assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+
+test.run(chdir='work3', arguments='-c .')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='.')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.sln')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.vcproj')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+
+
+
+test.pass_test()