summaryrefslogtreecommitdiff
path: root/engine/SCons/Tool/MSCommon
diff options
context:
space:
mode:
Diffstat (limited to 'engine/SCons/Tool/MSCommon')
-rw-r--r--engine/SCons/Tool/MSCommon/__init__.py56
-rw-r--r--engine/SCons/Tool/MSCommon/arch.py61
-rw-r--r--engine/SCons/Tool/MSCommon/common.py195
-rw-r--r--engine/SCons/Tool/MSCommon/netframework.py84
-rw-r--r--engine/SCons/Tool/MSCommon/sdk.py321
-rw-r--r--engine/SCons/Tool/MSCommon/vc.py367
-rw-r--r--engine/SCons/Tool/MSCommon/vs.py497
7 files changed, 1581 insertions, 0 deletions
diff --git a/engine/SCons/Tool/MSCommon/__init__.py b/engine/SCons/Tool/MSCommon/__init__.py
new file mode 100644
index 0000000..4f56a4a
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/__init__.py
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/__init__.py 4577 2009/12/27 19:43:56 scons"
+
+__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.sdk import mssdk_exists, \
+ mssdk_setup_env
+
+from SCons.Tool.MSCommon.vc import msvc_exists, \
+ msvc_setup_env, \
+ msvc_setup_env_once
+
+from SCons.Tool.MSCommon.vs import get_default_version, \
+ get_vs_by_version, \
+ merge_default_version, \
+ msvs_exists, \
+ query_versions
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/engine/SCons/Tool/MSCommon/arch.py b/engine/SCons/Tool/MSCommon/arch.py
new file mode 100644
index 0000000..ce214c2
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/arch.py
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/arch.py 4577 2009/12/27 19:43:56 scons"
+
+__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
+
diff --git a/engine/SCons/Tool/MSCommon/common.py b/engine/SCons/Tool/MSCommon/common.py
new file mode 100644
index 0000000..219e680
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/common.py
@@ -0,0 +1,195 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/common.py 4577 2009/12/27 19:43:56 scons"
+
+__doc__ = """
+Common helper functions for working with the Microsoft tool chain.
+"""
+
+import copy
+import os
+import subprocess
+import re
+
+import SCons.Util
+
+
+logfile = os.environ.get('SCONS_MSCOMMON_DEBUG')
+if logfile == '-':
+ def debug(x):
+ print x
+elif logfile:
+ try:
+ import logging
+ except ImportError:
+ debug = lambda x: open(logfile, 'a').write(x + '\n')
+ else:
+ logging.basicConfig(filename=logfile, level=logging.DEBUG)
+ debug = logging.debug
+else:
+ debug = lambda x: None
+
+
+_is_win64 = None
+
+def is_win64():
+ """Return true if running on windows 64 bits.
+
+ Works whether python itself runs in 64 bits or 32 bits."""
+ # 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:
+ _is_win64 = has_reg(r"Software\Wow6432Node")
+ return _is_win64
+
+
+def read_reg(value):
+ return SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, value)[0]
+
+def has_reg(value):
+ """Return True if the given key exists in HKEY_LOCAL_MACHINE, False
+ otherwise."""
+ try:
+ SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value)
+ ret = True
+ except WindowsError:
+ ret = False
+ return ret
+
+# 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, dkeep=dkeep):
+ 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:
diff --git a/engine/SCons/Tool/MSCommon/netframework.py b/engine/SCons/Tool/MSCommon/netframework.py
new file mode 100644
index 0000000..300f662
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/netframework.py
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/netframework.py 4577 2009/12/27 19:43:56 scons"
+
+__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:
diff --git a/engine/SCons/Tool/MSCommon/sdk.py b/engine/SCons/Tool/MSCommon/sdk.py
new file mode 100644
index 0000000..f1345e4
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/sdk.py
@@ -0,0 +1,321 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/sdk.py 4577 2009/12/27 19:43:56 scons"
+
+__doc__ = """Module to detect the Platform/Windows SDK
+
+PSDK 2003 R1 is the earliest version detected.
+"""
+
+import os
+
+import SCons.Errors
+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:
+#
+# 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_sdk_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('find_sdk_dir(): can not read registry')
+ return None
+
+ hkey = self.HKEY_FMT % self.hkey_data
+
+ try:
+ sdk_dir = common.read_reg(hkey)
+ except WindowsError, e:
+ debug('find_sdk_dir(): no SDK registry key %s' % repr(hkey))
+ return None
+
+ if not os.path.exists(sdk_dir):
+ debug('find_sdk_dir(): %s not on file system' % sdk_dir)
+ return None
+
+ 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)
+ return None
+
+ return sdk_dir
+
+ def get_sdk_dir(self):
+ """Return the MSSSDK given the version string."""
+ try:
+ return self._sdk_dir
+ except AttributeError:
+ sdk_dir = self.find_sdk_dir()
+ self._sdk_dir = sdk_dir
+ return sdk_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'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',
+ 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',
+ include_subdir='include',
+ lib_subdir='lib',
+ ),
+
+ 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:
+ debug('trying to find SDK %s' % sdk.version)
+ if sdk.get_sdk_dir():
+ debug('found SDK %s' % sdk.version)
+ 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 = 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 None
+
+ if not os.path.exists(val):
+ debug("Current sdk dir %s not on fs" % val)
+ return None
+
+ return val
+
+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()
+ return InstalledSDKMap.get(mssdk)
+
+def get_default_sdk():
+ """Set up the default Platform/Windows SDK."""
+ get_installed_sdks()
+ if not InstalledSDKList:
+ return None
+ 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)
+ if not msvs:
+ return
+ 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
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/engine/SCons/Tool/MSCommon/vc.py b/engine/SCons/Tool/MSCommon/vc.py
new file mode 100644
index 0000000..c02f15c
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/vc.py
@@ -0,0 +1,367 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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.
+#
+
+# TODO:
+# * supported arch for versions: for old versions of batch file without
+# argument, giving bogus argument cannot be detected, so we have to hardcode
+# this here
+# * print warning when msvc version specified but not found
+# * find out why warning do not print
+# * test on 64 bits XP + VS 2005 (and VS 6 if possible)
+# * SDK
+# * Assembly
+__revision__ = "src/engine/SCons/Tool/MSCommon/vc.py 4577 2009/12/27 19:43:56 scons"
+
+__doc__ = """Module for Visual C/C++ detection and configuration.
+"""
+import SCons.compat
+
+import os
+import platform
+
+import SCons.Warnings
+
+import common
+
+debug = common.debug
+
+class VisualCException(Exception):
+ pass
+
+class UnsupportedVersion(VisualCException):
+ pass
+
+class UnsupportedArch(VisualCException):
+ pass
+
+class MissingConfiguration(VisualCException):
+ pass
+
+class NoVersionFound(VisualCException):
+ pass
+
+class BatchFileExecutionError(VisualCException):
+ pass
+
+# Dict to 'canonalize' the arch
+_ARCH_TO_CANONICAL = {
+ "x86": "x86",
+ "amd64": "amd64",
+ "i386": "x86",
+ "emt64": "amd64",
+ "x86_64": "amd64",
+ "itanium": "ia64",
+ "ia64": "ia64",
+}
+
+# Given a (host, target) tuple, return the argument for the bat file. Both host
+# and targets should be canonalized.
+_HOST_TARGET_ARCH_TO_BAT_ARCH = {
+ ("x86", "x86"): "x86",
+ ("x86", "amd64"): "x86_amd64",
+ ("amd64", "amd64"): "amd64",
+ ("amd64", "x86"): "x86",
+ ("x86", "ia64"): "x86_ia64"
+}
+
+def get_host_target(env):
+ host_platform = env.get('HOST_ARCH')
+ if not host_platform:
+ host_platform = platform.machine()
+ # TODO(2.5): the native Python platform.machine() function returns
+ # '' on all Python versions before 2.6, after which it also uses
+ # PROCESSOR_ARCHITECTURE.
+ if not host_platform:
+ host_platform = os.environ.get('PROCESSOR_ARCHITECTURE', '')
+ target_platform = env.get('TARGET_ARCH')
+ if not target_platform:
+ target_platform = host_platform
+
+ try:
+ host = _ARCH_TO_CANONICAL[host_platform]
+ except KeyError, e:
+ msg = "Unrecognized host architecture %s"
+ raise ValueError(msg % repr(host_platform))
+
+ try:
+ target = _ARCH_TO_CANONICAL[target_platform]
+ except KeyError, e:
+ raise ValueError("Unrecognized target architecture %s" % target_platform)
+
+ return (host, target)
+
+_VCVER = ["10.0", "9.0", "8.0", "7.1", "7.0", "6.0"]
+
+_VCVER_TO_PRODUCT_DIR = {
+ '10.0': [
+ r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'],
+ '9.0': [
+ r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',
+ r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'],
+ '8.0': [
+ r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir',
+ r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'],
+ '7.1': [
+ r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'],
+ '7.0': [
+ r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'],
+ '6.0': [
+ r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir']
+}
+
+def msvc_version_to_maj_min(msvc_version):
+ t = msvc_version.split(".")
+ if not len(t) == 2:
+ raise ValueError("Unrecognized version %s" % msvc_version)
+ try:
+ maj = int(t[0])
+ min = int(t[1])
+ return maj, min
+ except ValueError, e:
+ raise ValueError("Unrecognized version %s" % msvc_version)
+
+def is_host_target_supported(host_target, msvc_version):
+ """Return True if the given (host, target) tuple is supported given the
+ msvc version.
+
+ Parameters
+ ----------
+ host_target: tuple
+ tuple of (canonalized) host-target, e.g. ("x86", "amd64") for cross
+ compilation from 32 bits windows to 64 bits.
+ msvc_version: str
+ msvc version (major.minor, e.g. 10.0)
+
+ Note
+ ----
+ This only check whether a given version *may* support the given (host,
+ target), not that the toolchain is actually present on the machine.
+ """
+ # We assume that any Visual Studio version supports x86 as a target
+ if host_target[1] != "x86":
+ maj, min = msvc_version_to_maj_min(msvc_version)
+ if maj < 8:
+ return False
+
+ return True
+
+def find_vc_pdir(msvc_version):
+ """Try to find the product directory for the given
+ version.
+
+ Note
+ ----
+ If for some reason the requested version could not be found, an
+ exception which inherits from VisualCException will be raised."""
+ root = 'Software\\'
+ if common.is_win64():
+ root = root + 'Wow6432Node\\'
+ try:
+ hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
+ except KeyError:
+ debug("Unknown version of MSVC: %s" % msvc_version)
+ raise UnsupportedVersion("Unknown version %s" % msvc_version)
+
+ for key in 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)
+ if os.path.exists(comps):
+ return comps
+ else:
+ debug('find_vc_dir(): reg says dir is %s, but it does not exist. (ignoring)'\
+ % comps)
+ raise MissingConfiguration("registry dir %s not found on the filesystem" % comps)
+ return None
+
+def find_batch_file(msvc_version):
+ pdir = find_vc_pdir(msvc_version)
+ if pdir is None:
+ raise NoVersionFound("No version of Visual Studio found")
+
+ vernum = float(msvc_version)
+ if 7 <= vernum < 8:
+ pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
+ batfilename = os.path.join(pdir, "vsvars32.bat")
+ elif vernum < 7:
+ pdir = os.path.join(pdir, "Bin")
+ batfilename = os.path.join(pdir, "vcvars32.bat")
+ else: # >= 8
+ batfilename = os.path.join(pdir, "vcvarsall.bat")
+
+ if os.path.exists(batfilename):
+ return batfilename
+ else:
+ debug("Not found: %s" % batfilename)
+ return None
+
+__INSTALLED_VCS_RUN = None
+
+def cached_get_installed_vcs():
+ global __INSTALLED_VCS_RUN
+
+ if __INSTALLED_VCS_RUN is None:
+ ret = get_installed_vcs()
+ __INSTALLED_VCS_RUN = ret
+
+ return __INSTALLED_VCS_RUN
+
+def get_installed_vcs():
+ installed_versions = []
+ for ver in _VCVER:
+ debug('trying to find VC %s' % ver)
+ try:
+ if find_vc_pdir(ver):
+ debug('found VC %s' % ver)
+ installed_versions.append(ver)
+ else:
+ debug('find_vc_pdir return None for ver %s' % ver)
+ except VisualCException, e:
+ debug('did not find VC %s: caught exception %s' % (ver, str(e)))
+ return installed_versions
+
+def reset_installed_vcs():
+ """Make it try again to find VC. This is just for the tests."""
+ __INSTALLED_VCS_RUN = None
+
+def script_env(script, args=None):
+ stdout = common.get_output(script, args)
+ # Stupid batch files do not set return code: we take a look at the
+ # beginning of the output for an error message instead
+ olines = stdout.splitlines()
+ if olines[0].startswith("The specified configuration type is missing"):
+ raise BatchFileExecutionError("\n".join(olines[:2]))
+
+ return common.parse_output(stdout)
+
+def get_default_version(env):
+ debug('get_default_version()')
+
+ msvc_version = env.get('MSVC_VERSION')
+ msvs_version = env.get('MSVS_VERSION')
+
+ if msvs_version and not msvc_version:
+ SCons.Warnings.warn(
+ SCons.Warnings.DeprecatedWarning,
+ "MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
+ return msvs_version
+ elif msvc_version and msvs_version:
+ if not msvc_version == msvs_version:
+ SCons.Warnings.warn(
+ SCons.Warnings.VisualVersionMismatch,
+ "Requested msvc version (%s) and msvs version (%s) do " \
+ "not match: please use MSVC_VERSION only to request a " \
+ "visual studio version, MSVS_VERSION is deprecated" \
+ % (msvc_version, msvs_version))
+ return msvs_version
+ if not msvc_version:
+ installed_vcs = cached_get_installed_vcs()
+ debug('installed_vcs:%s' % installed_vcs)
+ if not installed_vcs:
+ msg = 'No installed VCs'
+ debug('msv %s\n' % repr(msg))
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+ return None
+ msvc_version = installed_vcs[0]
+ debug('msvc_setup_env: using default installed MSVC version %s\n' % repr(msvc_version))
+
+ return msvc_version
+
+def msvc_setup_env_once(env):
+ try:
+ has_run = env["MSVC_SETUP_RUN"]
+ except KeyError:
+ has_run = False
+
+ if not has_run:
+ msvc_setup_env(env)
+ env["MSVC_SETUP_RUN"] = True
+
+def msvc_setup_env(env):
+ debug('msvc_setup_env()')
+
+ version = get_default_version(env)
+ if version is None:
+ warn_msg = "No version of Visual Studio compiler found - C/C++ " \
+ "compilers most likely not set correctly"
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ return None
+ debug('msvc_setup_env: using specified MSVC version %s\n' % repr(version))
+
+ # XXX: we set-up both MSVS version for backward
+ # compatibility with the msvs tool
+ env['MSVC_VERSION'] = version
+ env['MSVS_VERSION'] = version
+ env['MSVS'] = {}
+
+ try:
+ script = find_batch_file(version)
+ except VisualCException, e:
+ msg = str(e)
+ debug('Caught exception while looking for batch file (%s)' % msg)
+ warn_msg = "VC version %s not installed. " + \
+ "C/C++ compilers are most likely not set correctly.\n" + \
+ " Installed versions are: %s"
+ warn_msg = warn_msg % (version, cached_get_installed_vcs())
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ return None
+
+ 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:
+ host_platform, target_platform = get_host_target(env)
+ host_target = (host_platform, target_platform)
+ if not is_host_target_supported(host_target, version):
+ warn_msg = "host, target = %s not supported for MSVC version %s" % \
+ (host_target, version)
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
+ debug('use_script 2 %s, args:%s\n' % (repr(script), arg))
+ try:
+ d = script_env(script, args=arg)
+ except BatchFileExecutionError, e:
+ msg = "MSVC error while executing %s with args %s (error was %s)" % \
+ (script, arg, str(e))
+ raise SCons.Errors.UserError(msg)
+ else:
+ debug('MSVC_USE_SCRIPT set to False')
+ warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
+ "set correctly."
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
+ return None
+
+ for k, v in d.items():
+ env.PrependENVPath(k, v, delete_existing=True)
+
+def msvc_exists(version=None):
+ vcs = cached_get_installed_vcs()
+ if version is None:
+ return len(vcs) > 0
+ return version in vcs
+
diff --git a/engine/SCons/Tool/MSCommon/vs.py b/engine/SCons/Tool/MSCommon/vs.py
new file mode 100644
index 0000000..f9531c0
--- /dev/null
+++ b/engine/SCons/Tool/MSCommon/vs.py
@@ -0,0 +1,497 @@
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
+#
+# 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__ = "src/engine/SCons/Tool/MSCommon/vs.py 4577 2009/12/27 19:43:56 scons"
+
+__doc__ = """Module to detect Visual Studio and/or Visual C/C++
+"""
+
+import os
+
+import SCons.Errors
+import SCons.Util
+
+from common import debug, \
+ get_output, \
+ is_win64, \
+ normalize_env, \
+ parse_output, \
+ read_reg
+
+import SCons.Tool.MSCommon.vc
+
+class VisualStudio:
+ """
+ An abstract base class for trying to find installed versions of
+ Visual Studio.
+ """
+ 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):
+ vs_dir = self.get_vs_dir()
+ if not vs_dir:
+ debug('find_executable(): no vs_dir')
+ return None
+ 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()
+ dir = SCons.Tool.MSCommon.vc.find_vc_pdir(self.vc_version)
+ if not dir:
+ debug('find_vs_dir(): no installed VC %s' % self.vc_version)
+ return None
+ return dir
+
+ 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):
+ 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(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 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:
+ debug('get_executable using cache:%s'%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']
+ 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 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',
+ # executable_path=r'TBD',
+ # default_dirname='TBD',
+ #),
+
+ # Visual Studio 2008
+ # The batch file we look for is in the VC directory,
+ # so the devenv.com executable is up in ..\..\Common7\IDE.
+ VisualStudio('9.0',
+ sdk_version='6.1',
+ hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'],
+ common_tools_var='VS90COMNTOOLS',
+ 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'],
+ ),
+
+ # Visual C++ 2008 Express Edition
+ # The batch file we look for is in the VC directory,
+ # so the VCExpress.exe executable is up in ..\..\Common7\IDE.
+ VisualStudio('9.0Exp',
+ vc_version='9.0',
+ sdk_version='6.1',
+ hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'],
+ common_tools_var='VS90COMNTOOLS',
+ executable_path=r'Common7\IDE\VCExpress.exe',
+ batch_file_path=r'Common7\Tools\vsvars32.bat',
+ default_dirname='Microsoft Visual Studio 9',
+ supported_arch=['x86'],
+ ),
+
+ # Visual Studio 2005
+ # The batch file we look for is in the VC directory,
+ # so the devenv.com executable is up in ..\..\Common7\IDE.
+ VisualStudio('8.0',
+ sdk_version='6.0A',
+ hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'],
+ common_tools_var='VS80COMNTOOLS',
+ 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'],
+ ),
+
+ # Visual C++ 2005 Express Edition
+ # The batch file we look for is in the VC directory,
+ # so the VCExpress.exe executable is up in ..\..\Common7\IDE.
+ VisualStudio('8.0Exp',
+ vc_version='8.0',
+ sdk_version='6.0A',
+ hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'],
+ common_tools_var='VS80COMNTOOLS',
+ executable_path=r'Common7\IDE\VCExpress.exe',
+ batch_file_path=r'Common7\Tools\vsvars32.bat',
+ default_dirname='Microsoft Visual Studio 8',
+ supported_arch=['x86'],
+ ),
+
+ # Visual Studio .NET 2003
+ # 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',
+ sdk_version='6.0',
+ hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'],
+ common_tools_var='VS71COMNTOOLS',
+ executable_path=r'Common7\IDE\devenv.com',
+ batch_file_path=r'Common7\Tools\vsvars32.bat',
+ default_dirname='Microsoft Visual Studio .NET 2003',
+ supported_arch=['x86'],
+ ),
+
+ # Visual Studio .NET
+ # 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',
+ sdk_version='2003R2',
+ hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
+ common_tools_var='VS70COMNTOOLS',
+ 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',
+ sdk_version='2003R1',
+ hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir',
+ 'use_dir'],
+ common_tools_var='VS60COMNTOOLS',
+ executable_path=r'Common\MSDev98\Bin\MSDEV.COM',
+ batch_file_path=r'Common7\Tools\vsvars32.bat',
+ 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 VS %s' % vs.version)
+ if vs.get_executable():
+ debug('found VS %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()
+
+ # 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
+# 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 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
+ # 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)
+
+def msvs_setup_env(env):
+ batfilename = msvs.get_batch_file()
+ msvs = get_vs_by_version(version)
+ if msvs is None:
+ return
+
+ # 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: