Commits

Anonymous committed a4996d3

Rename MSVCCommon to MSCommon so it's not tied too tightly to Visual C/C++
(leaving the door a little more open for other Visual products).

  • Participants
  • Parent commits 5d7d37c
  • Branches vs_revamp

Comments (0)

Files changed (23)

File src/engine/MANIFEST.in

 SCons/Tool/lex.py
 SCons/Tool/link.py
 SCons/Tool/linkloc.py
-SCons/Tool/MSVCCommon/__init__.py
-SCons/Tool/MSVCCommon/common.py
-SCons/Tool/MSVCCommon/netframework.py
-SCons/Tool/MSVCCommon/sdk.py
-SCons/Tool/MSVCCommon/vs.py
+SCons/Tool/MSCommon/__init__.py
+SCons/Tool/MSCommon/common.py
+SCons/Tool/MSCommon/netframework.py
+SCons/Tool/MSCommon/sdk.py
+SCons/Tool/MSCommon/vs.py
 SCons/Tool/m4.py
 SCons/Tool/masm.py
 SCons/Tool/midl.py

File src/engine/SCons/Tool/MSCommon/TODO

+Last Change: Fri Oct 17 04:00 PM 2008 J
+
+- Make sure VS 6 and VS 2003 .Net work (with their own SDK)
+- See whether current unit tests can be updated and need to be rewritten from
+  scratch

File src/engine/SCons/Tool/MSCommon/__init__.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__ = """
+Common functions for Microsoft Visual Studio and Visual C/C++.
+"""
+
+import copy
+import os
+import re
+import subprocess
+
+import SCons.Errors
+import SCons.Platform.win32
+import SCons.Util
+
+from SCons.Tool.MSCommon.vs import detect_msvs, \
+                                   get_default_version, \
+                                   get_vs_by_version, \
+                                   merge_default_version, \
+                                   query_versions
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSCommon/common.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__ = """
+Common helper functions for working with
+"""
+
+import copy
+import os
+import subprocess
+import re
+
+import SCons.Util
+
+# Uncomment to enable debug logging to your choice of file
+#import logging,os
+#os.unlink('c:/tmp/debug.log')
+#logging.basicConfig(filename='c:/tmp/debug.log', level=logging.DEBUG,)
+
+try:
+    from logging import debug
+except ImportError:
+    debug = lambda x : None
+
+#debug = lambda x : open('con', 'w').write(x + '\n')
+
+# TODO(sgk): unused
+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
+
+def read_reg(value):
+    return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0]
+
+
+# Functions for fetching environment variable settings from batch files.
+
+def normalize_env(env, keys):
+    """Given a dictionary representing a shell environment, add the variables
+    from os.environ needed for the processing of .bat files; the keys are
+    controlled by the keys argument.
+
+    It also makes sure the environment values are correctly encoded.
+
+    Note: the environment is copied"""
+    normenv = {}
+    if env:
+        for k in env.keys():
+            normenv[k] = copy.deepcopy(env[k]).encode('mbcs')
+
+        for k in keys:
+            if os.environ.has_key(k):
+                normenv[k] = os.environ[k].encode('mbcs')
+
+    return normenv
+
+def get_output(vcbat, args = None, env = None):
+    """Parse the output of given bat file, with given args."""
+    if args:
+        debug("Calling '%s %s'" % (vcbat, args))
+        popen = subprocess.Popen('"%s" %s & set' % (vcbat, args),
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE,
+                                 env=env)
+    else:
+        debug("Calling '%s'" % vcbat)
+        popen = subprocess.Popen('"%s" & set' % vcbat,
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE,
+                                 env=env)
+
+    # Use the .stdout and .stderr attributes directly because the
+    # .communicate() method uses the threading module on Windows
+    # and won't work under Pythons not built with threading.
+    stdout = popen.stdout.read()
+    if popen.wait() != 0:
+        raise IOError(popen.stderr.read().decode("mbcs"))
+
+    output = stdout.decode("mbcs")
+    return output
+
+def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")):
+    # dkeep is a dict associating key: path_list, where key is one item from
+    # keep, and pat_list the associated list of paths
+
+    # TODO(1.5):  replace with the following list comprehension:
+    #dkeep = dict([(i, []) for i in keep])
+    dkeep = dict(map(lambda i: (i, []), keep))
+
+    # rdk will  keep the regex to match the .bat file output line starts
+    rdk = {}
+    for i in keep:
+        rdk[i] = re.compile('%s=(.*)' % i, re.I)
+
+    def add_env(rmatch, key):
+        plist = rmatch.group(1).split(os.pathsep)
+        for p in plist:
+            # Do not add empty paths (when a var ends with ;)
+            if p:
+                p = p.encode('mbcs')
+                # XXX: For some reason, VC98 .bat file adds "" around the PATH
+                # values, and it screws up the environment later, so we strip
+                # it. 
+                p = p.strip('"')
+                dkeep[key].append(p)
+
+    for line in output.splitlines():
+        for k,v in rdk.items():
+            m = v.match(line)
+            if m:
+                add_env(m, k)
+
+    return dkeep
+
+# TODO(sgk): unused
+def output_to_dict(output):
+    """Given an output string, parse it to find env variables.
+
+    Return a dict where keys are variables names, and values their content"""
+    envlinem = re.compile(r'^([a-zA-z0-9]+)=([\S\s]*)$')
+    parsedenv = {}
+    for line in output.splitlines():
+        m = envlinem.match(line)
+        if m:
+            parsedenv[m.group(1)] = m.group(2)
+    return parsedenv
+
+# TODO(sgk): unused
+def get_new(l1, l2):
+    """Given two list l1 and l2, return the items in l2 which are not in l1.
+    Order is maintained."""
+
+    # We don't try to be smart: lists are small, and this is not the bottleneck
+    # is any case
+    new = []
+    for i in l2:
+        if i not in l1:
+            new.append(i)
+
+    return new
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSCommon/msvc_changes.txt

+The Visual Studio support has been totally revamped. Instead of using registry
+magic, we use the .bat files available for each version of visual studio. This
+is simpler (does not depend on the version of the compiler), more reliable, and
+just plain better.
+
+Specification
+=============
+
+Tested versions
+---------------
+
+The following versions have been succesfully tested:
+  - VS 2008 (express), 32 bits
+  - VS 2005 (express), 32 bits
+  - VS 2003 (.Net, pro), 32 bits
+
+Detection
+---------
+
+All tools related to the ms toolchain are detected through the same method:
+  - detect the .bat configuration file (vsvarsall.bat/vsvars32.bat
+    depending on the version) from the registry
+  - if registry does not return anything useful, use the VS*COMNTOOLS env
+    variable.
+
+A version is detected only when the .bat file actually exists on the
+filesystem.  Once the .bat file is found, it is executed through a clean
+environment, and its output is parsed to get the variables
+PATH/LIB/LIBPATH/INCLUDE. Those variables are then added to env['ENV']
+
+By default, the most recent detected version is set, and can be queried in
+env['MSVS_VERSION'] *after* the tool initialization. The version can be forced
+by setting the MSVS_VERSION variable *before* initializing the tool.
+
+SDK
+---
+
+Separate SDKs are only supported for the following versions:
+        - Platform SDK 2003 R1 and R2
+        - Windows SDK. I tried the following versions: 6.0, 6.0A (SDK delivered
+          with VS 2008 express) and 6.1 (Windows SDK 2008).
+
+Previous SDKs are not available anymore on MS website, so I could not test
+them. I believe VS 6 has its own SDK included, as well as VS 2003 .Net. The SDK
+is set *after* the msvs tool.
+
+The version of the SDK can be controlled by the scons variable:
+
+    MSSDK_DIR:      If set, specifies the directory location of the
+                    SDK to be used.
+
+    MSSDK_VERSION:  If set, specifies the version of the SDK to be used.
+
+If neither of these is set, MSVS_VERSION is used to pick an appropriate
+default.
+
+Architecture
+------------
+
+env['MSVS_ARCH'] = 'x86'
+                   'amd64'
+
+If not set, the selection logic defaults to x86. Cross compiling has been
+disabled, filtering out values not included in version.SUPPORTED_ARCH.
+(No tests made with cross compiling.)
+
+Fundamental changes
+===================
+
+env["ENV"] has been expanded a bit on windows:
+  - add %SystemRoot%\system32 in the path for windows
+  - add COMSPEC (needed by the .bat file execution)
+
+Internals
+=========
+
+The code can be found in the MSVCCommon submodule:
+  - findloc: find the product dir from the registry or the shell environment
+        - versions: query the system for available versions of the VS suite on
+          the system
+        - misc: high level functions, *candidates* for the public API.
+        - sdk: specifics to the SDK detection.
+        - defaults: default values to use for the paths, to use instead of the
+          whole env parsing which can be quite slow, but less reliable. Still
+          experimental, may be removed
+  - envhelpers: functions to execute a VS .bat file, parse its output,
+    and get the variables with modified values.
+
+At this point, no function should be considered public, the exact API is not
+good yet.

File src/engine/SCons/Tool/MSCommon/netframework.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__ = """
+"""
+
+import os
+import re
+import string
+
+from common import read_reg, debug
+
+# Original value recorded by dcournapeau
+_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot'
+# On SGK's system
+_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder'
+
+def find_framework_root():
+    # XXX: find it from environment (FrameworkDir)
+    try:
+        froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT)
+        debug("Found framework install root in registry: %s" % froot)
+    except WindowsError, e:
+        debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT)
+        return None
+
+    if not os.path.exists(froot):
+        debug("%s not found on fs" % froot)
+        return None
+
+    return froot
+
+def query_versions():
+    froot = find_framework_root()
+    if froot:
+        contents = os.listdir(froot)
+
+        l = re.compile('v[0-9]+.*')
+        versions = filter(lambda e, l=l: l.match(e), contents)
+
+        def versrt(a,b):
+            # since version numbers aren't really floats...
+            aa = a[1:]
+            bb = b[1:]
+            aal = string.split(aa, '.')
+            bbl = string.split(bb, '.')
+            # sequence comparison in python is lexicographical
+            # which is exactly what we want.
+            # Note we sort backwards so the highest version is first.
+            return cmp(bbl,aal)
+
+        versions.sort(versrt)
+    else:
+        versions = []
+
+    return versions
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSCommon/sdk.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 detect the Platform/Windows SDK
+
+PSDK 2003 R1 is the earliest version detected.
+"""
+
+import os
+
+import SCons.Errors
+from SCons.Tool.MSCommon.common import debug, read_reg
+import SCons.Util
+
+# SDK Checks. This is of course a mess as everything else on MS platforms. Here
+# is what we do to detect the SDK:
+#
+# For Windows SDK >= 6.0: just look into the registry entries:
+#   HKLM\Software\Microsoft\Microsoft SDKs\Windows
+# All the keys in there are the available versions.
+#
+# For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not
+# seem to be any sane registry key, so the precise location is hardcoded.
+#
+# For versions below 2003R1, it seems the PSDK is included with Visual Studio?
+#
+# Also, per the following:
+#     http://benjamin.smedbergs.us/blog/tag/atl/
+# VC++ Professional comes with the SDK, VC++ Express does not.
+
+# Location of the SDK (checked for 6.1 only)
+_CURINSTALLED_SDK_HKEY_ROOT = \
+        r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
+
+
+class SDKDefinition:
+    """
+    An abstract base class for trying to find installed SDK directories.
+    """
+    def __init__(self, version, **kw):
+        self.version = version
+        self.__dict__.update(kw)
+
+    def find_install_dir(self):
+        """Try to find the MS SDK from the registry.
+
+        Return None if failed or the directory does not exist.
+        """
+        if not SCons.Util.can_read_reg:
+            debug('SCons cannot read registry')
+            return None
+
+        hkey = self.HKEY_FMT % self.hkey_data
+
+        try:
+            install_dir = read_reg(hkey)
+            debug('Found sdk dir in registry: %s' % install_dir)
+        except WindowsError, e:
+            debug('Did not find sdk dir key %s in registry' % hkey)
+            return None
+
+        if not os.path.exists(install_dir):
+            debug('%s is not found on the filesystem' % install_dir)
+            return None
+
+        ftc = os.path.join(install_dir, self.sanity_check_file)
+        if not os.path.exists(ftc):
+            debug("File %s used for sanity check not found" % ftc)
+            return None
+
+        return install_dir
+
+    def get_install_dir(self):
+        """Return the MSSSDK given the version string."""
+        try:
+            return self._install_dir
+        except AttributeError:
+            install_dir = self.find_install_dir()
+            self._install_dir = install_dir
+            return install_dir
+
+class WindowsSDK(SDKDefinition):
+    """
+    A subclass for trying to find installed Windows SDK directories.
+    """
+    HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder'
+    def __init__(self, *args, **kw):
+        apply(SDKDefinition.__init__, (self,)+args, kw)
+        self.hkey_data = self.version
+
+class PlatformSDK(SDKDefinition):
+    """
+    A subclass for trying to find installed Platform SDK directories.
+    """
+    HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir'
+    def __init__(self, *args, **kw):
+        apply(SDKDefinition.__init__, (self,)+args, kw)
+        self.hkey_data = self.uuid
+
+# The list of support SDKs which we know how to detect.
+#
+# The first SDK found in the list is the one used by default if there
+# are multiple SDKs installed.  Barring good reasons to the contrary,
+# this means we should list SDKs with from most recent to oldest.
+#
+# If you update this list, update the documentation in Tool/mssdk.xml.
+SupportedSDKList = [
+    WindowsSDK('6.1',
+                sanity_check_file=r'include\windows.h'),
+
+    WindowsSDK('6.0A',
+               sanity_check_file=r'include\windows.h'),
+
+    WindowsSDK('6.0',
+               sanity_check_file=r'bin\gacutil.exe'),
+
+    PlatformSDK('2003R2',
+                sanity_check_file=r'SetEnv.Cmd',
+                uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"),
+
+    PlatformSDK('2003R1',
+                sanity_check_file=r'SetEnv.Cmd',
+                uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3"),
+]
+
+SupportedSDKMap = {}
+for sdk in SupportedSDKList:
+    SupportedSDKMap[sdk.version] = sdk
+
+
+# Finding installed SDKs isn't cheap, because it goes not only to the
+# registry but also to the disk to sanity-check that there is, in fact,
+# an SDK installed there and that the registry entry isn't just stale.
+# Find this information once, when requested, and cache it.
+
+InstalledSDKList = None
+InstalledSDKMap = None
+
+def get_installed_sdks():
+    global InstalledSDKList
+    global InstalledSDKMap
+    if InstalledSDKList is None:
+        InstalledSDKList = []
+        InstalledSDKMap = {}
+        for sdk in SupportedSDKList:
+            if sdk.get_install_dir():
+                InstalledSDKList.append(sdk)
+                InstalledSDKMap[sdk.version] = sdk
+    return InstalledSDKList
+
+
+# We may be asked to update multiple construction environments with
+# SDK information.  When doing this, we check on-disk for whether
+# the SDK has 'mfc' and 'atl' subdirectories.  Since going to disk
+# is expensive, cache results by directory.
+
+SDKEnvironmentUpdates = {}
+
+def set_sdk_by_directory(env, sdk_dir):
+    global SDKEnvironmentUpdates
+    try:
+        env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
+    except KeyError:
+        env_tuple_list = []
+        SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
+
+        include_path = os.path.join(sdk_dir, 'include')
+        mfc_path = os.path.join(include_path, 'mfc')
+        atl_path = os.path.join(include_path, 'atl')
+
+        if os.path.exists(mfc_path):
+            env_tuple_list.append(('INCLUDE', mfc_path))
+        if os.path.exists(atl_path):
+            env_tuple_list.append(('INCLUDE', atl_path))
+        env_tuple_list.append(('INCLUDE', include_path))
+
+        env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
+        env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
+        env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
+
+    for variable, directory in env_tuple_list:
+        env.PrependENVPath(variable, directory)
+
+
+# TODO(sgk):  currently unused; remove?
+def get_cur_sdk_dir_from_reg():
+    """Try to find the platform sdk directory from the registry.
+
+    Return None if failed or the directory does not exist"""
+    if not SCons.Util.can_read_reg:
+        debug('SCons cannot read registry')
+        return None
+
+    try:
+        val = 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 None
+
+    if not os.path.exists(val):
+        debug("Current sdk dir %s not on fs" % val)
+        return None
+
+    return val
+
+
+def detect_sdk():
+    return (len(get_installed_sdks()) > 0)
+
+def set_sdk_by_version(env, 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_install_dir())
+
+def set_default_sdk(env, msver):
+    """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_install_dir())
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSCommon/vs.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 detect Visual Studio and/or Visual C/C++
+"""
+
+import os
+
+import SCons.Errors
+import SCons.Util
+
+from SCons.Tool.MSCommon.common import debug, \
+                                       read_reg, \
+                                       normalize_env, \
+                                       get_output, \
+                                       parse_output
+
+class VisualStudio:
+    """
+    An abstract base class for trying to find installed versions of
+    Visual Studio.
+    """
+    def __init__(self, version, **kw):
+        self.version = version
+        self.__dict__.update(kw)
+        self._cache = {}
+
+    def batch_file_path(self):
+        pdir = self.get_vc_product_dir()
+        if not pdir:
+            return None
+        return os.path.join(pdir, self.batch_file)
+
+    def common_tools_path(self):
+        return os.environ.get(self.common_tools_var)
+
+    def vc_product_dir_path(self):
+        if not SCons.Util.can_read_reg:
+            debug('SCons can not read registry')
+            return None
+        key = self.hkey_root + '\\' + self.vc_product_dir_key
+        try:
+            comps = read_reg(key)
+        except WindowsError, e:
+            debug('Did not find product dir key %s in registry' % key)
+        else:
+            if self.batch_file_dir_reg_relpath:
+                comps = os.path.join(comps, self.batch_file_dir_reg_relpath)
+            if os.path.exists(comps):
+                return comps
+            debug('%s is not found on the file system' % comps)
+
+    #
+
+    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')
+            return None
+        batch_file = os.path.join(pdir, self.batch_file)
+        if not os.path.isfile(batch_file):
+            debug('%s file not on file system' % batch_file)
+            return None
+        return batch_file
+
+    def find_executable(self):
+        pdir = self.get_vc_product_dir()
+        if not pdir:
+            return None
+        executable = os.path.join(pdir, self.executable_path)
+        if not os.path.isfile(executable):
+            debug('%s file not on file system' % executable)
+            return None
+        return executable
+
+    def find_vc_product_dir(self):
+        if SCons.Util.can_read_reg:
+            key = self.hkey_root + '\\' + self.vc_product_dir_key
+            try:
+                comps = read_reg(key)
+            except WindowsError, e:
+                debug('Did not find product dir key %s in registry' % key)
+            else:
+                if self.batch_file_dir_reg_relpath:
+                    comps = os.path.join(comps, self.batch_file_dir_reg_relpath)
+                if os.path.exists(comps):
+                    return comps
+                debug('%s is not found on the file system' % comps)
+        else:
+            debug('SCons can not read registry')
+
+        d = os.environ.get(self.common_tools_var)
+        if d and os.path.isdir(d):
+            debug('%s found from %s' % (d, self.common_tools_var))
+            if self.batch_file_dir_env_relpath:
+                d = os.path.join(d, self.batch_file_dir_env_relpath)
+            return d
+        return None
+
+    #
+
+    def get_batch_file(self):
+        try:
+            return self._cache['batch_file']
+        except KeyError:
+            batch_file = self.find_batch_file()
+            self._cache['batch_file'] = batch_file
+            return batch_file
+
+    def get_executable(self):
+        try:
+            return self._cache['executable']
+        except KeyError:
+            executable = self.find_executable()
+            self._cache['executable'] = executable
+            return executable
+
+    def get_supported_arch(self):
+        try:
+            return self._cache['supported_arch']
+        except KeyError:
+            # RDEVE: for the time being use hardcoded lists
+            # supported_arch = self.find_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 = {}
+
+# The list of supported Visual Studio versions we know how to detect.
+#
+# How to look for .bat file ?
+#  - VS 2008 Express (x86):
+#     * from registry key productdir, gives the full path to vsvarsall.bat. In
+#     HKEY_LOCAL_MACHINE):
+#         Software\Microsoft\VCEpress\9.0\Setup\VC\productdir
+#     * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC
+#     relatively to the path given by the variable.
+#
+#  - VS 2008 Express (WoW6432: 32 bits on windows x64):
+#         Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir
+#
+#  - VS 2005 Express (x86):
+#     * from registry key productdir, gives the full path to vsvarsall.bat. In
+#     HKEY_LOCAL_MACHINE):
+#         Software\Microsoft\VCEpress\8.0\Setup\VC\productdir
+#     * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC
+#     relatively to the path given by the variable.
+#
+#  - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a
+#  productdir ?
+#
+#  - VS 2003 .Net (pro edition ? x86):
+#     * from registry key productdir. The path is then ..\Common7\Tools\
+#     relatively to the key. The key is in HKEY_LOCAL_MACHINE):
+#         Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir
+#     * from environmnent variable VS71COMNTOOLS: the path is the full path to
+#     vsvars32.bat
+#
+#  - VS 98 (VS 6):
+#     * from registry key productdir. The path is then Bin
+#     relatively to the key. The key is in HKEY_LOCAL_MACHINE):
+#         Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir
+#
+# The first version found in the list is the one used by default if
+# there are multiple versions installed.  Barring good reasons to
+# the contrary, this means we should list versions from most recent
+# to oldest.  Pro versions get listed before Express versions on the
+# assumption that, by default, you'd rather use the version you paid
+# good money for in preference to whatever Microsoft makes available
+# for free.
+#
+# If you update this list, update the documentation in Tool/msvs.xml.
+
+SupportedVSList = [
+    # Visual Studio 2010
+    # TODO: find the settings, perhaps from someone with a CTP copy?
+    #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',
+    #),
+
+    # Visual Studio 2008
+    VisualStudio('9.0',
+                 hkey_root=r'Software\Microsoft\VisualStudio\9.0',
+                 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',
+                 default_dirname='Microsoft Visual Studio 9',
+                 supported_arch=['x86', 'amd64'],
+    ),
+
+    # Visual C++ 2008 Express Edition
+    VisualStudio('9.0Exp',
+                 hkey_root=r'Software\Microsoft\VisualStudio\9.0',
+                 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',
+                 default_dirname='Microsoft Visual Studio 9',
+                 supported_arch=['x86'],
+    ),
+
+    # Visual Studio 2005
+    VisualStudio('8.0',
+                 hkey_root=r'Software\Microsoft\VisualStudio\8.0',
+                 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',
+                 default_dirname='Microsoft Visual Studio 8',
+                 supported_arch=['x86', 'amd64'],
+    ),
+
+    # Visual C++ 2005 Express Edition
+    VisualStudio('8.0Exp',
+                 hkey_root=r'Software\Microsoft\VCExpress\8.0',
+                 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\VCExpress.exe',
+                 default_dirname='Microsoft Visual Studio 8',
+                 supported_arch=['x86'],
+    ),
+
+    # Visual Studio .NET 2003
+    VisualStudio('7.1',
+                 hkey_root=r'Software\Microsoft\VisualStudio\7.1',
+                 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'..\Common7\IDE\devenv.com',
+                 default_dirname='Microsoft Visual Studio .NET',
+                 supported_arch=['x86'],
+    ),
+
+    # Visual Studio .NET
+    VisualStudio('7.0',
+                 hkey_root=r'Software\Microsoft\VisualStudio\7.0',
+                 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'..\Common7\IDE\devenv.com',
+                 default_dirname='Microsoft Visual Studio .NET',
+                 supported_arch=['x86'],
+    ),
+
+    # Visual Studio 6.0
+    VisualStudio('6.0',
+                 hkey_root=r'Software\Microsoft\VisualStudio\6.0',
+                 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',
+                 default_dirname='Microsoft Visual Studio',
+                 supported_arch=['x86'],
+    ),
+]
+
+SupportedVSMap = {}
+for vs in SupportedVSList:
+    SupportedVSMap[vs.version] = vs
+
+
+# Finding installed versions of Visual Studio isn't cheap, because it
+# goes not only to the registry but also to the disk to sanity-check
+# that there is, in fact, a Visual Studio directory there and that the
+# registry entry isn't just stale.  Find this information once, when
+# requested, and cache it.
+
+InstalledVSList = None
+InstalledVSMap = None
+
+def get_installed_visual_studios():
+    global InstalledVSList
+    global InstalledVSMap
+    if InstalledVSList is None:
+        InstalledVSList = []
+        InstalledVSMap = {}
+        for vs in SupportedVSList:
+            debug('trying to find %s' % vs.version)
+            if vs.get_batch_file():
+                debug('found %s' % vs.version)
+                InstalledVSList.append(vs)
+                InstalledVSMap[vs.version] = vs
+    return InstalledVSList
+
+def reset_installed_visual_studios():
+    global InstalledVSList
+    global InstalledVSMap
+    InstalledVSList = None
+    InstalledVSMap = None
+    for vs in SupportedVSList:
+        vs.reset()
+
+
+# We may be asked to update multiple construction environments with
+# SDK information.  When doing this, we check on-disk for whether
+# the SDK has 'mfc' and 'atl' subdirectories.  Since going to disk
+# is expensive, cache results by directory.
+
+#SDKEnvironmentUpdates = {}
+#
+#def set_sdk_by_directory(env, sdk_dir):
+#    global SDKEnvironmentUpdates
+#    try:
+#        env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
+#    except KeyError:
+#        env_tuple_list = []
+#        SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
+#
+#        include_path = os.path.join(sdk_dir, 'include')
+#        mfc_path = os.path.join(include_path, 'mfc')
+#        atl_path = os.path.join(include_path, 'atl')
+#
+#        if os.path.exists(mfc_path):
+#            env_tuple_list.append(('INCLUDE', mfc_path))
+#        if os.path.exists(atl_path):
+#            env_tuple_list.append(('INCLUDE', atl_path))
+#        env_tuple_list.append(('INCLUDE', include_path))
+#
+#        env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
+#        env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
+#        env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
+#
+#    for variable, directory in env_tuple_list:
+#        env.PrependENVPath(variable, directory)
+
+def detect_msvs():
+    return (len(get_installed_visual_studios()) > 0)
+
+def get_vs_by_version(msvs):
+    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)
+    # 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
+    # tests) on systems that don't, or won't ever, have it installed.
+    # It might be worth resurrecting this, with some configurable
+    # setting that the tests can use to bypass the check.
+    #if not vs:
+    #    msg = "Visual Studio version %s is not installed" % repr(msvs)
+    #    raise SCons.Errors.UserError, msg
+    return vs
+
+def get_default_version(env):
+    """Returns the default version string to use for MSVS.
+
+    If no version was requested by the user through the MSVS environment
+    variable, query all the available the visual studios through
+    query_versions, and take the highest one.
+
+    Return
+    ------
+    version: str
+        the default version.
+    """
+    if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
+        # TODO(1.5):
+        #versions = [vs.version for vs in get_installed_visual_studios()]
+        versions = map(lambda vs: vs.version, get_installed_visual_studios())
+        env['MSVS'] = {'VERSIONS' : versions}
+    else:
+        versions = env['MSVS'].get('VERSIONS', [])
+
+    if not env.has_key('MSVS_VERSION'):
+        if versions:
+            env['MSVS_VERSION'] = versions[0] #use highest version by default
+        else:
+            env['MSVS_VERSION'] = SupportedVSList[0].version
+
+    env['MSVS']['VERSION'] = env['MSVS_VERSION']
+
+    return env['MSVS_VERSION']
+
+def get_default_arch(env):
+    """Return the default arch to use for MSVS
+
+    if no version was requested by the user through the MSVS_ARCH environment
+    variable, select x86
+
+    Return
+    ------
+    arch: str
+    """
+    arch = env.get('MSVS_ARCH', 'x86')
+
+    msvs = InstalledVSMap.get(env['MSVS_VERSION'])
+
+    if not msvs:
+        arch = 'x86'
+    elif not arch in msvs.get_supported_arch():
+        fmt = "Visual Studio version %s does not support architecture %s"
+        raise SCons.Errors.UserError, fmt % (env['MSVS_VERSION'], arch)
+
+    return arch
+
+def merge_default_version(env):
+    version = get_default_version(env)
+    arch = get_default_arch(env)
+
+    msvs = get_vs_by_version(version)
+    if msvs is None:
+        return
+    batfilename = msvs.get_batch_file()
+
+    # XXX: I think this is broken. This will silently set a bogus tool instead
+    # of failing, but there is no other way with the current scons tool
+    # framework
+    if batfilename is not None:
+
+        vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE')
+
+        msvs_list = get_installed_visual_studios()
+        # TODO(1.5):
+        #vscommonvarnames = [ vs.common_tools_var for vs in msvs_list ]
+        vscommonvarnames = map(lambda vs: vs.common_tools_var, msvs_list)
+        nenv = normalize_env(env['ENV'], vscommonvarnames + ['COMSPEC'])
+        output = get_output(batfilename, arch, env=nenv)
+        vars = parse_output(output, vars)
+
+        for k, v in vars.items():
+            env.PrependENVPath(k, v, delete_existing=1)
+
+def query_versions():
+    """Query the system to get available versions of VS. A version is
+    considered when a batfile is found."""
+    msvs_list = get_installed_visual_studios()
+    # TODO(1.5)
+    #versions = [ msvs.version for msvs in msvs_list ]
+    versions = map(lambda msvs:  msvs.version, msvs_list)
+    return versions
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSVCCommon/TODO

-Last Change: Fri Oct 17 04:00 PM 2008 J
-
-- Make sure VS 6 and VS 2003 .Net work (with their own SDK)
-- See whether current unit tests can be updated and need to be rewritten from
-  scratch

File src/engine/SCons/Tool/MSVCCommon/__init__.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__ = """
-Common functions for Microsoft Visual Studio and Visual C/C++.
-"""
-
-import copy
-import os
-import re
-import subprocess
-
-import SCons.Errors
-import SCons.Platform.win32
-import SCons.Util
-
-from SCons.Tool.MSVCCommon.vs import detect_msvs, \
-                                     get_default_version, \
-                                     get_vs_by_version, \
-                                     merge_default_version, \
-                                     query_versions
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSVCCommon/common.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__ = """
-Common helper functions for working with
-"""
-
-import copy
-import os
-import subprocess
-import re
-
-import SCons.Util
-
-# Uncomment to enable debug logging to your choice of file
-#import logging,os
-#os.unlink('c:/tmp/debug.log')
-#logging.basicConfig(filename='c:/tmp/debug.log', level=logging.DEBUG,)
-
-try:
-    from logging import debug
-except ImportError:
-    debug = lambda x : None
-
-#debug = lambda x : open('con', 'w').write(x + '\n')
-
-# TODO(sgk): unused
-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
-
-def read_reg(value):
-    return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0]
-
-
-# Functions for fetching environment variable settings from batch files.
-
-def normalize_env(env, keys):
-    """Given a dictionary representing a shell environment, add the variables
-    from os.environ needed for the processing of .bat files; the keys are
-    controlled by the keys argument.
-
-    It also makes sure the environment values are correctly encoded.
-
-    Note: the environment is copied"""
-    normenv = {}
-    if env:
-        for k in env.keys():
-            normenv[k] = copy.deepcopy(env[k]).encode('mbcs')
-
-        for k in keys:
-            if os.environ.has_key(k):
-                normenv[k] = os.environ[k].encode('mbcs')
-
-    return normenv
-
-def get_output(vcbat, args = None, env = None):
-    """Parse the output of given bat file, with given args."""
-    if args:
-        debug("Calling '%s %s'" % (vcbat, args))
-        popen = subprocess.Popen('"%s" %s & set' % (vcbat, args),
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE,
-                                 env=env)
-    else:
-        debug("Calling '%s'" % vcbat)
-        popen = subprocess.Popen('"%s" & set' % vcbat,
-                                 stdout=subprocess.PIPE,
-                                 stderr=subprocess.PIPE,
-                                 env=env)
-
-    # Use the .stdout and .stderr attributes directly because the
-    # .communicate() method uses the threading module on Windows
-    # and won't work under Pythons not built with threading.
-    stdout = popen.stdout.read()
-    if popen.wait() != 0:
-        raise IOError(popen.stderr.read().decode("mbcs"))
-
-    output = stdout.decode("mbcs")
-    return output
-
-def parse_output(output, keep = ("INCLUDE", "LIB", "LIBPATH", "PATH")):
-    # dkeep is a dict associating key: path_list, where key is one item from
-    # keep, and pat_list the associated list of paths
-
-    # TODO(1.5):  replace with the following list comprehension:
-    #dkeep = dict([(i, []) for i in keep])
-    dkeep = dict(map(lambda i: (i, []), keep))
-
-    # rdk will  keep the regex to match the .bat file output line starts
-    rdk = {}
-    for i in keep:
-        rdk[i] = re.compile('%s=(.*)' % i, re.I)
-
-    def add_env(rmatch, key):
-        plist = rmatch.group(1).split(os.pathsep)
-        for p in plist:
-            # Do not add empty paths (when a var ends with ;)
-            if p:
-                p = p.encode('mbcs')
-                # XXX: For some reason, VC98 .bat file adds "" around the PATH
-                # values, and it screws up the environment later, so we strip
-                # it. 
-                p = p.strip('"')
-                dkeep[key].append(p)
-
-    for line in output.splitlines():
-        for k,v in rdk.items():
-            m = v.match(line)
-            if m:
-                add_env(m, k)
-
-    return dkeep
-
-# TODO(sgk): unused
-def output_to_dict(output):
-    """Given an output string, parse it to find env variables.
-
-    Return a dict where keys are variables names, and values their content"""
-    envlinem = re.compile(r'^([a-zA-z0-9]+)=([\S\s]*)$')
-    parsedenv = {}
-    for line in output.splitlines():
-        m = envlinem.match(line)
-        if m:
-            parsedenv[m.group(1)] = m.group(2)
-    return parsedenv
-
-# TODO(sgk): unused
-def get_new(l1, l2):
-    """Given two list l1 and l2, return the items in l2 which are not in l1.
-    Order is maintained."""
-
-    # We don't try to be smart: lists are small, and this is not the bottleneck
-    # is any case
-    new = []
-    for i in l2:
-        if i not in l1:
-            new.append(i)
-
-    return new
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSVCCommon/msvc_changes.txt

-The Visual Studio support has been totally revamped. Instead of using registry
-magic, we use the .bat files available for each version of visual studio. This
-is simpler (does not depend on the version of the compiler), more reliable, and
-just plain better.
-
-Specification
-=============
-
-Tested versions
----------------
-
-The following versions have been succesfully tested:
-  - VS 2008 (express), 32 bits
-  - VS 2005 (express), 32 bits
-  - VS 2003 (.Net, pro), 32 bits
-
-Detection
----------
-
-All tools related to the ms toolchain are detected through the same method:
-  - detect the .bat configuration file (vsvarsall.bat/vsvars32.bat
-    depending on the version) from the registry
-  - if registry does not return anything useful, use the VS*COMNTOOLS env
-    variable.
-
-A version is detected only when the .bat file actually exists on the
-filesystem.  Once the .bat file is found, it is executed through a clean
-environment, and its output is parsed to get the variables
-PATH/LIB/LIBPATH/INCLUDE. Those variables are then added to env['ENV']
-
-By default, the most recent detected version is set, and can be queried in
-env['MSVS_VERSION'] *after* the tool initialization. The version can be forced
-by setting the MSVS_VERSION variable *before* initializing the tool.
-
-SDK
----
-
-Separate SDKs are only supported for the following versions:
-        - Platform SDK 2003 R1 and R2
-        - Windows SDK. I tried the following versions: 6.0, 6.0A (SDK delivered
-          with VS 2008 express) and 6.1 (Windows SDK 2008).
-
-Previous SDKs are not available anymore on MS website, so I could not test
-them. I believe VS 6 has its own SDK included, as well as VS 2003 .Net. The SDK
-is set *after* the msvs tool.
-
-The version of the SDK can be controlled by the scons variable:
-
-    MSSDK_DIR:      If set, specifies the directory location of the
-                    SDK to be used.
-
-    MSSDK_VERSION:  If set, specifies the version of the SDK to be used.
-
-If neither of these is set, MSVS_VERSION is used to pick an appropriate
-default.
-
-Architecture
-------------
-
-env['MSVS_ARCH'] = 'x86'
-                   'amd64'
-
-If not set, the selection logic defaults to x86. Cross compiling has been
-disabled, filtering out values not included in version.SUPPORTED_ARCH.
-(No tests made with cross compiling.)
-
-Fundamental changes
-===================
-
-env["ENV"] has been expanded a bit on windows:
-  - add %SystemRoot%\system32 in the path for windows
-  - add COMSPEC (needed by the .bat file execution)
-
-Internals
-=========
-
-The code can be found in the MSVCCommon submodule:
-  - findloc: find the product dir from the registry or the shell environment
-        - versions: query the system for available versions of the VS suite on
-          the system
-        - misc: high level functions, *candidates* for the public API.
-        - sdk: specifics to the SDK detection.
-        - defaults: default values to use for the paths, to use instead of the
-          whole env parsing which can be quite slow, but less reliable. Still
-          experimental, may be removed
-  - envhelpers: functions to execute a VS .bat file, parse its output,
-    and get the variables with modified values.
-
-At this point, no function should be considered public, the exact API is not
-good yet.

File src/engine/SCons/Tool/MSVCCommon/netframework.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__ = """
-"""
-
-import os
-import re
-import string
-
-from common import read_reg, debug
-
-# Original value recorded by dcournapeau
-_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot'
-# On SGK's system
-_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder'
-
-def find_framework_root():
-    # XXX: find it from environment (FrameworkDir)
-    try:
-        froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT)
-        debug("Found framework install root in registry: %s" % froot)
-    except WindowsError, e:
-        debug("Could not read reg key %s" % _FRAMEWORKDIR_HKEY_ROOT)
-        return None
-
-    if not os.path.exists(froot):
-        debug("%s not found on fs" % froot)
-        return None
-
-    return froot
-
-def query_versions():
-    froot = find_framework_root()
-    if froot:
-        contents = os.listdir(froot)
-
-        l = re.compile('v[0-9]+.*')
-        versions = filter(lambda e, l=l: l.match(e), contents)
-
-        def versrt(a,b):
-            # since version numbers aren't really floats...
-            aa = a[1:]
-            bb = b[1:]
-            aal = string.split(aa, '.')
-            bbl = string.split(bb, '.')
-            # sequence comparison in python is lexicographical
-            # which is exactly what we want.
-            # Note we sort backwards so the highest version is first.
-            return cmp(bbl,aal)
-
-        versions.sort(versrt)
-    else:
-        versions = []
-
-    return versions
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSVCCommon/sdk.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 detect the Platform/Windows SDK
-
-PSDK 2003 R1 is the earliest version detected.
-"""
-
-import os
-
-import SCons.Errors
-from SCons.Tool.MSVCCommon.common import debug, read_reg
-import SCons.Util
-
-# SDK Checks. This is of course a mess as everything else on MS platforms. Here
-# is what we do to detect the SDK:
-#
-# For Windows SDK >= 6.0: just look into the registry entries:
-#   HKLM\Software\Microsoft\Microsoft SDKs\Windows
-# All the keys in there are the available versions.
-#
-# For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not
-# seem to be any sane registry key, so the precise location is hardcoded.
-#
-# For versions below 2003R1, it seems the PSDK is included with Visual Studio?
-#
-# Also, per the following:
-#     http://benjamin.smedbergs.us/blog/tag/atl/
-# VC++ Professional comes with the SDK, VC++ Express does not.
-
-# Location of the SDK (checked for 6.1 only)
-_CURINSTALLED_SDK_HKEY_ROOT = \
-        r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
-
-
-class SDKDefinition:
-    """
-    An abstract base class for trying to find installed SDK directories.
-    """
-    def __init__(self, version, **kw):
-        self.version = version
-        self.__dict__.update(kw)
-
-    def find_install_dir(self):
-        """Try to find the MS SDK from the registry.
-
-        Return None if failed or the directory does not exist.
-        """
-        if not SCons.Util.can_read_reg:
-            debug('SCons cannot read registry')
-            return None
-
-        hkey = self.HKEY_FMT % self.hkey_data
-
-        try:
-            install_dir = read_reg(hkey)
-            debug('Found sdk dir in registry: %s' % install_dir)
-        except WindowsError, e:
-            debug('Did not find sdk dir key %s in registry' % hkey)
-            return None
-
-        if not os.path.exists(install_dir):
-            debug('%s is not found on the filesystem' % install_dir)
-            return None
-
-        ftc = os.path.join(install_dir, self.sanity_check_file)
-        if not os.path.exists(ftc):
-            debug("File %s used for sanity check not found" % ftc)
-            return None
-
-        return install_dir
-
-    def get_install_dir(self):
-        """Return the MSSSDK given the version string."""
-        try:
-            return self._install_dir
-        except AttributeError:
-            install_dir = self.find_install_dir()
-            self._install_dir = install_dir
-            return install_dir
-
-class WindowsSDK(SDKDefinition):
-    """
-    A subclass for trying to find installed Windows SDK directories.
-    """
-    HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder'
-    def __init__(self, *args, **kw):
-        apply(SDKDefinition.__init__, (self,)+args, kw)
-        self.hkey_data = self.version
-
-class PlatformSDK(SDKDefinition):
-    """
-    A subclass for trying to find installed Platform SDK directories.
-    """
-    HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir'
-    def __init__(self, *args, **kw):
-        apply(SDKDefinition.__init__, (self,)+args, kw)
-        self.hkey_data = self.uuid
-
-# The list of support SDKs which we know how to detect.
-#
-# The first SDK found in the list is the one used by default if there
-# are multiple SDKs installed.  Barring good reasons to the contrary,
-# this means we should list SDKs with from most recent to oldest.
-#
-# If you update this list, update the documentation in Tool/mssdk.xml.
-SupportedSDKList = [
-    WindowsSDK('6.1',
-                sanity_check_file=r'include\windows.h'),
-
-    WindowsSDK('6.0A',
-               sanity_check_file=r'include\windows.h'),
-
-    WindowsSDK('6.0',
-               sanity_check_file=r'bin\gacutil.exe'),
-
-    PlatformSDK('2003R2',
-                sanity_check_file=r'SetEnv.Cmd',
-                uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"),
-
-    PlatformSDK('2003R1',
-                sanity_check_file=r'SetEnv.Cmd',
-                uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3"),
-]
-
-SupportedSDKMap = {}
-for sdk in SupportedSDKList:
-    SupportedSDKMap[sdk.version] = sdk
-
-
-# Finding installed SDKs isn't cheap, because it goes not only to the
-# registry but also to the disk to sanity-check that there is, in fact,
-# an SDK installed there and that the registry entry isn't just stale.
-# Find this information once, when requested, and cache it.
-
-InstalledSDKList = None
-InstalledSDKMap = None
-
-def get_installed_sdks():
-    global InstalledSDKList
-    global InstalledSDKMap
-    if InstalledSDKList is None:
-        InstalledSDKList = []
-        InstalledSDKMap = {}
-        for sdk in SupportedSDKList:
-            if sdk.get_install_dir():
-                InstalledSDKList.append(sdk)
-                InstalledSDKMap[sdk.version] = sdk
-    return InstalledSDKList
-
-
-# We may be asked to update multiple construction environments with
-# SDK information.  When doing this, we check on-disk for whether
-# the SDK has 'mfc' and 'atl' subdirectories.  Since going to disk
-# is expensive, cache results by directory.
-
-SDKEnvironmentUpdates = {}
-
-def set_sdk_by_directory(env, sdk_dir):
-    global SDKEnvironmentUpdates
-    try:
-        env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
-    except KeyError:
-        env_tuple_list = []
-        SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
-
-        include_path = os.path.join(sdk_dir, 'include')
-        mfc_path = os.path.join(include_path, 'mfc')
-        atl_path = os.path.join(include_path, 'atl')
-
-        if os.path.exists(mfc_path):
-            env_tuple_list.append(('INCLUDE', mfc_path))
-        if os.path.exists(atl_path):
-            env_tuple_list.append(('INCLUDE', atl_path))
-        env_tuple_list.append(('INCLUDE', include_path))
-
-        env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
-        env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
-        env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
-
-    for variable, directory in env_tuple_list:
-        env.PrependENVPath(variable, directory)
-
-
-# TODO(sgk):  currently unused; remove?
-def get_cur_sdk_dir_from_reg():
-    """Try to find the platform sdk directory from the registry.
-
-    Return None if failed or the directory does not exist"""
-    if not SCons.Util.can_read_reg:
-        debug('SCons cannot read registry')
-        return None
-
-    try:
-        val = 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 None
-
-    if not os.path.exists(val):
-        debug("Current sdk dir %s not on fs" % val)
-        return None
-
-    return val
-
-
-def detect_sdk():
-    return (len(get_installed_sdks()) > 0)
-
-def set_sdk_by_version(env, 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_install_dir())
-
-def set_default_sdk(env, msver):
-    """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_install_dir())
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:

File src/engine/SCons/Tool/MSVCCommon/vs.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 detect Visual Studio and/or Visual C/C++
-"""
-
-import os
-
-import SCons.Errors
-import SCons.Util
-
-from SCons.Tool.MSVCCommon.common import debug, \
-                                         read_reg, \
-                                         normalize_env, \
-                                         get_output, \
-                                         parse_output
-
-class VisualStudio:
-    """
-    An abstract base class for trying to find installed versions of
-    Visual Studio.
-    """
-    def __init__(self, version, **kw):
-        self.version = version
-        self.__dict__.update(kw)
-        self._cache = {}
-
-    def batch_file_path(self):
-        pdir = self.get_vc_product_dir()
-        if not pdir:
-            return None
-        return os.path.join(pdir, self.batch_file)
-
-    def common_tools_path(self):
-        return os.environ.get(self.common_tools_var)
-
-    def vc_product_dir_path(self):
-        if not SCons.Util.can_read_reg:
-            debug('SCons can not read registry')
-            return None
-        key = self.hkey_root + '\\' + self.vc_product_dir_key
-        try:
-            comps = read_reg(key)
-        except WindowsError, e:
-            debug('Did not find product dir key %s in registry' % key)
-        else:
-            if self.batch_file_dir_reg_relpath:
-                comps = os.path.join(comps, self.batch_file_dir_reg_relpath)
-            if os.path.exists(comps):
-                return comps
-            debug('%s is not found on the file system' % comps)
-
-    #
-
-    def find_batch_file(self):