Commits

William Deegan committed ecf4ad3

In addition to changed merged below, commented out for platform os2 use of msvc, mslib, mslink
as they cause test/import.py to fail.
I don't have an OS2 system to resolve the issues on.

Merged revisions 4065,4067-4068,4071-4072,4074,4076,4085,4111,4163,4222 via svnmerge from
http://scons.tigris.org/svn/scons/branches/vs_revamp

................
r4065 | stevenknight | 2009-03-02 16:48:05 -0800 (Mon, 02 Mar 2009) | 42 lines

Copy over changes by hand from branches/core (I was working in a
directory pointing to the wrong branch):

........
r4059 | stevenknight | 2009-03-02 06:54:13 -0800 (Mon, 02 Mar 2009) | 14 lines

Initial prototypes of modules for architecture support (MSCommon/arch.py)
and Visual C/C++ configuration distinct from (and in preference to)
the Visual Studio configuration, incorporating configuration info and
ideas from Jason Kenny's latest parts/tools/MSCommon work.

This has a lot of cut-and-paste right now and does NOT actually work.
In particular, there are no changes to the rest of the infrastructure
to actually call any of this new stuff. I'm checking these in so I can
sync on other systems for continued development.

The ultimate goal is for much of the current MSCommon/vs.py module's
logic to migrate to MSCommon/vc.py, since that's what we're actually
interested in configuring.

........
r4058 | stevenknight | 2009-03-02 06:49:35 -0800 (Mon, 02 Mar 2009) | 2 lines

Fix doc string.

........
r4056 | stevenknight | 2009-03-01 06:10:31 -0800 (Sun, 01 Mar 2009) | 4 lines

Change the sanity_check file for 6.1 per Jason's update.
Add an optional version string argument to detect_sdk().
Import directly from common, not SCons.Tool.MSCommon.common.

........
r4055 | stevenknight | 2009-02-28 05:29:03 -0800 (Sat, 28 Feb 2009) | 5 lines

Minor common.py enhancements:
Refactor is_win64() to cache its return value so we don't have to hit
registry every time we want to know if the OS is 64-bit.
Accept SCONS_MSCOMMON_DEBUG=- to mean print debug messages to stdout.

........
................
r4067 | stevenknight | 2009-03-06 04:59:21 -0800 (Fri, 06 Mar 2009) | 4 lines

Fix entries in batch_file_map, after a double-check with the original code.
Use a host_architecture of None in the map to indicate the "default"
entry if there isn't a specific .bat file for our current architecture.
................
r4068 | stevenknight | 2009-03-06 05:15:39 -0800 (Fri, 06 Mar 2009) | 2 lines

Add include_subdir and lib_subdir data to the SDK definitions.
................
r4071 | stevenknight | 2009-03-10 07:42:53 -0700 (Tue, 10 Mar 2009) | 4 lines

Capture basically working snapshot.
src/engine/SCons/Tool/msvsTests.py and test/IDL/midl.py still fail,
and code needs clean up.
................
r4072 | stevenknight | 2009-03-11 06:38:37 -0700 (Wed, 11 Mar 2009) | 2 lines

Fix path to Common7\Tools. Find vs*.bat files.
................
r4074 | stevenknight | 2009-03-13 17:11:55 -0700 (Fri, 13 Mar 2009) | 3 lines

Import SCons.Tool.MSCommon.vc so it works regardless of other sys.path
manipulation.
................
r4076 | stevenknight | 2009-03-19 08:08:48 -0700 (Thu, 19 Mar 2009) | 7 lines

Refactor SDK support:
* New mssdk_exists() and mssdk_setup_env() methods as the primary
public entry points.
* Call internal sdk.*() utility functions that just return information
(like the SDK structure) not handle the actual setting.
* Give the VisualStudio definitions explicit settings for the SDK version.
................
r4085 | bdbaddog | 2009-04-05 14:30:46 -0700 (Sun, 05 Apr 2009) | 3 lines

Fix "can't find module vc" issue when building on windows.
................
r4111 | stevenknight | 2009-04-19 07:47:47 -0700 (Sun, 19 Apr 2009) | 2 lines

Doc updates for how MSVS_VERSION is used.
................
r4163 | bdbaddog | 2009-04-29 17:32:43 -0700 (Wed, 29 Apr 2009) | 4 lines

Fix for bug 2405
Also refactored some logic from Defaults._defines() into Defaults.processDefines() which is then used by msvs.py
................
r4222 | bdbaddog | 2009-05-31 17:01:22 -0700 (Sun, 31 May 2009) | 8 lines

Added definition of HOST_OS|ARCH TARGET_OS|ARCH (For win32 only right now)
Migrated some logic to determine arch from Tools/MSCommon -> Platform/Win32.py
Fixed lots of minor issues with string values for directories, architectures, and registry keys
Switch to find VS installs by registry (was using VC install location previously)

Added but commented out that HOST_{OS|ARCH} and TARGET_{OS|ARCH} will become reserved var names in Environment()
Need to resolve issues that SCons is issuing messages when SCons itself sets these variables.
................

Comments (0)

Files changed (28)

QMTest/TestSConsMSVS.py

 \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 &quot;Test.exe&quot;"
 \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 &quot;Test.exe&quot;"
 \t\t\t\tOutput="Test.exe"
-\t\t\t\tPreprocessorDefinitions="DEF1;DEF2"
+\t\t\t\tPreprocessorDefinitions="DEF1;DEF2;DEF3=1234"
 \t\t\t\tIncludeSearchPath="inc1;inc2"
 \t\t\t\tForcedIncludes=""
 \t\t\t\tAssemblySearchPath=""
 
 SConscript_contents_8_0 = """\
 env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='8.0',
-                CPPDEFINES=['DEF1', 'DEF2'],
+                CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')],
                 CPPPATH=['inc1', 'inc2'])
 
 testsrc = ['test1.cpp', 'test2.cpp']

src/engine/MANIFEST-xml.in

 SCons/Tool/as.xml
 SCons/Tool/bcc32.xml
 SCons/Tool/c++.xml
+SCons/Tool/c++.xml
 SCons/Tool/cc.xml
 SCons/Tool/cvf.xml
 SCons/Tool/default.xml
 SCons/Tool/g77.xml
 SCons/Tool/gas.xml
 SCons/Tool/gcc.xml
+SCons/Tool/gfortran.xml
 SCons/Tool/gnulink.xml
 SCons/Tool/gs.xml
 SCons/Tool/hpc++.xml
 SCons/Tool/sunar.xml
 SCons/Tool/sunc++.xml
 SCons/Tool/suncc.xml
+SCons/Tool/sunf77.xml
+SCons/Tool/sunf90.xml
+SCons/Tool/sunf95.xml
 SCons/Tool/sunlink.xml
 SCons/Tool/swig.xml
 SCons/Tool/tar.xml

src/engine/MANIFEST.in

 SCons/Tool/link.py
 SCons/Tool/linkloc.py
 SCons/Tool/MSCommon/__init__.py
+SCons/Tool/MSCommon/arch.py
 SCons/Tool/MSCommon/common.py
 SCons/Tool/MSCommon/netframework.py
 SCons/Tool/MSCommon/sdk.py
 SCons/Tool/MSCommon/vs.py
+SCons/Tool/MSCommon/vc.py
 SCons/Tool/m4.py
 SCons/Tool/masm.py
 SCons/Tool/midl.py

src/engine/SCons/Defaults.py

 
     return c(prefix, stripped, suffix, env)
 
-def _defines(prefix, defs, suffix, env, c=_concat_ixes):
-    """A wrapper around _concat_ixes that turns a list or string
-    into a list of C preprocessor command-line definitions.
+def processDefines(defs):
+    """process defines, resolving strings, lists, dictionaries, into a list of
+    strings
     """
     if SCons.Util.is_List(defs):
         l = []
                 l.append(str(k) + '=' + str(v))
     else:
         l = [str(defs)]
-    return c(prefix, env.subst_path(l), suffix, env)
+    return l
+
+def _defines(prefix, defs, suffix, env, c=_concat_ixes):
+    """A wrapper around _concat_ixes that turns a list or string
+    into a list of C preprocessor command-line definitions.
+    """
+
+    return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
     
 class NullCmdGenerator:
     """This is a callable class that can be used in place of other

src/engine/SCons/Environment.py

     'UNCHANGED_TARGETS',
 ]
 
-future_reserved_construction_var_names = []
+future_reserved_construction_var_names = [
+    #'HOST_OS',
+    #'HOST_ARCH',
+    #'HOST_CPU',
+    ]
 
 def copy_non_reserved_keywords(dict):
     result = semi_deepcopy(dict)
             platform = SCons.Platform.Platform(platform)
         self._dict['PLATFORM'] = str(platform)
         platform(self)
+        
+        self._dict['HOST_OS']      = self._dict.get('HOST_OS',None)
+        self._dict['HOST_ARCH']    = self._dict.get('HOST_ARCH',None)
+        
+        # Now set defaults for TARGET_{OS|ARCH}
+        self._dict['TARGET_OS']      = self._dict.get('HOST_OS',None)
+        self._dict['TARGET_ARCH']    = self._dict.get('HOST_ARCH',None)
+        
 
         # Apply the passed-in and customizable variables to the
         # environment before calling the tools, because they may use

src/engine/SCons/Platform/__init__.xml

 </summary>
 </cvar>
 
+<cvar name="HOST_OS">
+    <summary>
+        The name of the host operating system used to create the Environment.
+        If a platform is specified when creating the Environment, then
+        that Platform's logic will handle setting this value.
+        This value is immutable, and should not be changed by the user after
+        the Environment is initialized.
+        Currently only set for Win32.
+    </summary>
+</cvar>
+
+<cvar name="HOST_ARCH">
+    <summary>
+        The name of the host hardware architecture used to create the Environment.
+        If a platform is specified when creating the Environment, then
+        that Platform's logic will handle setting this value.
+        This value is immutable, and should not be changed by the user after
+        the Environment is initialized.
+        Currently only set for Win32.
+    </summary>
+</cvar>
+
+<cvar name="TARGET_OS">
+    <summary>
+        The name of the target operating system for the compiled objects
+        created by this Environment.
+        This defaults to the value of HOST_OS, and the user can override it.
+        Currently only set for Win32.
+    </summary>
+</cvar>
+
+<cvar name="TARGET_ARCH">
+    <summary>
+        The name of the target hardware architecture for the compiled objects
+        created by this Environment.
+        This defaults to the value of HOST_ARCH, and the user can override it.
+        Currently only set for Win32.
+    </summary>
+</cvar>
+
+
 <cvar name="PROGPREFIX">
 <summary>
 The prefix used for executable file names.

src/engine/SCons/Platform/os2.py

 #
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+import win32
 
 def generate(env):
     if not env.has_key('ENV'):
     env['SHLIBSUFFIX']    = '.dll'
     env['LIBPREFIXES']    = '$LIBPREFIX'
     env['LIBSUFFIXES']    = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
+    env['HOST_OS']        = 'os2'
+    env['HOST_ARCH']      = win32.get_architecture().arch
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Platform/win32.py

 from SCons.Platform import TempFileMunge
 import SCons.Util
 
-
-
 try:
     import msvcrt
     import win32api
 
     _builtin_file = __builtin__.file
     _builtin_open = __builtin__.open
-
+    
     def _scons_file(*args, **kw):
         fp = apply(_builtin_file, args, kw)
         win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()),
         
     return val
 
+
+
+# Determine which windows CPU were running on.
+class ArchDefinition:
+    """
+    A class for defining architecture-specific settings and logic.
+    """
+    def __init__(self, arch, synonyms=[]):
+        self.arch = arch
+        self.synonyms = synonyms
+
+SupportedArchitectureList = [
+    ArchDefinition(
+        'x86',
+        ['i386', 'i486', 'i586', 'i686'],
+    ),
+
+    ArchDefinition(
+        'x86_64',
+        ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
+    ),
+
+    ArchDefinition(
+        'ia64',
+        ['IA64'],
+    ),
+]
+
+SupportedArchitectureMap = {}
+for a in SupportedArchitectureList:
+    SupportedArchitectureMap[a.arch] = a
+    for s in a.synonyms:
+        SupportedArchitectureMap[s] = a
+
+def get_architecture(arch=None):
+    """Returns the definition for the specified architecture string.
+
+    If no string is specified, the system default is returned (as defined
+    by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment
+    variables).
+    """
+    if arch is None:
+        arch = os.environ.get('PROCESSOR_ARCHITEW6432')
+        if not arch:
+            arch = os.environ['PROCESSOR_ARCHITECTURE']
+    return SupportedArchitectureMap.get(arch, '')
+
 def generate(env):
     # Attempt to find cmd.exe (for WinNT/2k/XP) or
     # command.com for Win9x
     env['TEMPFILEPREFIX'] = '@'
     env['MAXLINELENGTH']  = 2048
     env['ESCAPE']         = escape
+    
+    env['HOST_OS']        = 'win32'
+    env['HOST_ARCH']      = get_architecture().arch
+    
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/MSCommon/__init__.py

 import SCons.Platform.win32
 import SCons.Util
 
-from SCons.Tool.MSCommon.vs import detect_msvs, \
-                                   get_default_version, \
+from SCons.Tool.MSCommon.sdk import mssdk_exists, \
+                                    mssdk_setup_env
+
+from SCons.Tool.MSCommon.vc import msvc_exists, \
+                                   msvc_setup_env
+
+from SCons.Tool.MSCommon.vs import get_default_version, \
                                    get_vs_by_version, \
                                    merge_default_version, \
+                                   msvs_exists, \
                                    query_versions
 
 # Local Variables:

src/engine/SCons/Tool/MSCommon/arch.py

+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Module to define supported Windows chip architectures.
+"""
+
+import os
+
+class ArchDefinition:
+    """
+    A class for defining architecture-specific settings and logic.
+    """
+    def __init__(self, arch, synonyms=[]):
+        self.arch = arch
+        self.synonyms = synonyms
+
+SupportedArchitectureList = [
+    ArchitectureDefinition(
+        'x86',
+        ['i386', 'i486', 'i586', 'i686'],
+    ),
+
+    ArchitectureDefinition(
+        'x86_64',
+        ['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
+    ),
+
+    ArchitectureDefinition(
+        'ia64',
+        ['IA64'],
+    ),
+]
+
+SupportedArchitectureMap = {}
+for a in SupportedArchitectureList:
+    SupportedArchitectureMap[a.arch] = a
+    for s in a.synonyms:
+        SupportedArchitectureMap[s] = a
+

src/engine/SCons/Tool/MSCommon/common.py

 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
 __doc__ = """
-Common helper functions for working with
+Common helper functions for working with the Microsoft tool chain.
 """
 
 import copy
 
 
 logfile = os.environ.get('SCONS_MSCOMMON_DEBUG')
-if logfile:
+if logfile == '-':
+    def debug(x):
+        print x
+elif logfile:
     try:
         import logging
     except ImportError:
     debug = lambda x: None
 
 
-# TODO(sgk): unused
+_is_win64 = None
+
 def is_win64():
     """Return true if running on windows 64 bits."""
-    # Unfortunately, python does not seem to have anything useful: neither
-    # sys.platform nor os.name gives something different on windows running on
-    # 32 bits or 64 bits. Note that we don't care about whether python itself
-    # is 32 or 64 bits here
-    value = "Software\Wow6432Node"
-    yo = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0]
-    if yo is None:
-        return 0
-    else:
-        return 1
+    # Unfortunately, python does not provide a useful way to determine
+    # if the underlying Windows OS is 32-bit or 64-bit.  Worse, whether
+    # the Python itself is 32-bit or 64-bit affects what it returns,
+    # so nothing in sys.* or os.* help.  So we go to the registry to
+    # look directly for a clue from Windows, caching the result to
+    # avoid repeated registry calls.
+    global _is_win64
+    if _is_win64 is None:
+        try:
+            yo = read_reg(r'Software\Wow6432Node')
+        except WindowsError:
+            yo = None
+        _is_win64 = (yo is not None)
+    return _is_win64
+
 
 def read_reg(value):
     return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0]

src/engine/SCons/Tool/MSCommon/sdk.py

 import os
 
 import SCons.Errors
-from SCons.Tool.MSCommon.common import debug, read_reg
 import SCons.Util
 
+import common
+
+debug = common.debug
+
 # SDK Checks. This is of course a mess as everything else on MS platforms. Here
 # is what we do to detect the SDK:
 #
         Return None if failed or the directory does not exist.
         """
         if not SCons.Util.can_read_reg:
-            debug('find_sdk_dir():  can not read registry')
+            debug('find_sdk_dir(): can not read registry')
             return None
 
         hkey = self.HKEY_FMT % self.hkey_data
 
         try:
-            sdk_dir = read_reg(hkey)
+            sdk_dir = common.read_reg(hkey)
         except WindowsError, e:
-            debug('find_sdk_dir(): no registry key %s' % hkey)
+            debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey))
             return None
 
         if not os.path.exists(sdk_dir):
 
         ftc = os.path.join(sdk_dir, self.sanity_check_file)
         if not os.path.exists(ftc):
-            debug("find_sdk_dir():  sanity check %s not found" % ftc)
+            debug("find_sdk_dir(): sanity check %s not found" % ftc)
             return None
 
         return sdk_dir
 # If you update this list, update the documentation in Tool/mssdk.xml.
 SupportedSDKList = [
     WindowsSDK('6.1',
-                sanity_check_file=r'include\windows.h'),
+               sanity_check_file=r'bin\SetEnv.Cmd',
+               include_subdir='include',
+               lib_subdir={
+                   'x86'       : ['lib'],
+                   'x86_64'    : [r'lib\x64'],
+                   'ia64'      : [r'lib\ia64'],
+               },
+              ),
 
     WindowsSDK('6.0A',
-               sanity_check_file=r'include\windows.h'),
+               sanity_check_file=r'include\windows.h',
+               include_subdir='include',
+               lib_subdir={
+                   'x86'       : ['lib'],
+                   'x86_64'    : [r'lib\x64'],
+                   'ia64'      : [r'lib\ia64'],
+               },
+              ),
 
     WindowsSDK('6.0',
-               sanity_check_file=r'bin\gacutil.exe'),
+               sanity_check_file=r'bin\gacutil.exe',
+               include_subdir='include',
+               lib_subdir='lib',
+              ),
 
     PlatformSDK('2003R2',
                 sanity_check_file=r'SetEnv.Cmd',
-                uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"),
+                uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"
+               ),
 
     PlatformSDK('2003R1',
                 sanity_check_file=r'SetEnv.Cmd',
-                uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3"),
+                uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3",
+               ),
 ]
 
 SupportedSDKMap = {}
         return None
 
     try:
-        val = read_reg(_CURINSTALLED_SDK_HKEY_ROOT)
+        val = common.read_reg(_CURINSTALLED_SDK_HKEY_ROOT)
         debug("Found current sdk dir in registry: %s" % val)
     except WindowsError, e:
         debug("Did not find current sdk in registry")
 
     return val
 
-
-def detect_sdk():
-    return (len(get_installed_sdks()) > 0)
-
-def set_sdk_by_version(env, mssdk):
+def get_sdk_by_version(mssdk):
     if not SupportedSDKMap.has_key(mssdk):
         msg = "SDK version %s is not supported" % repr(mssdk)
         raise SCons.Errors.UserError, msg
     get_installed_sdks()
-    sdk = InstalledSDKMap.get(mssdk)
-    if not sdk:
-        msg = "SDK version %s is not installed" % repr(mssdk)
-        raise SCons.Errors.UserError, msg
-    set_sdk_by_directory(env, sdk.get_sdk_dir())
+    return InstalledSDKMap.get(mssdk)
 
-def set_default_sdk(env, msver):
+def get_default_sdk():
     """Set up the default Platform/Windows SDK."""
-    # For MSVS < 8, use integrated windows sdk by default
-    if msver >= 8:
-        sdks = get_installed_sdks()
-        if len(sdks) > 0:
-            set_sdk_by_directory(env, sdks[0].get_sdk_dir())
+    get_installed_sdks()
+    return InstalledSDKList[0]
+
+def mssdk_setup_env(env):
+    debug('msvs_setup_env()')
+    if env.has_key('MSSDK_DIR'):
+        sdk_dir = env['MSSDK_DIR']
+        if sdk_dir is None:
+            return
+        sdk_dir = env.subst(sdk_dir)
+    elif env.has_key('MSSDK_VERSION'):
+        sdk_version = env['MSSDK_VERSION']
+        if sdk_version is None:
+            msg = "SDK version %s is not installed" % repr(mssdk)
+            raise SCons.Errors.UserError, msg
+        sdk_version = env.subst(sdk_version)
+        mssdk = get_sdk_by_version(sdk_version)
+        sdk_dir = mssdk.get_sdk_dir()
+    elif env.has_key('MSVS_VERSION'):
+        msvs_version = env['MSVS_VERSION']
+        debug('Getting MSVS_VERSION from env:%s'%msvs_version)
+        if msvs_version is None:
+            return
+        msvs_version = env.subst(msvs_version)
+        import vs
+        msvs = vs.get_vs_by_version(msvs_version)
+        debug('msvs is :%s'%msvs)
+        sdk_version = msvs.sdk_version
+        if not sdk_version:
+            return
+        mssdk = get_sdk_by_version(sdk_version)
+        if not mssdk:
+            mssdk = get_default_sdk()
+            if not mssdk:
+                return
+        sdk_dir = mssdk.get_sdk_dir()
+    else:
+        mssdk = get_default_sdk()
+        if not mssdk:
+            return
+        sdk_dir = mssdk.get_sdk_dir()
+
+    set_sdk_by_directory(env, sdk_dir)
+
+    #print "No MSVS_VERSION: this is likely to be a bug"
+
+def mssdk_exists(version=None):
+    sdks = get_installed_sdks()
+    if version is None:
+        return len(sdks) > 0
+    return sdks.has_key(version)
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/MSCommon/vc.py

+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+__doc__ = """Module for Visual C/C++ detection and configuration.
+"""
+
+import os
+
+import SCons.Warnings
+
+import common
+
+debug = common.debug
+
+class VisualC:
+    """
+    An base class for finding installed versions of Visual C/C++.
+    """
+    def __init__(self, version, **kw):
+        self.version = version
+        self.__dict__.update(kw)
+        self._cache = {}
+
+    def vcbin_arch(self):
+        if common.is_win64():
+            result = {
+                'x86_64' : ['amd64', r'BIN\x86_amd64'],
+                'ia64'   : [r'BIN\ia64'],
+            }.get(target_arch, [])
+        else:
+            result = {
+                'x86_64' : ['x86_amd64'],
+                'ia64'   : ['x86_ia64'],
+            }.get(target_arch, [])
+        # TODO(1.5)
+        #return ';'.join(result)
+        return string.join(result, ';')
+
+    # Support for searching for an appropriate .bat file.
+    # The map is indexed by (target_architecture, host_architecture).
+    # Entries where the host_architecture is None specify the
+    # cross-platform "default" .bat file if there isn't sn entry
+    # specific to the current host architecture.
+
+    batch_file_map = {
+        ('x86_64', 'x86_64') : [
+            r'bin\amd64\vcvarsamd64.bat',
+            r'bin\x86_amd64\vcvarsx86_amd64.bat',
+        ],
+        ('x86_64', 'x86') : [
+            r'bin\x86_amd64\vcvarsx86_amd64.bat',
+        ],
+        ('ia64', 'ia64') : [
+            r'bin\ia64\vcvarsia64.bat',
+            r'bin\x86_ia64\vcvarsx86_ia64.bat',
+        ],
+        ('ia64', None) : [
+            r'bin\x86_ia64\vcvarsx86_ia64.bat',
+        ],
+        ('x86', None) : [
+            r'bin\vcvars32.bat',
+        ],
+    }
+
+    def find_batch_file(self, target_architecture, host_architecture):
+        key = (target_architecture, host_architecture)
+        potential_batch_files = self.batch_file_map.get(key)
+        if not potential_batch_files:
+            key = (target_architecture, None)
+            potential_batch_files = self.batch_file_map.get(key)
+        if potential_batch_files:
+            product_dir = self.get_vc_dir()
+            for batch_file in potential_batch_files:
+                bf = os.path.join(product_dir, batch_file)
+                if os.path.isfile(bf):
+                    return bf
+        return None
+
+    def find_vc_dir(self):
+        root = 'Software\\'
+        if common.is_win64():
+            root = root + 'Wow6432Node\\'
+        for key in self.hkeys:
+            key = root + key
+            try:
+                comps = common.read_reg(key)
+            except WindowsError, e:
+                debug('find_vc_dir(): no VC registry key %s' % repr(key))
+            else:
+                debug('find_vc_dir(): found VC in registry: %s' % comps)
+                return comps
+        return None
+
+    #
+
+    def get_batch_file(self, target_architecture, host_architecture):
+        try:
+            return self._cache['batch_file']
+        except KeyError:
+            batch_file = self.find_batch_file(target_architecture, host_architecture)
+            self._cache['batch_file'] = batch_file
+            return batch_file
+
+    def get_vc_dir(self):
+        try:
+            return self._cache['vc_dir']
+        except KeyError:
+            vc_dir = self.find_vc_dir()
+            self._cache['vc_dir'] = vc_dir
+            return vc_dir
+        
+    def reset(self):
+        self._cache={}
+        
+
+# The list of supported Visual C/C++ versions we know how to detect.
+#
+# The first VC found in the list is the one used by default if there
+# are multiple VC installed.  Barring good reasons to the contrary,
+# this means we should list VC with from most recent to oldest.
+#
+# If you update this list, update the documentation in Tool/vc.xml.
+SupportedVCList = [
+    VisualC('9.0',
+            hkeys=[
+                r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',
+                r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir',
+            ],
+            default_install=r'Microsoft Visual Studio 9.0\VC',
+            common_tools_var='VS90COMNTOOLS',
+            vc_subdir=r'\VC',
+            batch_file_base='vcvars',
+            supported_arch=['x86', 'x86_64', 'ia64'],
+            atlmc_include_subdir = [r'ATLMFC\INCLUDE'],
+            atlmfc_lib_subdir = {
+                'x86'       : r'ATLMFC\LIB',
+                'x86_64'    : r'ATLMFC\LIB\amd64',
+                'ia64'      : r'ATLMFC\LIB\ia64',
+            },
+            crt_lib_subdir = {
+                'x86_64'    : r'LIB\amd64',
+                'ia64'      : r'LIB\ia64',
+            },
+    ),
+    VisualC('8.0',
+            hkeys=[
+                r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir',
+                r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir',
+            ],
+            default_install=r'%s\Microsoft Visual Studio 8\VC',
+            common_tools_var='VS80COMNTOOLS',
+            vc_subdir=r'\VC',
+            batch_file_base='vcvars',
+            supported_arch=['x86', 'x86_64', 'ia64'],
+            atlmc_include_subdir = [r'ATLMFC\INCLUDE'],
+            atlmfc_lib_subdir = {
+                'x86'       : r'ATLMFC\LIB',
+                'x86_64'    : r'ATLMFC\LIB\amd64',
+                'ia64'      : r'ATLMFC\LIB\ia64',
+            },
+            crt_lib_subdir = {
+                'x86_64'    : r'LIB\amd64',
+                'ia64'      : r'LIB\ia64',
+            },
+    ),
+    VisualC('7.1',
+            hkeys=[
+                r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir',
+            ],
+            default_install=r'%s\Microsoft Visual Studio 7.1.NET 2003\VC7',
+            common_tools_var='VS71COMNTOOLS',
+            vc_subdir=r'\VC7',
+            batch_file_base='vcvars',
+            supported_arch=['x86'],
+            atlmc_include_subdir = [r'ATLMFC\INCLUDE'],
+            atlmfc_lib_subdir = {
+                'x86' : r'ATLMFC\LIB',
+            },
+    ),
+    VisualC('7.0',
+            hkeys=[
+                r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir',
+            ],
+            default_install=r'%s\Microsoft Visual Studio .NET\VC7',
+            common_tools_var='VS70COMNTOOLS',
+            vc_subdir=r'\VC7',
+            batch_file_base='vcvars',
+            supported_arch=['x86'],
+            atlmc_include_subdir = [r'ATLMFC\INCLUDE'],
+            atlmfc_lib_subdir = {
+                'x86' : r'ATLMFC\LIB',
+            },
+    ),
+    VisualC('6.0',
+            hkeys=[
+                r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir',
+            ],
+            default_install=r'%s\Microsoft Visual Studio\VC98',
+            common_tools_var='VS60COMNTOOLS',
+            vc_subdir=r'\VC98',
+            batch_file_base='vcvars',
+            supported_arch=['x86'],
+            atlmc_include_subdir = [r'ATL\INCLUDE', r'MFC\INCLUDE'],
+            atlmfc_lib_subdir = {
+                'x86' : r'MFC\LIB',
+            },
+    ),
+]
+
+SupportedVCMap = {}
+for vc in SupportedVCList:
+    SupportedVCMap[vc.version] = vc
+
+
+# Finding installed versions of Visual C/C++ isn't cheap, because it goes
+# not only to the registry but also to the disk to sanity-check that there
+# is, in fact, something installed there and that the registry entry isn't
+# just stale.  Find this information once, when requested, and cache it.
+
+InstalledVCList = None
+InstalledVCMap  = None
+
+def get_installed_vcs():
+    global InstalledVCList
+    global InstalledVCMap
+    if InstalledVCList is None:
+        InstalledVCList = []
+        InstalledVCMap = {}
+        for vc in SupportedVCList:
+            debug('trying to find VC %s' % vc.version)
+            if vc.get_vc_dir():
+                debug('found VC %s' % vc.version)
+                InstalledVCList.append(vc)
+                InstalledVCMap[vc.version] = vc
+    return InstalledVCList
+
+
+def set_vc_by_version(env, msvc):
+    if not SupportedVCMap.has_key(msvc):
+        msg = "VC version %s is not supported" % repr(msvc)
+        raise SCons.Errors.UserError, msg
+    get_installed_vcs()
+    vc = InstalledVCMap.get(msvc)
+    if not vc:
+        msg = "VC version %s is not installed" % repr(msvc)
+        raise SCons.Errors.UserError, msg
+    set_vc_by_directory(env, vc.get_vc_dir())
+
+# New stuff
+
+def script_env(script):
+    stdout = common.get_output(script)
+    return common.parse_output(stdout)
+
+def msvc_setup_env(env):
+    debug('msvc_setup_env()')
+    installed_vcs = get_installed_vcs()
+    msvc_version = env.get('MSVC_VERSION')
+    if not msvc_version:
+        if not installed_vcs:
+            msg = 'No installed VCs'
+            debug('msv %s\n' % repr(msg))
+            SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+            return
+        msvc = installed_vcs[0]
+        msvc_version = msvc.version
+        env['MSVC_VERSION'] = msvc_version
+    else:
+        msvc = InstalledVCMap.get(msvc_version)
+        if not msvc:
+            msg = 'VC version %s not installed' % msvc_version
+            debug('msv %s\n' % repr(msg))
+            SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+            return
+
+    host_platform = env.get('HOST_ARCH')
+    if not host_platform:
+      #host_platform = get_default_host_platform()
+      host_platform = 'x86'
+    target_platform = env.get('TARGET_ARCH')
+    if not target_platform:
+      target_platform = host_platform
+
+    use_script = env.get('MSVC_USE_SCRIPT', True)
+    if SCons.Util.is_String(use_script):
+        debug('use_script 1 %s\n' % repr(use_script))
+        d = script_env(use_script)
+    elif use_script:
+        script = msvc.get_batch_file(target_platform, host_platform)
+        debug('use_script 2 %s target_platform:%s host_platform:%s\n' % (repr(script),target_platform,host_platform))
+        d = script_env(script)
+    else:
+        debug('msvc.get_default_env()\n')
+        d = msvc.get_default_env()
+
+    for k, v in d.items():
+        env.PrependENVPath(k, v, delete_existing=True)
+      
+def msvc_exists(version=None):
+    vcs = get_installed_vcs()
+    if version is None:
+        return len(vcs) > 0
+    return InstalledVCMap.has_key(version)
+    
+    
+def reset_installed_vcs():
+    global InstalledVCList
+    global InstalledVCMap
+    InstalledVCList = None
+    InstalledVCMap  = None
+    for vc in SupportedVCList:
+        vc.reset()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

src/engine/SCons/Tool/MSCommon/vs.py

 import SCons.Errors
 import SCons.Util
 
-from SCons.Tool.MSCommon.common import debug, \
-                                       read_reg, \
-                                       normalize_env, \
-                                       get_output, \
-                                       parse_output
+from common import debug, \
+                   get_output, \
+                   is_win64, \
+                   normalize_env, \
+                   parse_output, \
+                   read_reg
+
+import SCons.Tool.MSCommon.vc
 
 class VisualStudio:
     """
     """
     def __init__(self, version, **kw):
         self.version = version
+        kw['vc_version']  = kw.get('vc_version', version)
+        kw['sdk_version'] = kw.get('sdk_version', version)
         self.__dict__.update(kw)
         self._cache = {}
 
     #
 
     def find_batch_file(self):
-        """Try to find the Visual Studio or Visual C/C++ batch file.
-
-        Return None if failed or the batch file does not exist.
-        """
-        pdir = self.get_vc_product_dir()
-        if not pdir:
-            debug('find_batch_file():  no pdir')
+        vs_dir = self.get_vs_dir()
+        if not vs_dir:
+            debug('find_executable():  no vs_dir')
             return None
-        batch_file = os.path.normpath(os.path.join(pdir, self.batch_file))
+        batch_file = os.path.join(vs_dir, self.batch_file_path)
         batch_file = os.path.normpath(batch_file)
         if not os.path.isfile(batch_file):
             debug('find_batch_file():  %s not on file system' % batch_file)
             return None
         return batch_file
 
+    def find_vs_dir_by_vc(self):
+        SCons.Tool.MSCommon.vc.get_installed_vcs()
+        ivc = SCons.Tool.MSCommon.vc.InstalledVCMap.get(self.vc_version)
+        if not ivc:
+            debug('find_vs_dir():  no installed VC %s' % self.vc_version)
+            return None
+        return ivc.get_vc_dir()[:-len(ivc.vc_subdir)]
+        
+    def find_vs_dir_by_reg(self):
+        root = 'Software\\'
+
+        if is_win64():
+            root = root + 'Wow6432Node\\'
+        for key in self.hkeys:
+            if key=='use_dir':
+                return self.find_vs_dir_by_vc()
+            key = root + key
+            try:
+                comps = read_reg(key)
+            except WindowsError, e:
+                debug('find_vs_dir_by_reg(): no VS registry key %s' % repr(key))
+            else:
+                debug('find_vs_dir_by_reg(): found VS in registry: %s' % comps)
+                return comps
+        return None
+    
+    def find_vs_dir(self):
+        """ Can use registry or location of VC to find vs dir
+        First try to find by registry, and if that fails find via VC dir
+        """
+        
+        
+        if True:
+            vs_dir=self.find_vs_dir_by_reg()
+            return vs_dir
+        else:
+            return self.find_vs_dir_by_vc()
+
     def find_executable(self):
-        pdir = self.get_vc_product_dir()
-        if not pdir:
-            debug('find_executable():  no pdir')
+        vs_dir = self.get_vs_dir()
+        if not vs_dir:
+            debug('find_executable():  no vs_dir (%s)'%vs_dir)
             return None
-        executable = os.path.join(pdir, self.executable_path)
+        executable = os.path.join(vs_dir, self.executable_path)
         executable = os.path.normpath(executable)
         if not os.path.isfile(executable):
             debug('find_executable():  %s not on file system' % executable)
             return None
         return executable
-
-    def find_vc_product_dir(self):
-        if not SCons.Util.can_read_reg:
-            debug('find_vc_product_dir():  can not read registry')
-            return None
-        key = self.hkey_root + '\\' + self.vc_product_dir_key
-        try:
-            comps = read_reg(key)
-        except WindowsError, e:
-            debug('find_vc_product_dir():  no registry key %s' % key)
-        else:
-            if self.batch_file_dir_reg_relpath:
-                comps = os.path.join(comps, self.batch_file_dir_reg_relpath)
-                comps = os.path.normpath(comps)
-            if os.path.exists(comps):
-                return comps
-            else:
-                debug('find_vc_product_dir():  %s not on file system' % comps)
-
-        d = os.environ.get(self.common_tools_var)
-        if not d:
-            msg = 'find_vc_product_dir():  no %s variable'
-            debug(msg % self.common_tools_var)
-            return None
-        if not os.path.isdir(d):
-            debug('find_vc_product_dir():  %s not on file system' % d)
-            return None
-        if self.batch_file_dir_env_relpath:
-            d = os.path.join(d, self.batch_file_dir_env_relpath)
-            d = os.path.normpath(d)
-        return d
-
+    
     #
 
     def get_batch_file(self):
 
     def get_executable(self):
         try:
+            debug('get_executable using cache'%self._cache['executable'])
             return self._cache['executable']
         except KeyError:
             executable = self.find_executable()
             self._cache['executable'] = executable
+            debug('get_executable not in cache:%s'%executable)
             return executable
 
+    def get_vs_dir(self):
+        try:
+            return self._cache['vs_dir']
+        except KeyError:
+            vs_dir = self.find_vs_dir()
+            self._cache['vs_dir'] = vs_dir
+            return vs_dir
+
     def get_supported_arch(self):
         try:
             return self._cache['supported_arch']
             self._cache['supported_arch'] = self.supported_arch
             return self.supported_arch
 
-    def get_vc_product_dir(self):
-        try:
-            return self._cache['vc_product_dir']
-        except KeyError:
-            vc_product_dir = self.find_vc_product_dir()
-            self._cache['vc_product_dir'] = vc_product_dir
-            return vc_product_dir
-
     def reset(self):
         self._cache = {}
 
     #VisualStudio('TBD',
     #             hkey_root=r'TBD',
     #             common_tools_var='TBD',
-    #             batch_file='TBD',
-    #             vc_product_dir_key=r'TBD',
-    #             batch_file_dir_reg_relpath=None,
-    #             batch_file_dir_env_relpath=r'TBD',
     #             executable_path=r'TBD',
     #             default_dirname='TBD',
     #),
     # The batch file we look for is in the VC directory,
     # so the devenv.com executable is up in ..\..\Common7\IDE.
     VisualStudio('9.0',
-                 hkey_root=r'Software\Microsoft\VisualStudio\9.0',
+                 sdk_version='6.1',
+                 hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'],
                  common_tools_var='VS90COMNTOOLS',
-                 batch_file='vcvarsall.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=None,
-                 batch_file_dir_env_relpath=r'..\..\VC',
-                 executable_path=r'..\Common7\IDE\devenv.com',
+                 executable_path=r'Common7\IDE\devenv.com',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio 9',
                  supported_arch=['x86', 'amd64'],
     ),
     # The batch file we look for is in the VC directory,
     # so the VCExpress.exe executable is up in ..\..\Common7\IDE.
     VisualStudio('9.0Exp',
-                 hkey_root=r'Software\Microsoft\VisualStudio\9.0',
+                 vc_version='9.0',
+                 sdk_version='6.1',
+                 hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'],
                  common_tools_var='VS90COMNTOOLS',
-                 batch_file='vcvarsall.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=None,
-                 batch_file_dir_env_relpath=r'..\..\VC',
-                 executable_path=r'..\Common7\IDE\VCExpress.exe',
+                 executable_path=r'Common7\IDE\VCExpress.exe',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio 9',
                  supported_arch=['x86'],
     ),
     # The batch file we look for is in the VC directory,
     # so the devenv.com executable is up in ..\..\Common7\IDE.
     VisualStudio('8.0',
-                 hkey_root=r'Software\Microsoft\VisualStudio\8.0',
+                 sdk_version='6.0A',
+                 hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'],
                  common_tools_var='VS80COMNTOOLS',
-                 batch_file='vcvarsall.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=None,
-                 batch_file_dir_env_relpath=r'..\..\VC',
-                 executable_path=r'..\Common7\IDE\devenv.com',
+                 executable_path=r'Common7\IDE\devenv.com',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio 8',
                  supported_arch=['x86', 'amd64'],
     ),
     # The batch file we look for is in the VC directory,
     # so the VCExpress.exe executable is up in ..\..\Common7\IDE.
     VisualStudio('8.0Exp',
-                 hkey_root=r'Software\Microsoft\VCExpress\8.0',
+                 vc_version='8.0',
+                 sdk_version='6.0A',
+                 hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'],
                  common_tools_var='VS80COMNTOOLS',
-                 batch_file='vcvarsall.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=None,
-                 batch_file_dir_env_relpath=r'..\..\VC',
-                 # The batch file is in the VC directory, so
-                 # so the devenv.com executable is next door in ..\IDE.
-                 executable_path=r'..\Common7\IDE\VCExpress.exe',
+                 executable_path=r'Common7\IDE\VCExpress.exe',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio 8',
                  supported_arch=['x86'],
     ),
     # The batch file we look for is in the Common7\Tools directory,
     # so the devenv.com executable is next door in ..\IDE.
     VisualStudio('7.1',
-                 hkey_root=r'Software\Microsoft\VisualStudio\7.1',
+                 sdk_version='6.0',
+                 hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'],
                  common_tools_var='VS71COMNTOOLS',
-                 batch_file='vsvars32.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=r'..\Common7\Tools',
-                 batch_file_dir_env_relpath=None,
-                 executable_path=r'..\IDE\devenv.com',
+                 executable_path=r'IDE\devenv.com',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio .NET',
                  supported_arch=['x86'],
     ),
     # The batch file we look for is in the Common7\Tools directory,
     # so the devenv.com executable is next door in ..\IDE.
     VisualStudio('7.0',
-                 hkey_root=r'Software\Microsoft\VisualStudio\7.0',
+                 sdk_version='2003R2',
+                 hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
                  common_tools_var='VS70COMNTOOLS',
-                 batch_file='vsvars32.bat',
-                 vc_product_dir_key=r'Setup\VC\ProductDir',
-                 batch_file_dir_reg_relpath=r'..\Common7\Tools',
-                 batch_file_dir_env_relpath=None,
-                 executable_path=r'..\IDE\devenv.com',
+                 executable_path=r'IDE\devenv.com',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio .NET',
                  supported_arch=['x86'],
     ),
 
     # Visual Studio 6.0
     VisualStudio('6.0',
-                 hkey_root=r'Software\Microsoft\VisualStudio\6.0',
+                 sdk_version='2003R1',
+                 hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir',
+                        'use_dir'],
                  common_tools_var='VS60COMNTOOLS',
-                 batch_file='vcvars32.bat',
-                 vc_product_dir_key='Setup\Microsoft Visual C++\ProductDir',
-                 batch_file_dir_reg_relpath='Bin',
-                 batch_file_dir_env_relpath=None,
                  executable_path=r'Common\MSDev98\Bin\MSDEV.COM',
+                 batch_file_path=r'Common7\Tools\vsvars32.bat',
                  default_dirname='Microsoft Visual Studio',
                  supported_arch=['x86'],
     ),
 # requested, and cache it.
 
 InstalledVSList = None
-InstalledVSMap = None
+InstalledVSMap  = None
 
 def get_installed_visual_studios():
     global InstalledVSList
     global InstalledVSList
     global InstalledVSMap
     InstalledVSList = None
-    InstalledVSMap = None
+    InstalledVSMap  = None
     for vs in SupportedVSList:
         vs.reset()
-
+        
+    # Need to clear installed VC's as well as they are used in finding
+    # installed VS's
+    SCons.Tool.MSCommon.vc.reset_installed_vcs()
+        
 
 # We may be asked to update multiple construction environments with
 # SDK information.  When doing this, we check on-disk for whether
 #    for variable, directory in env_tuple_list:
 #        env.PrependENVPath(variable, directory)
 
-def detect_msvs():
+def msvs_exists():
     return (len(get_installed_visual_studios()) > 0)
 
 def get_vs_by_version(msvs):
+    global InstalledVSMap
+    global SupportedVSMap
+
     if not SupportedVSMap.has_key(msvs):
         msg = "Visual Studio version %s is not supported" % repr(msvs)
         raise SCons.Errors.UserError, msg
     get_installed_visual_studios()
     vs = InstalledVSMap.get(msvs)
+    debug('InstalledVSMap:%s'%InstalledVSMap)
     # Some check like this would let us provide a useful error message
     # if they try to set a Visual Studio version that's not installed.
     # However, we also want to be able to run tests (like the unit

src/engine/SCons/Tool/__init__.py

 
 def tool_list(platform, env):
 
+    other_plat_tools=[]
     # XXX this logic about what tool to prefer on which platform
     #     should be moved into either the platform files or
     #     the tool files themselves.
         assemblers = ['masm', 'nasm', 'gas', '386asm' ]
         fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran']
         ars = ['mslib', 'ar', 'tlib']
+        other_plat_tools=['msvs','midl']
     elif str(platform) == 'os2':
         "prefer IBM tools on OS/2"
-        linkers = ['ilink', 'gnulink', 'mslink']
-        c_compilers = ['icc', 'gcc', 'msvc', 'cc']
-        cxx_compilers = ['icc', 'g++', 'msvc', 'c++']
-        assemblers = ['nasm', 'masm', 'gas']
+        linkers = ['ilink', 'gnulink', ]#'mslink']
+        c_compilers = ['icc', 'gcc',]# 'msvc', 'cc']
+        cxx_compilers = ['icc', 'g++',]# 'msvc', 'c++']
+        assemblers = ['nasm',]# 'masm', 'gas']
         fortran_compilers = ['ifl', 'g77']
-        ars = ['ar', 'mslib']
+        ars = ['ar',]# 'mslib']
     elif str(platform) == 'irix':
         "prefer MIPSPro on IRIX"
         linkers = ['sgilink', 'gnulink']
                                 'dvipdf', 'dvips', 'gs',
                                 'jar', 'javac', 'javah',
                                 'latex', 'lex',
-                                'm4', 'midl', 'msvs',
+                                'm4', #'midl', 'msvs',
                                 'pdflatex', 'pdftex', 'Perforce',
                                 'RCS', 'rmic', 'rpcgen',
                                 'SCCS',
                                 # 'Subversion',
                                 'swig',
                                 'tar', 'tex',
-                                'yacc', 'zip', 'rpm', 'wix'],
+                                'yacc', 'zip', 'rpm', 'wix']+other_plat_tools,
                                env)
 
     tools = ([linker, c_compiler, cxx_compiler,

src/engine/SCons/Tool/linkloc.py

 import SCons.Tool
 import SCons.Util
 
-from SCons.Tool.MSCommon import detect_msvs, merge_default_version
+from SCons.Tool.MSCommon import msvs_exists, merge_default_version
 from SCons.Tool.PharLapCommon import addPharLapPaths
 
 _re_linker_command = re.compile(r'(\s)@\s*([^\s]+)')
     addPharLapPaths(env)
 
 def exists(env):
-    if detect_msvs():
+    if msvs_exists():
         return env.Detect('linkloc')
     else:
         return 0

src/engine/SCons/Tool/midl.py

 import SCons.Scanner.IDL
 import SCons.Util
 
-from MSCommon import detect_msvs
+from MSCommon import msvs_exists
 
 def midl_emitter(target, source, env):
     """Produces a list of outputs from the MIDL compiler"""
     env['BUILDERS']['TypeLibrary'] = midl_builder
 
 def exists(env):
-    return detect_msvs()
+    return msvs_exists()
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/mslib.py

 import SCons.Tool.msvc
 import SCons.Util
 
-from MSCommon import detect_msvs, merge_default_version
+from MSCommon import msvs_exists, merge_default_version
 
 def generate(env):
     """Add Builders and construction variables for lib to an Environment."""
     env['LIBSUFFIX']   = '.lib'
 
 def exists(env):
-    return detect_msvs()
+    return msvs_exists()
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/mslink.py

 import SCons.Tool.msvs
 import SCons.Util
 
-from MSCommon import merge_default_version, detect_msvs
+from MSCommon import merge_default_version, msvs_exists
 
 def pdbGenerator(env, target, source, for_signature):
     try:
     env['LDMODULECOM'] = compositeLdmodAction
 
 def exists(env):
-    return detect_msvs()
+    return msvs_exists()
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/mssdk.py

 selection method.
 """
 
-from SCons.Tool.MSCommon.sdk import detect_sdk, \
-                                    set_default_sdk, \
-                                    set_sdk_by_directory, \
-                                    set_sdk_by_version
+from MSCommon import mssdk_exists, \
+                     mssdk_setup_env
 
 def generate(env):
     """Add construction variables for an MS SDK to an Environment."""
-    if env.has_key('MSSDK_DIR'):
-        set_sdk_by_directory(env, env.subst('$MSSDK_DIR'))
-        return
-
-    if env.has_key('MSSDK_VERSION'):
-        set_sdk_by_version(env, env.subst('$MSSDK_VERSION'))
-        return
-
-    if env.has_key('MSVS_VERSION'):
-        set_default_sdk(env, env['MSVS_VERSION'])
-
-    #print "No MSVS_VERSION: this is likely to be a bug"
-    return
+    mssdk_setup_env(env)
 
 def exists(env):
-    return detect_sdk()
+    return mssdk_exists()
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/msvc.py

 import SCons.Warnings
 import SCons.Scanner.RC
 
-from MSCommon import merge_default_version, detect_msvs
+from MSCommon import msvc_exists, msvc_setup_env
 
 CSuffixes = ['.c', '.C']
 CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
     env['SHOBJSUFFIX']    = '$OBJSUFFIX'
 
     # Set-up ms tools paths for default version
-    merge_default_version(env)
+    msvc_setup_env(env)
 
     import mssdk
     mssdk.generate(env)
         env['ENV']['SystemRoot'] = SCons.Platform.win32.get_system_root()
 
 def exists(env):
-    return detect_msvs()
+    return msvc_exists('cl')
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/msvc.xml

 when the &cv-RCINCFLAGS; variable is expanded.
 </summary>
 </cvar>
+
+<cvar name="MSVC_VERSION">
+<summary>
+Sets the preferred  version of Microsoft Visual C/C++ to use.
+
+If &v-MSVC_VERSION; is not set,
+&SCons; will (by default) select the latest version
+of Visual C/C++ installed on your system.
+If the specified version isn't installed,
+tool initialization will fail.
+</summary>
+</cvar>

src/engine/SCons/Tool/msvs.py

 import SCons.Util
 import SCons.Warnings
 
-from MSCommon import detect_msvs, merge_default_version
+from MSCommon import msvs_exists, merge_default_version
+from SCons.Defaults import processDefines
 
 ##############################################################################
 # Below here are the classes and functions for generation of
             # TODO(1.5)
             #preprocdefs = xmlify(';'.join(self.env.get('CPPDEFINES', [])))
             #includepath = xmlify(';'.join(self.env.get('CPPPATH', [])))
-            preprocdefs = xmlify(string.join(self.env.get('CPPDEFINES', []), ';'))
+            preprocdefs = xmlify(string.join(processDefines(self.env.get('CPPDEFINES', [])), ';'))
             includepath = xmlify(string.join(self.env.get('CPPPATH', []), ';'))
 
             if not env_has_buildtarget:
     env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
 
 def exists(env):
-    return detect_msvs()
+    return msvs_exists()
 
 # Local Variables:
 # tab-width:4

src/engine/SCons/Tool/msvs.xml

 
 <cvar name="MSVS_VERSION">
 <summary>
-Sets the preferred version of MSVS to use.
+Sets the preferred version of Microsoft Visual Studio to use.
 
-SCons will (by default) select the latest version of MSVS
-installed on your machine.
+If &v-MSVS_VERSION; is not set,
+&SCons; will (by default) select the latest version
+of Visual Studio installed on your system.
 So, if you have version 6 and version 7 (MSVS .NET) installed,
 it will prefer version 7.
 You can override this by
 <envar>MSVS_VERSION</envar>
 variable in the Environment initialization, setting it to the
 appropriate version ('6.0' or '7.0', for example).
-If the given version isn't installed, tool initialization will fail.
+If the specified version isn't installed,
+tool initialization will fail.
 </summary>
 </cvar>
 

src/engine/SCons/Tool/msvsTests.py

             mykey = 'HKEY_CURRENT_USER\\' + key
         if root == SCons.Util.HKEY_LOCAL_MACHINE:
             mykey = 'HKEY_LOCAL_MACHINE\\' + key
-        #print "Open Key",mykey
+        debug("Open Key:%s"%mykey)
         return self.root.key(mykey)
 
 def DummyOpenKeyEx(root, key):
     """This test case is run several times with different defaults.
     See its subclasses below."""
     def setUp(self):
+        debug("THIS TYPE :%s"%self)
         global registry
         registry = self.registry
         from SCons.Tool.MSCommon.vs import reset_installed_visual_studios
         reset_installed_visual_studios()
 
-    def test_detect_msvs(self):
-        """Test the detect_msvs() function"""
-        r = detect_msvs()
+    def test_msvs_exists(self):
+        """Test the msvs_exists() function"""
+        r = msvs_exists()
         assert r == (self.number_of_versions > 0), r
 
     def test_get_default_version(self):
         env = DummyEnv()
         v1 = get_default_version(env)
         assert env['MSVS_VERSION'] == self.default_version, \
-               (self.default_version, env['MSVS_VERSION'])
+               ("env['MSVS_VERSION'] != self.default_version",self.default_version, env['MSVS_VERSION'])
         assert env['MSVS']['VERSION'] == self.default_version, \
-               (self.default_version, env['MSVS']['VERSION'])
+               ("env['MSVS']['VERSION'] != self.default_version",self.default_version, env['MSVS']['VERSION'])
         assert v1 == self.default_version, (self.default_version, v1)
 
         env = DummyEnv({'MSVS_VERSION':'7.0'})
     highest_version = '7.0'
     number_of_versions = 2
     install_locs = {
-        '6.0' : {'VSINSTALLDIR': 'C:\\VS6\\VC98', 'VCINSTALLDIR': 'C:\\VS6\\VC98\\Bin'},
-        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7\\Tools'},
+        '6.0' : {'VSINSTALLDIR': 'C:\\VS6\\VC98',
+                 'VCINSTALLDIR': 'C:\\VS6\\VC98\\Bin'},
+        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7',
+                 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7\\Tools'},
         '7.1' : {},
         '8.0' : {},
         '8.0Exp' : {},
     number_of_versions = 1
     install_locs = {
         '6.0' : {},
-        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7\\Tools'},
+        '7.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7',
+                 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Common7\\Tools'},
         '7.1' : {},
         '8.0' : {},
         '8.0Exp' : {},
     install_locs = {
         '6.0' : {},
         '7.0' : {},
-        '7.1' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\Common7', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\Common7\\Tools'},
+        '7.1' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\Common7',
+                 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET 2003\\Common7\\Tools'},
         '8.0' : {},
         '8.0Exp' : {},
     }
         '7.0' : {},
         '7.1' : {},
         '8.0' : {},
-        '8.0Exp' : {'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']
 
         '6.0' : {},
         '7.0' : {},
         '7.1' : {},
-        '8.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\VC'},
+        '8.0' : {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8',
+                 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio 8\\VC'},
         '8.0Exp' : {},
     }
     default_install_loc = install_locs['8.0']
         sys.stdout.write("NO RESULT for msvsTests.py:  '%s' is not win32\n" % sys.platform)
         sys.exit(0)
 
-    SCons.Util.RegOpenKeyEx = DummyOpenKeyEx
-    SCons.Util.RegEnumKey = DummyEnumKey
-    SCons.Util.RegEnumValue = DummyEnumValue
+    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 :-)
     os.path.isfile = DummyExists # make sure all files are files :-)
     os.path.isdir  = DummyExists # make sure all dirs are dirs :-)

src/engine/SCons/Util.py

     can_read_reg = 1
     hkey_mod = _winreg
 
-    RegOpenKeyEx = _winreg.OpenKeyEx
-    RegEnumKey = _winreg.EnumKey
-    RegEnumValue = _winreg.EnumValue
+    RegOpenKeyEx    = _winreg.OpenKeyEx
+    RegEnumKey      = _winreg.EnumKey
+    RegEnumValue    = _winreg.EnumValue
     RegQueryValueEx = _winreg.QueryValueEx
-    RegError = _winreg.error
+    RegError        = _winreg.error
 
 except ImportError:
     try:
         can_read_reg = 1
         hkey_mod = win32con
 
-        RegOpenKeyEx = win32api.RegOpenKeyEx
-        RegEnumKey = win32api.RegEnumKey
-        RegEnumValue = win32api.RegEnumValue
+        RegOpenKeyEx    = win32api.RegOpenKeyEx
+        RegEnumKey      = win32api.RegEnumKey
+        RegEnumValue    = win32api.RegEnumValue
         RegQueryValueEx = win32api.RegQueryValueEx
-        RegError = win32api.error
+        RegError        = win32api.error
 
     except ImportError:
         class _NoError(Exception):
         RegError = _NoError
 
 if can_read_reg:
-    HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
+    HKEY_CLASSES_ROOT  = hkey_mod.HKEY_CLASSES_ROOT
     HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
-    HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
-    HKEY_USERS = hkey_mod.HKEY_USERS
+    HKEY_CURRENT_USER  = hkey_mod.HKEY_CURRENT_USER
+    HKEY_USERS         = hkey_mod.HKEY_USERS
 
     def RegGetValue(root, key):
         """This utility function returns a value in the registry

src/engine/SCons/Warnings.py

 class TaskmasterNeedsExecuteWarning(FutureDeprecatedWarning):
     pass
 
+class VisualCMissingWarning(Warning):
+    pass
+
+class VisualStudioMissingWarning(Warning):
+    pass
+
 class FortranCxxMixWarning(LinkWarning):
     pass
 

test/MSVS/vs-8.0-clean.py

 
 test.write('SConstruct', """\
 env=Environment(platform='win32', tools=['msvs'], MSVS_VERSION='8.0',
-                CPPDEFINES=['DEF1', 'DEF2'],
+                CPPDEFINES=['DEF1', 'DEF2',('DEF3','1234')],
                 CPPPATH=['inc1', 'inc2'])
 
 testsrc = ['test1.cpp', 'test2.cpp']