summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Knight <knight@baldmt.com>2003-06-08 13:22:57 (GMT)
committerSteven Knight <knight@baldmt.com>2003-06-08 13:22:57 (GMT)
commit4d7ed00302f2f872f9719125b4fcb048e4ecb7ef (patch)
tree4afaba4669ddae8c3ce9972f79471d8387930e87
parent8fc3c77d320fb435cb9268d31c34a58b18a58b54 (diff)
downloadSCons-4d7ed00302f2f872f9719125b4fcb048e4ecb7ef.zip
SCons-4d7ed00302f2f872f9719125b4fcb048e4ecb7ef.tar.gz
SCons-4d7ed00302f2f872f9719125b4fcb048e4ecb7ef.tar.bz2
Add MSVS Project file support. (Greg Spencer)
-rw-r--r--bin/files1
-rw-r--r--doc/man/scons.168
-rw-r--r--runtest.py1
-rw-r--r--src/CHANGES.txt10
-rw-r--r--src/RELEASE.txt7
-rw-r--r--src/engine/MANIFEST.in1
-rw-r--r--src/engine/SCons/Environment.py47
-rw-r--r--src/engine/SCons/EnvironmentTests.py48
-rw-r--r--src/engine/SCons/Platform/win32.py42
-rw-r--r--src/engine/SCons/Script/SConscript.py9
-rw-r--r--src/engine/SCons/Tool/__init__.py2
-rw-r--r--src/engine/SCons/Tool/mslib.py21
-rw-r--r--src/engine/SCons/Tool/mslink.py34
-rw-r--r--src/engine/SCons/Tool/msvc.py320
-rw-r--r--src/engine/SCons/Tool/msvs.py1030
-rw-r--r--src/engine/SCons/Tool/msvsTests.py476
-rw-r--r--src/engine/SCons/Util.py88
-rw-r--r--src/engine/SCons/UtilTests.py24
-rw-r--r--test/import.py25
-rw-r--r--test/midl.py2
-rw-r--r--test/msvs.py415
21 files changed, 2546 insertions, 125 deletions
diff --git a/bin/files b/bin/files
index 86f297c..4e3a863 100644
--- a/bin/files
+++ b/bin/files
@@ -64,6 +64,7 @@
./SCons/Tool/mslib.py
./SCons/Tool/mslink.py
./SCons/Tool/msvc.py
+./SCons/Tool/msvs.py
./SCons/Tool/nasm.py
./SCons/Tool/pdflatex.py
./SCons/Tool/pdftex.py
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 1a1b81f..32546ed 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -31,7 +31,7 @@
.RE
.fi
..
-.TH SCONS 1 "May 2003"
+.TH SCONS 1 "June 2003"
.SH NAME
scons \- a software construction tool
.SH SYNOPSIS
@@ -887,6 +887,7 @@ mingw
mslib
mslink
msvc
+msvs
nasm
pdflatex
pdftex
@@ -1150,6 +1151,49 @@ Example:
env.Program(target = 'foo', source = ['foo.o', 'bar.c', 'baz.f'])
.EE
+.IP MSVSProject
+Builds Microsoft Visual Studio project files.
+.B scons
+will detect installed versions of Visual Studio
+up to and including versions 7.x (.NET).
+When one is detected,
+this builder will generate the correct
+project file
+.RI ( .vcproj
+or
+.IR .dsp )
+and solution file
+.RI ( .sln
+or
+.IR .dsw ).
+This builder takes a number of additional
+keyword arguments that supply information
+necessary to build the proper project files.
+Examples:
+
+.ES
+# For Visual Studio 7.0 or later (.NET).
+env.MSVSProject(target = 'Foo.vcproj',
+ slnguid = '{SLNGUID}',
+ srcs = ['foo.cpp'],
+ incs = ['sdk.h'],
+ localincs = ['foo.h'],
+ resources = ['foo.rc'],
+ misc = ['readme.txt'],
+ buildtarget = 'Foo.exe',
+ variant = 'Release')
+
+# For earlier Visual Studio versions.
+env.MSVSProject(target = 'Foo.dsp',
+ srcs = ['foo.cpp'],
+ incs = ['sdk.h'],
+ localincs = ['foo.h'],
+ resources = ['foo.rc'],
+ misc = ['readme.txt'],
+ buildtarget = 'Foo.exe',
+ variant = 'Release')
+.EE
+
.IP RES
Builds a Microsoft Visual C++ resource file.
This builder is only provided
@@ -2646,6 +2690,28 @@ General options passed to the linker.
.IP LINKCOM
The command line used to link object files into an executable.
+.IP MSVSPROJECTCOM
+The action used to generate Microsoft Visual Studio
+project and solution files.
+
+.IP MSVSPROJECTSUFFIX
+The suffix used for Microsoft Visual Studio project (DSP) files.
+The default value is
+.B .vcproj
+when using Visual Studio version 7.x (.NET),
+and
+.B .dsp
+when using earlier versions of Visual Studio.
+
+.IP MSVSSOLUTIONSUFFIX
+The suffix used for Microsoft Visual Studio solution (DSW) files.
+The default value is
+.B .sln
+when using Visual Studio version 7.x (.NET),
+and
+.B .dsw
+when using earlier versions of Visual Studio.
+
.IP no_import_lib
When set to non-zero,
suppresses creation of a corresponding Win32 static import lib by the
diff --git a/runtest.py b/runtest.py
index b2176e9..049643a 100644
--- a/runtest.py
+++ b/runtest.py
@@ -309,6 +309,7 @@ elif scons_lib_dir:
if scons_exec:
os.environ['SCONS_EXEC'] = '1'
+os.environ['SCONS_SCRIPT_DIR'] = scons_script_dir
os.environ['SCONS_CWD'] = cwd
os.environ['SCONS_VERSION'] = version
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 1222d44..dd976ef 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -39,6 +39,16 @@ RELEASE 0.15 - XXX
- Fix use of the SConf subsystem with SConscriptChdir().
+ From Greg Spencer
+
+ - Check for the existence of MS Visual Studio on disk before using it,
+ to avoid getting fooled by leftover junk in the registry.
+
+ - Add support for MSVC++ .NET.
+
+ - Add support for MS Visual Studio project files (DSP, DSW,
+ SLN and VCPROJ files).
+
RELEASE 0.14 - Wed, 21 May 2003 05:16:32 -0500
diff --git a/src/RELEASE.txt b/src/RELEASE.txt
index 6d7916c..467633c 100644
--- a/src/RELEASE.txt
+++ b/src/RELEASE.txt
@@ -27,7 +27,12 @@ RELEASE 0.15 - XXX
Please note the following important changes since release 0.14:
- -
+ - SCons now tries to verify that Microsoft Visual Studio (including
+ Visual C++) is actually installed before using it, by checking that
+ the program directory exists. If SCons cannot find your copy of
+ Visual Studio, it is probably because it installed itself itself in
+ a default directory that we have not seen before. If this is the
+ case, please let us know so that we can update future versions.
Please note the following important changes since release 0.13:
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 65d6886..f1987e7 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -76,6 +76,7 @@ SCons/Tool/mingw.py
SCons/Tool/mslib.py
SCons/Tool/mslink.py
SCons/Tool/msvc.py
+SCons/Tool/msvs.py
SCons/Tool/nasm.py
SCons/Tool/pdflatex.py
SCons/Tool/pdftex.py
diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py
index ba5e279..0f5cb30 100644
--- a/src/engine/SCons/Environment.py
+++ b/src/engine/SCons/Environment.py
@@ -1,7 +1,12 @@
"""SCons.Environment
-XXX
+Base class for construction Environments. These are
+the primary objects used to communicate dependency and
+construction information to the build engine.
+Keyword arguments supplied when the construction Environment
+is created are construction variables used to initialize the
+Environment
"""
#
@@ -33,6 +38,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import copy
import os
import os.path
+import string
import re
import shutil
from UserDict import UserDict
@@ -271,6 +277,45 @@ class Environment:
else:
self._dict[key] = kw[key] + self._dict[key]
+ def PrependENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
+ """Prepend path elements to the path 'name' in the 'ENV'
+ dictionary for this environment. Will only add any particular
+ path once, and will normpath and normcase all paths to help
+ assure this. This can also handle the case where the env
+ variable is a list instead of a string.
+ """
+
+ orig = ''
+ if self._dict.has_key(envname) and self._dict[envname].has_key(name):
+ orig = self._dict[envname][name]
+
+ nv = SCons.Util.PrependPath(orig, newpath, sep)
+
+ if not self._dict.has_key(envname):
+ self._dict[envname] = {}
+
+ self._dict[envname][name] = nv
+
+ def AppendENVPath(self, name, newpath, envname = 'ENV', sep = os.pathsep):
+ """Append path elements to the path 'name' in the 'ENV'
+ dictionary for this environment. Will only add any particular
+ path once, and will normpath and normcase all paths to help
+ assure this. This can also handle the case where the env
+ variable is a list instead of a string.
+ """
+
+ orig = ''
+ if self._dict.has_key(envname) and self._dict[envname].has_key(name):
+ orig = self._dict[envname][name]
+
+ nv = SCons.Util.AppendPath(orig, newpath, sep)
+
+ if not self._dict.has_key(envname):
+ self._dict[envname] = {}
+
+ self._dict[envname][name] = nv
+
+
def Depends(self, target, dependency):
"""Explicity specify that 'target's depend on 'dependency'."""
tlist = SCons.Node.arg2nodes(target, self.fs.File)
diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py
index aed3a9e..d8b4f9d 100644
--- a/src/engine/SCons/EnvironmentTests.py
+++ b/src/engine/SCons/EnvironmentTests.py
@@ -474,6 +474,54 @@ class EnvironmentTestCase(unittest.TestCase):
assert hasattr(env4, 'z1')
assert hasattr(env4, 'z2')
+ def test_PrependENVPath(self):
+ """Test prepending to an ENV path."""
+ env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+ MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+ # have to include the pathsep here so that the test will work on UNIX too.
+ env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';')
+ env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
+ env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
+ env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
+ assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+ assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
+ def test_AppendENVPath(self):
+ """Test appending to an ENV path."""
+ env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+ MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+ # have to include the pathsep here so that the test will work on UNIX too.
+ env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
+ env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
+ assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+
+ def test_AppendENVPath(self):
+ """Test prepending to an ENV path."""
+ env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+ MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+ # have to include the pathsep here so that the test will work on UNIX too.
+ env1.PrependENVPath('PATH',r'C:\dir\num\two',sep = ';')
+ env1.PrependENVPath('PATH',r'C:\dir\num\three',sep = ';')
+ env1.PrependENVPath('MYPATH',r'C:\mydir\num\three','MYENV',sep = ';')
+ env1.PrependENVPath('MYPATH',r'C:\mydir\num\one','MYENV',sep = ';')
+ assert(env1['ENV']['PATH'] == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+ assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
+ def test_AppendENVPath(self):
+ """Test appending to an ENV path."""
+ env1 = Environment(ENV = {'PATH': r'C:\dir\num\one;C:\dir\num\two'},
+ MYENV = {'MYPATH': r'C:\mydir\num\one;C:\mydir\num\two'})
+ # have to include the pathsep here so that the test will work on UNIX too.
+ env1.AppendENVPath('PATH',r'C:\dir\num\two', sep = ';')
+ env1.AppendENVPath('PATH',r'C:\dir\num\three', sep = ';')
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\three','MYENV', sep = ';')
+ env1.AppendENVPath('MYPATH',r'C:\mydir\num\one','MYENV', sep = ';')
+ assert(env1['ENV']['PATH'] == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ assert(env1['MYENV']['MYPATH'] == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+
def test_Depends(self):
"""Test the explicit Depends method."""
env = Environment()
diff --git a/src/engine/SCons/Platform/win32.py b/src/engine/SCons/Platform/win32.py
index 6874d01..0803004 100644
--- a/src/engine/SCons/Platform/win32.py
+++ b/src/engine/SCons/Platform/win32.py
@@ -68,11 +68,7 @@ class TempFileMunge:
# a bug in Win32 that will use a forward slash as a path
# delimiter. Win32's link mistakes that for a command line
# switch and barfs.
- #
- # We use the .lnk suffix for the benefit of the Phar Lap
- # linkloc linker, which likes to append an .lnk suffix if
- # none is given.
- tmp = os.path.normpath(tempfile.mktemp('.lnk'))
+ tmp = os.path.normpath(tempfile.mktemp())
native_tmp = SCons.Util.get_native_path(tmp)
# The sh shell will try to escape the backslashes in the
@@ -160,10 +156,18 @@ def spawn(sh, escape, cmd, args, env):
sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
return ret
-# Windows does not allow special characters in file names
-# anyway, so no need for an escape function, we will just quote
-# the arg.
-escape = lambda x: '"' + x + '"'
+# We just quote the arg here, but since the escape for a double
+# quote in the command processor (I hesitate to call it a shell :-) is
+# to double it (i.e. '""' => '"' in the command processor), we have to
+# make sure not to double any double quotes on the ends.
+def escape(x):
+ first = '"'
+ last = '"'
+ if x and x[0] == '"':
+ first = '" '
+ if x and x[-1] == '"':
+ last = ' "'
+ return first + x + last
# Get the windows system directory name
def get_system_root():
@@ -233,10 +237,30 @@ def generate(env):
cmd_interp = os.path.join(val, 'command.com')
except:
pass
+
+ # For the special case of not having access to the registry, we
+ # use a temporary path and pathext to attempt to find the command
+ # interpreter. If we fail, we try to find the interpreter through
+ # the env's PATH. The problem with that is that it might not
+ # contain an ENV and a PATH.
+ if not cmd_interp:
+ systemroot = r'C:\Windows'
+ if os.environ.has_key('SYSTEMROOT'):
+ systemroot = os.environ['SYSTEMROOT']
+ tmp_path = systemroot + os.pathsep + \
+ os.path.join(systemroot,'System32')
+ tmp_pathext = '.com;.exe;.bat;.cmd'
+ if os.environ.has_key('PATHEXT'):
+ tmp_pathext = os.environ['PATHEXT']
+ cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
+ if not cmd_interp:
+ cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
+
if not cmd_interp:
cmd_interp = env.Detect('cmd')
if not cmd_interp:
cmd_interp = env.Detect('command')
+
if not env.has_key('ENV'):
env['ENV'] = {}
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 5258d90..1e14658 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -112,11 +112,16 @@ def compute_exports(exports):
class Frame:
"""A frame on the SConstruct/SConscript call stack"""
- def __init__(self, exports):
+ def __init__(self, exports, sconscript):
self.globals = BuildDefaultGlobals()
self.retval = None
self.prev_dir = SCons.Node.FS.default_fs.getcwd()
self.exports = compute_exports(exports) # exports from the calling SConscript
+ # make sure the sconscript attr is a Node.
+ if isinstance(sconscript, SCons.Node.Node):
+ self.sconscript = sconscript
+ else:
+ self.sconscript = SCons.Node.FS.default_fs.File(str(sconscript))
# the SConstruct/SConscript call stack:
stack = []
@@ -215,7 +220,7 @@ def SConscript(*ls, **kw):
# evaluate each SConscript file
results = []
for fn in files:
- stack.append(Frame(exports))
+ stack.append(Frame(exports,fn))
old_sys_path = sys.path
try:
if fn == "-":
diff --git a/src/engine/SCons/Tool/__init__.py b/src/engine/SCons/Tool/__init__.py
index 7cf9b29..b039460 100644
--- a/src/engine/SCons/Tool/__init__.py
+++ b/src/engine/SCons/Tool/__init__.py
@@ -228,7 +228,7 @@ def tool_list(platform, env):
other_tools = FindAllTools(['BitKeeper', 'CVS',
'dvipdf', 'dvips', 'gs',
'jar', 'javac', 'javah',
- 'latex', 'lex', 'midl',
+ 'latex', 'lex', 'midl', 'msvs',
'pdflatex', 'pdftex', 'Perforce',
'RCS', 'rmic', 'SCCS',
# 'Subversion',
diff --git a/src/engine/SCons/Tool/mslib.py b/src/engine/SCons/Tool/mslib.py
index 4180e05..93a36cc 100644
--- a/src/engine/SCons/Tool/mslib.py
+++ b/src/engine/SCons/Tool/mslib.py
@@ -34,15 +34,32 @@ selection method.
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import SCons.Defaults
+import SCons.Tool.msvs
+import SCons.Tool.msvc
def generate(env):
"""Add Builders and construction variables for lib to an Environment."""
env['BUILDERS']['Library'] = SCons.Defaults.StaticLibrary
env['BUILDERS']['StaticLibrary'] = SCons.Defaults.StaticLibrary
-
+
+ version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+
+ if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+ include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(version)
+ else:
+ include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+
+ # since other tools can set this, we just make sure that the
+ # relevant stuff from MSVS is in there somewhere.
+ env.PrependENVPath('PATH', exe_path)
+
env['AR'] = 'lib'
env['ARFLAGS'] = '/nologo'
env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
def exists(env):
- return env.Detect('lib')
+ if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+ return env.Detect('lib')
+ else:
+ # there's at least one version of MSVS installed.
+ return True
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 8aa6f09..5a8a729 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -40,9 +40,9 @@ import SCons.Action
import SCons.Defaults
import SCons.Errors
import SCons.Util
-import msvc
-
-from SCons.Tool.msvc import get_msdev_paths
+import SCons.Tool.msvs
+import SCons.Tool.msvc
+import SCons.Platform.win32
def pdbGenerator(env, target, source, for_signature):
if target and env.has_key('PDB') and env['PDB']:
@@ -73,7 +73,7 @@ def win32ShlinkSources(target, source, env, for_signature):
return listCmd
def win32LibEmitter(target, source, env):
- msvc.validate_vars(env)
+ SCons.Tool.msvc.validate_vars(env)
dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
no_import_lib = env.get('no_import_lib', 0)
@@ -107,7 +107,7 @@ def win32LibEmitter(target, source, env):
return (target, source)
def prog_emitter(target, source, env):
- msvc.validate_vars(env)
+ SCons.Tool.msvc.validate_vars(env)
if env.has_key('PDB') and env['PDB']:
env.SideEffect(env['PDB'], target)
@@ -159,14 +159,26 @@ def generate(env):
env['WIN32EXPSUFFIX'] = '.exp'
env['REGSVRACTION'] = regServerCheck
- env['REGSVR'] = 'regsvr32'
+ env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
env['REGSVRFLAGS'] = '/s '
env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
- if SCons.Util.can_read_reg:
- include_path, lib_path, exe_path = get_msdev_paths()
- env['ENV']['LIB'] = lib_path
- env['ENV']['PATH'] = exe_path
+ version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+
+ if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+ include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_default_paths(version)
+ else:
+ include_path, lib_path, exe_path = SCons.Tool.msvc.get_msvc_paths(version)
+
+ # since other tools can set these, we just make sure that the
+ # relevant stuff from MSVS is in there somewhere.
+ env.PrependENVPath('INCLUDE', include_path)
+ env.PrependENVPath('LIB', lib_path)
+ env.PrependENVPath('PATH', exe_path)
def exists(env):
- return env.Detect('link')
+ if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+ return env.Detect('link')
+ else:
+ # there's at least one version of MSVS installed.
+ return True
diff --git a/src/engine/SCons/Tool/msvc.py b/src/engine/SCons/Tool/msvc.py
index 6f0c516..f936535 100644
--- a/src/engine/SCons/Tool/msvc.py
+++ b/src/engine/SCons/Tool/msvc.py
@@ -35,59 +35,121 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import os.path
import string
+import types
+import re
import SCons.Action
import SCons.Tool
import SCons.Errors
+import SCons.Warnings
import SCons.Builder
import SCons.Util
import SCons.Platform.win32
+import SCons.Tool.msvs
CSuffixes = ['.c', '.C']
CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
-def get_devstudio_versions():
- """
- Get list of devstudio versions from the Windows registry. Return a
- list of strings containing version numbers; an exception will be raised
- if we were unable to access the registry (eg. couldn't import
- a registry-access module) or the appropriate registry keys weren't
- found.
- """
-
+def _parse_msvc7_overrides(version):
+ """ Parse any overridden defaults for MSVS directory locations in MSVS .NET. """
+
+ # First, we get the shell folder for this user:
if not SCons.Util.can_read_reg:
raise SCons.Errors.InternalError, "No Windows registry module was found"
- K = 'Software\\Microsoft\\Devstudio'
- L = []
- for base in (SCons.Util.HKEY_CLASSES_ROOT,
- SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER,
- SCons.Util.HKEY_USERS):
+ comps = ""
+ try:
+ (comps, t) = SCons.Util.RegGetValue(SCons.Util.HKEY_CURRENT_USER,
+ r'Software\Microsoft\Windows\CurrentVersion' +\
+ r'\Explorer\Shell Folders\Local AppData')
+ except SCons.Util.RegError:
+ raise SCons.Errors.InternalError, "The Local AppData directory was not found in the registry."
+
+ comps = comps + '\\Microsoft\\VisualStudio\\' + version + '\\VSComponents.dat'
+ dirs = {}
+
+ if os.path.exists(comps):
+ # now we parse the directories from this file, if it exists.
+ # We only look for entries after: [VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories],
+ # since this file could contain a number of things...
+ f = open(comps,'r')
+ line = f.readline()
+ found = 0
+ while line:
+ line.strip()
+ if found == 1:
+ (key, val) = line.split('=',1)
+ key = key.replace(' Dirs','')
+ dirs[key.upper()] = val
+ if line.find(r'[VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]') >= 0:
+ found = 1
+ if line == '':
+ found = 0
+ line = f.readline()
+ f.close()
+ else:
+ # since the file didn't exist, we have only the defaults in
+ # the registry to work with.
try:
- k = SCons.Util.RegOpenKeyEx(base,K)
+ K = 'SOFTWARE\\Microsoft\\VisualStudio\\' + version
+ K = K + r'\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories'
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,K)
i = 0
while 1:
try:
- p = SCons.Util.RegEnumKey(k,i)
- if p[0] in '123456789' and p not in L:
- L.append(p)
+ (key,val,t) = SCons.Util.RegEnumValue(k,i)
+ key = key.replace(' Dirs','')
+ dirs[key.upper()] = val
+ i = i + 1
except SCons.Util.RegError:
break
- i = i + 1
except SCons.Util.RegError:
- pass
+ # if we got here, then we didn't find the registry entries:
+ raise SCons.Errors.InternalError, "Unable to find MSVC paths in the registry."
+ return dirs
+
+def _get_msvc7_path(path, version, platform):
+ """
+ Get Visual Studio directories from version 7 (MSVS .NET)
+ (it has a different registry structure than versions before it)
+ """
+ # first, look for a customization of the default values in the
+ # registry: These are sometimes stored in the Local Settings area
+ # for Visual Studio, in a file, so we have to parse it.
+ dirs = _parse_msvc7_overrides(version)
+
+ if dirs.has_key(path):
+ p = dirs[path]
+ else:
+ raise SCons.Errors.InternalError, "Unable to retrieve the %s path from MS VC++."%path
+
+ # collect some useful information for later expansions...
+ paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+
+ # expand the directory path variables that we support. If there
+ # is a variable we don't support, then replace that entry with
+ # "---Unknown Location VSInstallDir---" or something similar, to clue
+ # people in that we didn't find something, and so env expansion doesn't
+ # do weird things with the $(xxx)'s
+ s = re.compile('\$\(([a-zA-Z0-9_]+?)\)')
+
+ def repl(match):
+ key = string.upper(match.group(1))
+ if paths.has_key(key):
+ return paths[key]
+ else:
+ return '---Unknown Location %s---' % match.group()
- if not L:
- raise SCons.Errors.InternalError, "DevStudio was not found."
+ rv = []
+ for entry in p.split(os.pathsep):
+ entry = s.sub(repl,entry)
+ rv.append(entry)
- L.sort()
- L.reverse()
- return L
+ return string.join(rv,os.pathsep)
def get_msvc_path (path, version, platform='x86'):
"""
- Get a list of devstudio directories (include, lib or path). Return
+ Get a list of visualstudio directories (include, lib or path). Return
a string delimited by ';'. An exception will be raised if unable to
access the registry or appropriate registry keys not found.
"""
@@ -95,16 +157,22 @@ def get_msvc_path (path, version, platform='x86'):
if not SCons.Util.can_read_reg:
raise SCons.Errors.InternalError, "No Windows registry module was found"
- if path=='lib':
- path= 'Library'
+ # normalize the case for comparisons (since the registry is case
+ # insensitive)
+ path = string.upper(path)
+
+ if path=='LIB':
+ path= 'LIBRARY'
+
+ if float(version) >= 7.0:
+ return _get_msvc7_path(path, version, platform)
+
path = string.upper(path + ' Dirs')
K = ('Software\\Microsoft\\Devstudio\\%s\\' +
'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
(version,platform)
- for base in (SCons.Util.HKEY_CLASSES_ROOT,
- SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER,
- SCons.Util.HKEY_USERS):
+ for base in (SCons.Util.HKEY_CURRENT_USER,
+ SCons.Util.HKEY_LOCAL_MACHINE):
try:
k = SCons.Util.RegOpenKeyEx(base,K)
i = 0
@@ -120,77 +188,127 @@ def get_msvc_path (path, version, platform='x86'):
pass
# if we got here, then we didn't find the registry entries:
- raise SCons.Errors.InternalError, "%s was not found in the registry."%path
-
-def get_msdev_dir(version):
- """Returns the root directory of the MSDev installation from the
- registry if it can be found, otherwise we guess."""
- if SCons.Util.can_read_reg:
- K = ('Software\\Microsoft\\Devstudio\\%s\\' +
- 'Products\\Microsoft Visual C++') % \
- version
- for base in (SCons.Util.HKEY_LOCAL_MACHINE,
- SCons.Util.HKEY_CURRENT_USER):
- try:
- k = SCons.Util.RegOpenKeyEx(base,K)
- val, tok = SCons.Util.RegQueryValueEx(k, 'ProductDir')
- return os.path.split(val)[0]
- except SCons.Util.RegError:
- pass
-
-def get_msdev_paths(version=None):
+ raise SCons.Errors.InternalError, "The %s path was not found in the registry."%path
+
+def _get_msvc6_default_paths(version):
+ """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+ three environment variables that should be set in order to execute
+ the MSVC 6.0 tools properly, if the information wasn't available
+ from the registry."""
+ MVSdir = None
+ paths = {}
+ exe_path = ''
+ lib_path = ''
+ include_path = ''
+ try:
+ paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+ MVSdir = paths['VSINSTALLDIR']
+ except (SCons.Util.RegError, SCons.Errors.InternalError):
+ if os.environ.has_key('MSDEVDIR'):
+ MVSdir = os.path.normpath(os.path.join(os.environ['MSDEVDIR'],'..','..'))
+ else:
+ MVSdir = r'C:\Program Files\Microsoft Visual Studio'
+ if MVSdir:
+ if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'):
+ MVSVCdir = paths['VCINSTALLDIR']
+ else:
+ MVSVCdir = os.path.join(MVSdir,'VC98')
+
+ MVSCommondir = r'%s\Common' % MVSdir
+ include_path = r'%s\ATL\include;%s\MFC\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
+ lib_path = r'%s\MFC\lib;%s\lib' % (MVSVCdir, MVSVCdir)
+ exe_path = r'%s\MSDev98\bin;%s\bin' % (MVSCommondir, MVSVCdir)
+ return (include_path, lib_path, exe_path)
+
+def _get_msvc7_default_paths(version):
+ """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+ three environment variables that should be set in order to execute
+ the MSVC .NET tools properly, if the information wasn't available
+ from the registry."""
+
+ MVSdir = None
+ paths = {}
+ exe_path = ''
+ lib_path = ''
+ include_path = ''
+ try:
+ paths = SCons.Tool.msvs.get_msvs_install_dirs(version)
+ MVSdir = paths['VSINSTALLDIR']
+ except (KeyError, SCons.Util.RegError, SCons.Errors.InternalError):
+ if os.environ.has_key('VSCOMNTOOLS'):
+ MVSdir = os.path.normpath(os.path.join(os.environ['VSCOMNTOOLS'],'..','..'))
+ else:
+ # last resort -- default install location
+ MVSdir = r'C:\Program Files\Microsoft Visual Studio .NET'
+
+ if not MVSdir:
+ if SCons.Util.can_read_reg and paths.has_key('VCINSTALLDIR'):
+ MVSVCdir = paths['VCINSTALLDIR']
+ else:
+ MVSVCdir = os.path.join(MVSdir,'Vc7')
+
+ MVSCommondir = r'%s\Common7' % MVSdir
+ include_path = r'%s\atlmfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
+ lib_path = r'%s\atlmfc\lib;%s\lib' % (MVSVCdir, MVSVCdir)
+ exe_path = r'%s\Tools\bin;%s\Tools;%s\bin' % (MVSCommondir, MVSCommondir, MVSVCdir)
+ return (include_path, lib_path, exe_path)
+
+def get_msvc_paths(version=None):
"""Return a 3-tuple of (INCLUDE, LIB, PATH) as the values
of those three environment variables that should be set
in order to execute the MSVC tools properly."""
exe_path = ''
lib_path = ''
include_path = ''
+
+ if not version and not SCons.Util.can_read_reg:
+ version = '6.0'
+
try:
if not version:
- version = get_devstudio_versions()[0] #use highest version
+ version = get_visualstudio_versions()[0] #use highest version
+
include_path = get_msvc_path("include", version)
lib_path = get_msvc_path("lib", version)
- exe_path = get_msvc_path("path", version) + ";" + os.environ['PATH']
+ exe_path = get_msvc_path("path", version)
+
except (SCons.Util.RegError, SCons.Errors.InternalError):
- # Could not get the configured directories from the registry.
- # However, the configured directories only appear if the user
- # changes them from the default. Therefore, we'll see if
- # we can get the path to the MSDev base installation from
- # the registry and deduce the default directories.
- MVSdir = None
- if version:
- MVSdir = get_msdev_dir(version)
- if MVSdir:
- MVSVCdir = r'%s\VC98' % MVSdir
- MVSCommondir = r'%s\Common' % MVSdir
- include_path = r'%s\atl\include;%s\mfc\include;%s\include' % (MVSVCdir, MVSVCdir, MVSVCdir)
- lib_path = r'%s\mfc\lib;%s\lib' % (MVSVCdir, MVSVCdir)
- try:
- extra_path = os.pathsep + os.environ['PATH']
- except KeyError:
- extra_path = ''
- exe_path = (r'%s\MSDev98\Bin;%s\Bin' % (MVSCommondir, MVSVCdir)) + extra_path
+ # Could not get all the configured directories from the
+ # registry. However, some of the configured directories only
+ # appear if the user changes them from the default.
+ # Therefore, we'll see if we can get the path to the MSDev
+ # base installation from the registry and deduce the default
+ # directories.
+ if float(version) >= 7.0:
+ return _get_msvc7_default_paths(version)
else:
- # The DevStudio environment variables don't exist,
- # so just use the variables from the source environment.
- progfiles = SCons.Platform.win32.get_program_files_dir()
- MVSdir = os.path.join(progfiles,r'Microsoft Visual Studio')
- MVSVCdir = r'%s\VC98' % MVSdir
- MVSCommondir = r'%s\Common' % MVSdir
- try:
- include_path = os.environ['INCLUDE']
- except KeyError:
- include_path = ''
- try:
- lib_path = os.environ['LIB']
- except KeyError:
- lib_path = ''
- try:
- exe_path = os.environ['PATH']
- except KeyError:
- exe_path = ''
+ return _get_msvc6_default_paths(version)
+
return (include_path, lib_path, exe_path)
+def get_msvc_default_paths(version = None):
+ """Return a 3-tuple of (INCLUDE, LIB, PATH) as the values of those
+ three environment variables that should be set in order to execute
+ the MSVC tools properly. This will only return the default
+ locations for the tools, not the values used by MSVS in their
+ directory setup area. This can help avoid problems with different
+ developers having different settings, and should allow the tools
+ to run in most cases."""
+
+ if not version and not SCons.Util.can_read_reg:
+ version = '6.0'
+
+ try:
+ if not version:
+ version = get_visualstudio_versions()[0] #use highest version
+ except:
+ pass
+
+ if float(version) >= 7.0:
+ return _get_msvc7_default_paths(version)
+ else:
+ return _get_msvc6_default_paths(version)
+
def validate_vars(env):
"""Validate the PDB, PCH, and PCHSTOP construction variables."""
if env.has_key('PCH') and env['PCH']:
@@ -282,10 +400,18 @@ def generate(env):
CScan.add_skey('.rc')
env['BUILDERS']['RES'] = res_builder
- if SCons.Util.can_read_reg:
- include_path, lib_path, exe_path = get_msdev_paths()
- env['ENV']['INCLUDE'] = include_path
- env['ENV']['PATH'] = exe_path
+ version = SCons.Tool.msvs.get_default_visualstudio_version(env)
+
+ if env.has_key('MSVS_IGNORE_IDE_PATHS') and env['MSVS_IGNORE_IDE_PATHS']:
+ include_path, lib_path, exe_path = get_msvc_default_paths(version)
+ else:
+ include_path, lib_path, exe_path = get_msvc_paths(version)
+
+ # since other tools can set these, we just make sure that the
+ # relevant stuff from MSVS is in there somewhere.
+ env.PrependENVPath('INCLUDE', include_path)
+ env.PrependENVPath('LIB', lib_path)
+ env.PrependENVPath('PATH', exe_path)
env['CFILESUFFIX'] = '.c'
env['CXXFILESUFFIX'] = '.cc'
@@ -294,4 +420,8 @@ def generate(env):
env['BUILDERS']['PCH'] = pch_builder
def exists(env):
- return env.Detect('cl')
+ if not SCons.Util.can_read_reg or not SCons.Tool.msvs.get_visualstudio_versions():
+ return env.Detect('cl')
+ else:
+ # there's at least one version of MSVS installed.
+ return True
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
new file mode 100644
index 0000000..9b8eb41
--- /dev/null
+++ b/src/engine/SCons/Tool/msvs.py
@@ -0,0 +1,1030 @@
+"""SCons.Tool.msvs
+
+Tool-specific initialization for Microsoft Visual Studio project files.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import base64
+import md5
+import os.path
+import pickle
+import re
+import string
+import sys
+import types
+
+import SCons.Builder
+import SCons.Node.FS
+import SCons.Platform.win32
+import SCons.Script.SConscript
+import SCons.Util
+import SCons.Warnings
+
+##############################################################################
+# Below here are the classes and functions for generation of
+# DSP/DSW/SLN/VCPROJ files.
+##############################################################################
+
+def _hexdigest(s):
+ """Return a string as a string of hex characters.
+ """
+ # NOTE: This routine is a method in the Python 2.0 interface
+ # of the native md5 module, but we want SCons to operate all
+ # the way back to at least Python 1.5.2, which doesn't have it.
+ h = string.hexdigits
+ r = ''
+ for c in s:
+ i = ord(c)
+ r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
+ return r
+
+def _generateGUID(slnfile, name):
+ """This generates a dummy GUID for the sln file to use. It is
+ based on the MD5 signatures of the sln filename plus the name of
+ the project. It basically just needs to be unique, and not
+ change with each invocation."""
+ solution = _hexdigest(md5.new(str(slnfile)+str(name)).digest()).upper()
+ # convert most of the signature to GUID form (discard the rest)
+ solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:28] + "}"
+ return solution
+
+class Config:
+ pass
+
+class _DSPGenerator:
+ """ Base class for DSP generators """
+ def __init__(self, dspfile, source, env):
+ if type(dspfile) == types.StringType:
+ self.dspfile = os.path.abspath(dspfile)
+ else:
+ self.dspfile = dspfile.get_abspath()
+
+ try:
+ self.conspath = source[0].attributes.sconstruct.get_abspath()
+ except KeyError:
+ raise SCons.Errors.InternalError, \
+ "Unable to determine where the SConstruct is"
+
+ self.config = Config()
+ if env.has_key('variant'):
+ self.config.variant = env['variant'].capitalize()
+ else:
+ raise SCons.Errors.InternalError, \
+ "You must specify a 'variant' argument (i.e. 'Debug' or " +\
+ "'Release') to create an MSVSProject."
+
+ if env.has_key('buildtarget'):
+ if type(env['buildtarget']) == types.StringType:
+ self.config.buildtarget = os.path.abspath(env['buildtarget'])
+ elif type(env['buildtarget']) == types.ListType:
+ self.config.buildtarget = env['buildtarget'][0].get_abspath()
+ else:
+ self.config.buildtarget = env['buildtarget'].get_abspath()
+ else:
+ raise SCons.Errors.InternalError, \
+ "You must specify a target 'buildtarget' file argument (such as the target" +\
+ " executable) to create an MSVSProject."
+
+ self.config.outdir = os.path.dirname(self.config.buildtarget)
+
+ if type(source[0]) == types.StringType:
+ self.source = os.path.abspath(source[0])
+ else:
+ self.source = source[0].get_abspath()
+
+ self.env = env
+
+ if self.env.has_key('name'):
+ self.name = self.env['name']
+ else:
+ self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+
+ print "Adding '" + self.name + ' - ' + self.config.variant + "' to Visual Studio Project '" + str(dspfile) + "'"
+
+ sourcenames = [
+ ' Source Files',
+ 'Header Files',
+ 'Local Headers',
+ 'Resource Files',
+ 'Other Files']
+
+ srcargs = [
+ 'srcs',
+ 'incs',
+ 'localincs',
+ 'resources',
+ 'misc']
+
+ self.sources = {}
+ for n in sourcenames:
+ self.sources[n] = []
+
+ self.configs = {}
+
+ if os.path.exists(self.dspfile):
+ self.Parse()
+
+ for t in zip(sourcenames,srcargs):
+ if self.env.has_key(t[1]):
+ if type(self.env[t[1]]) == types.ListType:
+ for i in self.env[t[1]]:
+ if not i in self.sources[t[0]]:
+ self.sources[t[0]].append(i)
+ else:
+ if not self.env[t[1]] in self.sources[t[0]]:
+ self.sources[t[0]].append(self.env[t[1]])
+
+ for n in sourcenames:
+ self.sources[n].sort()
+
+ self.configs[self.config.variant] = self.config
+
+ def Build(self):
+ pass
+
+class _GenerateV6DSP(_DSPGenerator):
+ """Generates a Project file for MSVS 6.0"""
+
+ def PrintHeader(self):
+ name = self.name
+ # pick a default config
+ confkeys = self.configs.keys()
+ confkeys.sort()
+
+ self.file.write('# Microsoft Developer Studio Project File - Name="%s" - Package Owner=<4>\n'
+ '# Microsoft Developer Studio Generated Build File, Format Version 6.00\n'
+ '# ** DO NOT EDIT **\n\n'
+ '# TARGTYPE "Win32 (x86) External Target" 0x0106\n\n'
+ 'CFG=%s - Win32 %s\n'
+ '!MESSAGE This is not a valid makefile. To build this project using NMAKE,\n'
+ '!MESSAGE use the Export Makefile command and run\n'
+ '!MESSAGE \n'
+ '!MESSAGE NMAKE /f "%s.mak".\n'
+ '!MESSAGE \n'
+ '!MESSAGE You can specify a configuration when running NMAKE\n'
+ '!MESSAGE by defining the macro CFG on the command line. For example:\n'
+ '!MESSAGE \n'
+ '!MESSAGE NMAKE /f "%s.mak" CFG="%s - Win32 %s"\n'
+ '!MESSAGE \n'
+ '!MESSAGE Possible choices for configuration are:\n'
+ '!MESSAGE \n' % (name,name,confkeys[0],name,name,name,confkeys[0]))
+
+ for kind in confkeys:
+ self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind))
+
+ self.file.write('!MESSAGE \n\n')
+
+ def PrintProject(self):
+ name = self.name
+ self.file.write('# Begin Project\n'
+ '# PROP AllowPerConfigDependencies 0\n'
+ '# PROP Scc_ProjName ""\n'
+ '# PROP Scc_LocalPath ""\n\n')
+
+ first = 1
+ confkeys = self.configs.keys()
+ confkeys.sort()
+ for kind in confkeys:
+ outdir = self.configs[kind].outdir
+ buildtarget = self.configs[kind].buildtarget
+ if first == 1:
+ self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
+ first = 0
+ else:
+ self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
+
+ # have to write this twice, once with the BASE settings, and once without
+ for base in ("BASE ",""):
+ self.file.write('# PROP %sUse_MFC 0\n'
+ '# PROP %sUse_Debug_Libraries ' % (base, base))
+ if kind.lower().find('debug') < 0:
+ self.file.write('0\n')
+ else:
+ self.file.write('1\n')
+ self.file.write('# PROP %sOutput_Dir "%s"\n'
+ '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir))
+ (d,c) = os.path.split(str(self.conspath))
+ cmd = '%s %s -C %s -f %s %s' % (sys.executable, os.path.normpath(sys.argv[0]), d, c, buildtarget)
+ self.file.write('# PROP %sCmd_Line "%s"\n'
+ '# PROP %sRebuild_Opt "-c && %s"\n'
+ '# PROP %sTarget_File "%s"\n'
+ '# PROP %sBsc_Name ""\n'
+ '# PROP %sTarget_Dir ""\n'\
+ %(base,cmd,base,cmd,base,buildtarget,base,base))
+
+ self.file.write('\n!ENDIF\n\n'
+ '# Begin Target\n\n')
+ for kind in confkeys:
+ self.file.write('# Name "%s - Win32 %s"\n' % (name,kind))
+ self.file.write('\n')
+ first = 0
+ for kind in confkeys:
+ if first == 0:
+ self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
+ first = 1
+ else:
+ self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
+ self.file.write('!ENDIF \n\n')
+ self.PrintSourceFiles()
+ self.file.write('# End Target\n'
+ '# End Project\n')
+
+ # now we pickle some data and add it to the file -- MSDEV will ignore it.
+ pdata = pickle.dumps(self.configs,True)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '\n')
+ pdata = pickle.dumps(self.sources,True)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '\n')
+
+ def PrintSourceFiles(self):
+ categories = {' Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat',
+ 'Header Files': 'h|hpp|hxx|hm|inl',
+ 'Local Headers': 'h|hpp|hxx|hm|inl',
+ 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe',
+ 'Other Files': ''}
+
+ cats = categories.keys()
+ cats.sort()
+ for kind in cats:
+ if not self.sources[kind]:
+ continue # skip empty groups
+
+ self.file.write('# Begin Group "' + kind + '"\n\n')
+ typelist = categories[kind].replace('|',';')
+ self.file.write('# PROP Default_Filter "' + typelist + '"\n')
+
+ for file in self.sources[kind]:
+ file = os.path.normpath(file)
+ self.file.write('# Begin Source File\n\n'
+ 'SOURCE="' + file + '"\n'
+ '# End Source File\n')
+ self.file.write('# End Group\n')
+
+ # add the Conscript file outside of the groups
+ self.file.write('# Begin Source File\n\n'
+ 'SOURCE="' + str(self.source) + '"\n'
+ '# End Source File\n')
+
+ def Parse(self):
+ try:
+ dspfile = file(self.dspfile,'r')
+ except IOError:
+ return # doesn't exist yet, so can't add anything to configs.
+
+ line = dspfile.readline()
+ while line:
+ if line.find("# End Project") > -1:
+ break
+ line = dspfile.readline()
+
+ line = dspfile.readline()
+ datas = line
+ while line and line != '\n':
+ line = dspfile.readline()
+ datas = datas + line
+
+ # OK, we've found our little pickled cache of data.
+ try:
+ datas = base64.decodestring(datas)
+ data = pickle.loads(datas)
+ except:
+ return # unable to unpickle any data for some reason
+
+ self.configs.update(data)
+
+ data = None
+ line = dspfile.readline()
+ datas = line
+ while line and line != '\n':
+ line = dspfile.readline()
+ datas = datas + line
+
+ # OK, we've found our little pickled cache of data.
+ # it has a "# " in front of it, so we strip that.
+ try:
+ datas = base64.decodestring(datas)
+ data = pickle.loads(datas)
+ except:
+ return # unable to unpickle any data for some reason
+
+ self.sources.update(data)
+
+ def Build(self):
+ try:
+ self.file = file(self.dspfile,'w')
+ except IOError, detail:
+ raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+ else:
+ self.PrintHeader()
+ self.PrintProject()
+ self.file.close()
+
+class _GenerateV7DSP(_DSPGenerator):
+ """Generates a Project file for MSVS .NET"""
+
+ def PrintHeader(self):
+ self.file.write('<?xml version="1.0" encoding = "Windows-1252"?>\n'
+ '<VisualStudioProject\n'
+ ' ProjectType="Visual C++"\n'
+ ' Version="7.00"\n'
+ ' Name="%s"\n'
+ ' SccProjectName=""\n'
+ ' SccLocalPath=""\n'
+ ' Keyword="MakeFileProj">\n'
+ ' <Platforms>\n'
+ ' <Platform\n'
+ ' Name="Win32"/>\n'
+ ' </Platforms>\n' % self.name)
+
+ def PrintProject(self):
+
+
+ self.file.write(' <Configurations>\n')
+
+ first = 1
+ confkeys = self.configs.keys()
+ confkeys.sort()
+ for kind in confkeys:
+ outdir = self.configs[kind].outdir
+ buildtarget = self.configs[kind].buildtarget
+
+ (d,c) = os.path.split(str(self.conspath))
+ cmd = '%s %s -C %s -f %s %s\n' % (sys.executable,\
+ os.path.normpath(sys.argv[0]),\
+ d,c,buildtarget)
+
+ cleancmd = '%s %s -C %s -f %s -c %s' % (sys.executable,\
+ os.path.normpath(sys.argv[0]),\
+ d,c,buildtarget)
+
+ self.file.write(' <Configuration\n'
+ ' Name="%s|Win32"\n'
+ ' OutputDirectory="%s"\n'
+ ' IntermediateDirectory="%s"\n'
+ ' ConfigurationType="0"\n'
+ ' UseOfMFC="0"\n'
+ ' ATLMinimizesCRunTimeLibraryUsage="FALSE">\n'
+ ' <Tool\n'
+ ' Name="VCNMakeTool"\n'
+ ' BuildCommandLine="%s"\n'
+ ' CleanCommandLine="%s"\n'
+ ' RebuildCommandLine="%s"\n'
+ ' Output="%s"/>\n'
+ ' </Configuration>\n' % (kind.capitalize(),outdir,outdir,\
+ cmd,cleancmd,cmd,buildtarget))
+
+ self.file.write(' </Configurations>\n')
+
+ self.PrintSourceFiles()
+
+ self.file.write('</VisualStudioProject>\n')
+
+ # now we pickle some data and add it to the file -- MSDEV will ignore it.
+ pdata = pickle.dumps(self.configs,True)
+ pdata = base64.encodestring(pdata)
+ self.file.write('<!-- SCons Data:\n' + pdata + '\n')
+ pdata = pickle.dumps(self.sources,True)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '-->\n')
+
+ def PrintSourceFiles(self):
+ categories = {' Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
+ 'Header Files': 'h;hpp;hxx;hm;inl',
+ 'Local Headers': 'h;hpp;hxx;hm;inl',
+ 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe',
+ 'Other Files': ''}
+
+ self.file.write(' <Files>\n')
+
+ cats = categories.keys()
+ cats.sort()
+ for kind in cats:
+ if not self.sources[kind]:
+ continue # skip empty groups
+
+ self.file.write(' <Filter\n'
+ ' Name="%s"\n'
+ ' Filter="%s">\n' % (kind, categories[kind]))
+
+ for file in self.sources[kind]:
+ file = os.path.normpath(file)
+ self.file.write(' <File\n'
+ ' RelativePath="%s">\n'
+ ' </File>\n' % file)
+
+ self.file.write(' </Filter>\n')
+
+ # add the Conscript file outside of the groups
+ self.file.write(' <File\n'
+ ' RelativePath="%s">\n'
+ ' </File>\n'
+ ' </Files>\n'
+ ' <Globals>\n'
+ ' </Globals>\n' % str(self.source))
+
+ def Parse(self):
+ try:
+ dspfile = file(self.dspfile,'r')
+ except IOError:
+ return # doesn't exist yet, so can't add anything to configs.
+
+ line = dspfile.readline()
+ while line:
+ if line.find('<!-- SCons Data:') > -1:
+ break
+ line = dspfile.readline()
+
+ line = dspfile.readline()
+ datas = line
+ while line and line != '\n':
+ line = dspfile.readline()
+ datas = datas + line
+
+ # OK, we've found our little pickled cache of data.
+ try:
+ datas = base64.decodestring(datas)
+ data = pickle.loads(datas)
+ except:
+ return # unable to unpickle any data for some reason
+
+ self.configs.update(data)
+
+ data = None
+ line = dspfile.readline()
+ datas = line
+ while line and line != '\n':
+ line = dspfile.readline()
+ datas = datas + line
+
+ # OK, we've found our little pickled cache of data.
+ try:
+ datas = base64.decodestring(datas)
+ data = pickle.loads(datas)
+ except:
+ return # unable to unpickle any data for some reason
+
+ self.sources.update(data)
+
+ def Build(self):
+ try:
+ self.file = file(self.dspfile,'w')
+ except IOError, detail:
+ raise SCons.Errors.InternalError, 'Unable to open "' + self.dspfile + '" for writing:' + str(detail)
+ else:
+ self.PrintHeader()
+ self.PrintProject()
+ self.file.close()
+
+class _DSWGenerator:
+ """ Base class for DSW generators """
+ def __init__(self, dswfile, dspfile, source, env):
+ self.dswfile = os.path.normpath(str(dswfile))
+ self.dspfile = os.path.abspath(str(dspfile))
+ self.env = env
+
+ if self.env.has_key('name'):
+ self.name = self.env['name']
+ else:
+ self.name = os.path.basename(os.path.splitext(self.dspfile)[0])
+
+ def Build(self):
+ pass
+
+class _GenerateV7DSW(_DSWGenerator):
+ """Generates a Solution file for MSVS .NET"""
+ def __init__(self, dswfile, dspfile, source, env):
+ _DSWGenerator.__init__(self, dswfile,dspfile,source,env)
+
+ if env.has_key('slnguid') and env['slnguid']:
+ self.slnguid = env['slnguid']
+ else:
+ self.slnguid = _generateGUID(dswfile, self.name)
+
+ self.config = Config()
+ if env.has_key('variant'):
+ self.config.variant = env['variant'].capitalize()
+ else:
+ raise SCons.Errors.InternalError, \
+ "You must specify a 'variant' argument (i.e. 'Debug' or " +\
+ "'Release') to create an MSVS Solution File."
+
+ self.configs = {}
+
+ if os.path.exists(self.dswfile):
+ self.Parse()
+
+ self.configs[self.config.variant] = self.config
+
+ def Parse(self):
+ try:
+ dswfile = file(self.dswfile,'r')
+ except IOError:
+ return # doesn't exist yet, so can't add anything to configs.
+
+ line = dswfile.readline()
+ while line:
+ if line[:9] == "EndGlobal":
+ break
+ line = dswfile.readline()
+
+ line = dswfile.readline()
+ datas = line
+ while line:
+ line = dswfile.readline()
+ datas = datas + line
+
+ # OK, we've found our little pickled cache of data.
+ try:
+ datas = base64.decodestring(datas)
+ data = pickle.loads(datas)
+ except:
+ return # unable to unpickle any data for some reason
+
+ self.configs.update(data)
+
+ def PrintSolution(self):
+ """Writes a solution file"""
+ self.file.write('Microsoft Visual Studio Solution File, Format Version 7.00\n'
+ # the next line has the GUID for an external makefile project.
+ 'Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "%s", "%s", "%s"\n'
+ 'EndProject\n'
+ 'Global\n'
+ ' GlobalSection(SolutionConfiguration) = preSolution\n'\
+ % (self.name, os.path.basename(self.dspfile), self.slnguid))
+ confkeys = self.configs.keys()
+ confkeys.sort()
+ cnt = 0
+ for name in confkeys:
+ self.file.write(' ConfigName.%d = %s\n' % (cnt, name.capitalize()))
+ cnt = cnt + 1
+ self.file.write(' EndGlobalSection\n'
+ ' GlobalSection(ProjectDependencies) = postSolution\n'
+ ' EndGlobalSection\n'
+ ' GlobalSection(ProjectConfiguration) = postSolution\n')
+ for name in confkeys:
+ name = name.capitalize()
+ self.file.write(' %s.%s.ActiveCfg = %s|Win32\n'
+ ' %s.%s.Build.0 = %s|Win32\n' %(self.slnguid,name,name,self.slnguid,name,name))
+ self.file.write(' EndGlobalSection\n'
+ ' GlobalSection(ExtensibilityGlobals) = postSolution\n'
+ ' EndGlobalSection\n'
+ ' GlobalSection(ExtensibilityAddIns) = postSolution\n'
+ ' EndGlobalSection\n'
+ 'EndGlobal\n')
+ pdata = pickle.dumps(self.configs,True)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '\n')
+
+ def Build(self):
+ try:
+ self.file = file(self.dswfile,'w')
+ except IOError, detail:
+ raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+ else:
+ self.PrintSolution()
+ self.file.close()
+
+class _GenerateV6DSW(_DSWGenerator):
+ """Generates a Workspace file for MSVS 6.0"""
+
+ def PrintWorkspace(self):
+ """ writes a DSW file """
+ self.file.write('Microsoft Developer Studio Workspace File, Format Version 6.00\n'
+ '# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\n'
+ '\n'
+ '###############################################################################\n'
+ '\n'
+ 'Project: "%s"="%s" - Package Owner=<4>\n'
+ '\n'
+ 'Package=<5>\n'
+ '{{{\n'
+ '}}}\n'
+ '\n'
+ 'Package=<4>\n'
+ '{{{\n'
+ '}}}\n'
+ '\n'
+ '###############################################################################\n'
+ '\n'
+ 'Global:\n'
+ '\n'
+ 'Package=<5>\n'
+ '{{{\n'
+ '}}}\n'
+ '\n'
+ 'Package=<3>\n'
+ '{{{\n'
+ '}}}\n'
+ '\n'
+ '###############################################################################\n'\
+ %(self.name,self.dspfile))
+
+ def Build(self):
+ try:
+ self.file = file(self.dswfile,'w')
+ except IOError, detail:
+ raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
+ else:
+ self.PrintWorkspace()
+ self.file.close()
+
+
+def GenerateDSP(dspfile, source, env):
+ """Generates a Project file based on the version of MSVS that is being used"""
+
+ if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+ g = _GenerateV7DSP(dspfile, source, env)
+ g.Build()
+ else:
+ g = _GenerateV6DSP(dspfile, source, env)
+ g.Build()
+
+def GenerateDSW(dswfile, dspfile, source, env):
+ """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
+
+ if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+ g = _GenerateV7DSW(dswfile, dspfile, source, env)
+ g.Build()
+ else:
+ g = _GenerateV6DSW(dswfile, dspfile, source, env)
+ g.Build()
+
+
+##############################################################################
+# Above here are the classes and functions for generation of
+# DSP/DSW/SLN/VCPROJ files.
+##############################################################################
+
+def get_default_visualstudio_version(env):
+ """Returns the version set in the env, or the latest version
+ installed, if it can find it, or '6.0' if all else fails. Also
+ updated the environment with what it found."""
+
+ version = '6.0'
+ versions = [version]
+ if not env.has_key('MSVS') or type(env['MSVS']) != types.DictType:
+ env['MSVS'] = {}
+
+ if env.has_key('MSVS_VERSION'):
+ version = env['MSVS_VERSION']
+ versions = [version]
+ else:
+ if SCons.Util.can_read_reg:
+ versions = get_visualstudio_versions()
+ version = versions[0] #use highest version by default
+
+ env['MSVS_VERSION'] = version
+ env['MSVS']['VERSIONS'] = versions
+ env['MSVS']['VERSION'] = version
+
+ return version
+
+def get_visualstudio_versions():
+ """
+ Get list of visualstudio versions from the Windows registry. Return a
+ list of strings containing version numbers; an exception will be raised
+ if we were unable to access the registry (eg. couldn't import
+ a registry-access module) or the appropriate registry keys weren't
+ found.
+ """
+
+ if not SCons.Util.can_read_reg:
+ raise SCons.Errors.InternalError, "No Windows registry module was found"
+
+ HLM = SCons.Util.HKEY_LOCAL_MACHINE
+ K = r'Software\Microsoft\VisualStudio'
+ L = []
+ try:
+ k = SCons.Util.RegOpenKeyEx(HLM, K)
+ i = 0
+ while 1:
+ try:
+ p = SCons.Util.RegEnumKey(k,i)
+ except SCons.Util.RegError:
+ break
+ i = i + 1
+ if not p[0] in '123456789' or p in L:
+ continue
+ # Only add this version number if there is a valid
+ # registry structure (includes the "Setup" key),
+ # and at least some of the correct directories
+ # exist. Sometimes VS uninstall leaves around
+ # some registry/filesystem turds that we don't
+ # want to trip over. Also, some valid registry
+ # entries are MSDN entries, not MSVS ('7.1',
+ # notably), and we want to skip those too.
+ try:
+ tst = SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p + '\\Setup')
+ except SCons.Util.RegError:
+ continue
+
+ id = []
+ idk = SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p)
+ # This is not always here -- it only exists if the
+ # user installed into a non-standard location (at
+ # least in VS6 it works that way -- VS7 seems to
+ # always write it)
+ try:
+ id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
+ except SCons.Util.RegError:
+ pass
+
+ # If the InstallDir key doesn't exist,
+ # then we check the default locations.
+ if not id or not id[0]:
+ files_dir = SCons.Platform.win32.get_program_files_dir()
+ if float(p) < 7.0:
+ vs = r'Microsoft Visual Studio\Common\MSDev98'
+ else:
+ vs = r'Microsoft Visual Studio .NET\Common7\IDE'
+ id = [ os.path.join(files_dir, vs) ]
+ if os.path.exists(id[0]):
+ L.append(p)
+ except SCons.Util.RegError:
+ pass
+
+ if not L:
+ raise SCons.Errors.InternalError, "Microsoft Visual Studio was not found."
+
+ L.sort()
+ L.reverse()
+
+ return L
+
+def get_msvs_install_dirs(version = None):
+ """
+ Get installed locations for various msvc-related products, like the .NET SDK
+ and the Platform SDK.
+ """
+
+ if not SCons.Util.can_read_reg:
+ raise SCons.Errors.InternalError, "No Windows registry module was found"
+
+ if not version:
+ version = get_visualstudio_versions()[0] #use highest version by default
+
+ K = 'Software\\Microsoft\\VisualStudio\\' + version
+
+ # vc++ install dir
+ rv = {}
+ try:
+ if (float(version) < 7.0):
+ (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ K + r'\Setup\Microsoft Visual C++\ProductDir')
+ else:
+ (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ K + r'\Setup\VC\ProductDir')
+ except SCons.Util.RegError:
+ pass
+
+ # visual studio install dir
+ if (float(version) < 7.0):
+ try:
+ (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ K + r'\Setup\Microsoft Visual Studio\ProductDir')
+ except SCons.Util.RegError:
+ pass
+
+ if not rv.has_key('VSINSTALLDIR') or not rv['VSINSTALLDIR']:
+ if rv.has_key('VCINSTALLDIR') and rv['VCINSTALLDIR']:
+ rv['VSINSTALLDIR'] = os.path.dirname(rv['VCINSTALLDIR'])
+ else:
+ rv['VSINSTALLDIR'] = os.path.join(SCons.Platform.win32.get_program_files_dir(),'Microsoft Visual Studio')
+ else:
+ try:
+ (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ K + r'\Setup\VS\ProductDir')
+ except SCons.Util.RegError:
+ pass
+
+ # .NET framework install dir
+ try:
+ (rv['FRAMEWORKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ r'Software\Microsoft\.NETFramework\InstallRoot')
+ except SCons.Util.RegError:
+ pass
+
+ if rv.has_key('FRAMEWORKDIR'):
+ # try and enumerate the installed versions of the .NET framework.
+ contents = os.listdir(rv['FRAMEWORKDIR'])
+ l = re.compile('v[0-9]+.*')
+ versions = []
+ for entry in contents:
+ if l.match(entry):
+ versions.append(entry)
+
+ def versrt(a,b):
+ # since version numbers aren't really floats...
+ aa = a[1:]
+ bb = b[1:]
+ aal = aa.split('.')
+ bbl = bb.split('.')
+ c = int(bbl[0]) - int(aal[0])
+ if c == 0:
+ c = int(bbl[1]) - int(aal[1])
+ if c == 0:
+ c = int(bbl[2]) - int(aal[2])
+ return c
+
+ versions.sort(versrt)
+
+ rv['FRAMEWORKVERSIONS'] = versions
+ # assume that the highest version is the latest version installed
+ rv['FRAMEWORKVERSION'] = versions[0]
+
+ # .NET framework SDK install dir
+ try:
+ (rv['FRAMEWORKSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ r'Software\Microsoft\.NETFramework\sdkInstallRoot')
+ except SCons.Util.RegError:
+ pass
+
+ # MS Platform SDK dir
+ try:
+ (rv['PLATFORMSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
+ r'Software\Microsoft\MicrosoftSDK\Directories\Install Dir')
+ except SCons.Util.RegError:
+ pass
+
+ if rv.has_key('PLATFORMSDKDIR'):
+ # if we have a platform SDK, try and get some info on it.
+ vers = {}
+ try:
+ loc = r'Software\Microsoft\MicrosoftSDK\InstalledSDKs'
+ k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,loc)
+ i = 0
+ while 1:
+ try:
+ key = SCons.Util.RegEnumKey(k,i)
+ sdk = SCons.Util.RegOpenKeyEx(k,key)
+ j = 0
+ name = ''
+ date = ''
+ version = ''
+ while 1:
+ try:
+ (vk,vv,t) = SCons.Util.RegEnumValue(sdk,j)
+ if vk.lower() == 'keyword':
+ name = vv
+ if vk.lower() == 'propagation_date':
+ date = vv
+ if vk.lower() == 'version':
+ version = vv
+ j = j + 1
+ except SCons.Util.RegError:
+ break
+ if name:
+ vers[name] = (date, version)
+ i = i + 1
+ except SCons.Util.RegError:
+ break
+ rv['PLATFORMSDK_MODULES'] = vers
+ except SCons.Util.RegError:
+ pass
+
+ return rv;
+
+def GenerateProject(target, source, env):
+ # generate the dsp file, according to the version of MSVS.
+ builddspfile = target[0]
+ builddswfile = target[1]
+ dswfile = builddswfile.srcnode()
+ dspfile = builddspfile.srcnode()
+
+# print "SConscript :",str(source[0])
+# print "DSW file :",dswfile
+# print "DSP file :",dspfile
+# print "Build DSW file:",builddswfile
+# print "Build DSP file:",builddspfile
+
+ # this detects whether or not we're using a BuildDir
+ if os.path.abspath(os.path.normcase(str(dspfile))) != \
+ os.path.abspath(os.path.normcase(str(builddspfile))):
+ try:
+ bdsp = file(str(builddspfile), "w+")
+ except IOError, detail:
+ print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
+ raise
+
+ bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
+
+ try:
+ bdsw = file(str(builddswfile), "w+")
+ except IOError, detail:
+ print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
+ raise
+
+ bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
+
+ GenerateDSP(dspfile, source, env)
+ GenerateDSW(dswfile, dspfile, source, env)
+
+def projectEmitter(target, source, env):
+ """Sets up the DSP and DSW dependencies for an SConscript file."""
+
+ if source[0] == target[0]:
+ source = []
+
+ # make sure the suffix is correct for the version of MSVS we're running.
+ (base, suff) = os.path.splitext(str(target[0]))
+ suff = env['MSVSPROJECTSUFFIX']
+ target[0] = base + suff
+
+ dspfile = SCons.Node.FS.default_fs.File(target[0]).srcnode()
+ dswfile = SCons.Node.FS.default_fs.File(os.path.splitext(str(dspfile))[0] + env['MSVSSOLUTIONSUFFIX'])
+
+ if not source:
+ source = [SCons.Script.SConscript.stack[-1].sconscript.srcnode()]
+
+ source[0].attributes.sconstruct = SCons.Script.SConscript.stack[0].sconscript
+
+ bdswpath = os.path.splitext(str(target[0]))[0] + env['MSVSSOLUTIONSUFFIX']
+ bdswfile = SCons.Node.FS.default_fs.File(bdswpath)
+
+ # only make these side effects if they're
+ # not the same file.
+ if os.path.abspath(os.path.normcase(str(dspfile))) != \
+ os.path.abspath(os.path.normcase(str(target[0]))):
+ env.SideEffect(dspfile, target[0])
+ env.Precious(dspfile)
+ # dswfile isn't precious -- it can be blown away and rewritten each time.
+ env.SideEffect(dswfile, target[0])
+
+ return ([target[0],bdswfile], source)
+
+projectGeneratorAction = SCons.Action.Action(GenerateProject, None)
+
+projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM',
+ suffix = '$MSVSPROJECTSUFFIX',
+ emitter = projectEmitter)
+
+def generate(env):
+ """Add Builders and construction variables for Microsoft Visual
+ Studio project files to an Environment."""
+ try:
+ bld = env['BUILDERS']['MSVSProject']
+ except KeyError:
+ env['BUILDERS']['MSVSProject'] = projectBuilder
+
+ env['MSVSPROJECTCOM'] = projectGeneratorAction
+
+ version = get_default_visualstudio_version(env)
+
+ # keep a record of some of the MSVS info so the user can use it.
+ try:
+ dirs = get_msvs_install_dirs(version)
+ env['MSVS'].update(dirs)
+ except (SCons.Util.RegError, SCons.Errors.InternalError):
+ # we don't care if we can't do this -- if we can't, it's
+ # because we don't have access to the registry, or because the
+ # tools aren't installed. In either case, the user will have to
+ # find them on their own.
+ pass
+
+ if (float(env['MSVS_VERSION']) < 7.0):
+ env['MSVSPROJECTSUFFIX'] = '.dsp'
+ env['MSVSSOLUTIONSUFFIX'] = '.dsw'
+ else:
+ env['MSVSPROJECTSUFFIX'] = '.vcproj'
+ env['MSVSSOLUTIONSUFFIX'] = '.sln'
+
+def exists(env):
+ if not SCons.Util.can_read_reg or not get_visualstudio_versions():
+ if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
+ return env.Detect('devenv')
+ else:
+ return env.Detect('msdev')
+ else:
+ # there's at least one version of MSVS installed.
+ return True
+
diff --git a/src/engine/SCons/Tool/msvsTests.py b/src/engine/SCons/Tool/msvsTests.py
new file mode 100644
index 0000000..731cc2d
--- /dev/null
+++ b/src/engine/SCons/Tool/msvsTests.py
@@ -0,0 +1,476 @@
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import string
+import sys
+import TestCmd
+import unittest
+
+from SCons.Tool.msvs import *
+import SCons.Util
+import SCons.Warnings
+
+regdata_6a = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\ServicePacks]
+"sp3"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup]
+"VsCommonDir"="C:\Program Files\Microsoft Visual Studio\Common"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Developer Network Library - Visual Studio 6.0a]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio\MSDN98\98VSa\1033"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio\VC98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+regdata_6b = string.split(r'''[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0]
+"InstallDir"="C:\VS6\Common\IDE\IDE98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\ServicePacks]
+"sp5"=""
+"latest"=dword:00000005
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup]
+"VsCommonDir"="C:\VS6\Common"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Basic]
+"ProductDir"="C:\VS6\VB98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++]
+"ProductDir"="C:\VS6\VC98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio]
+"ProductDir"="C:\VS6"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft VSEE Client]
+"ProductDir"="C:\VS6\Common\Tools"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Visual Studio 98]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+regdata_7 = string.split(r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0]
+"InstallDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"Source Directories"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\crt\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\mfc\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\atl\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\CrystalReports]
+@="#15007"
+"Package"="{F05E92C6-8346-11D3-B4AD-00A0C9B04E7B}"
+"ProductDetails"="#15009"
+"LogoID"="0"
+"PID"="#15008"
+"UseInterface"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual Basic.NET]
+@=""
+"DefaultProductAttribute"="VB"
+"Package"="{164B10B9-B200-11D0-8C61-00A0C91E29D5}"
+"UseInterface"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual C#]
+@=""
+"Package"="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}"
+"UseInterface"=dword:00000001
+"DefaultProductAttribute"="C#"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\VisualC++]
+"UseInterface"=dword:00000001
+"Package"="{F1C25864-3097-11D2-A5C5-00C04F7968B4}"
+"DefaultProductAttribute"="VC"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup]
+"Dbghelp_path"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"dw_dir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\MSDN]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Msdn\1033\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Servicing\SKU]
+"Visual Studio .NET Professional - English"="{D0610409-7D65-11D5-A54F-0090278A1BB8}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VB]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vb7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC#]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\VC#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Visual Studio .NET Professional - English]
+"InstallSuccess"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS]
+"EnvironmentDirectory"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"EnvironmentPath"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
+"VS7EnvironmentLocation"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
+"MSMDir"="C:\Program Files\Common Files\Merge Modules\"
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
+"VS7CommonBinDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\Tools\"
+"VS7CommonDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\"
+"VSUpdateDir"="C:\Program Files\Microsoft Visual Studio .NET\Setup\VSUpdate\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\BuildNumber]
+"1033"="7.0.9466"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\Pro]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32]
+@="{A54AAE91-30C2-11D3-87BF-A04A4CC10000}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]
+"Path Dirs"="$(VCInstallDir)bin;$(VSInstallDir)Common7\Tools\bin\prerelease;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;C:\Program Files\HTML Help Workshop\;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);C:\perl\bin;C:\cygwin\bin;c:\cygwin\usr\bin;C:\bin;C:\program files\perforce;C:\cygwin\usr\local\bin\i686-pc-cygwin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem"
+"Library Dirs"="$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)PlatformSDK\lib\prerelease;$(VCInstallDir)PlatformSDK\lib;$(FrameworkSDKDir)lib"
+"Include Dirs"="$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include\prerelease;$(VCInstallDir)PlatformSDK\include;$(FrameworkSDKDir)include"
+"Source Dirs"="$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src"
+"Reference Dirs"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+regdata_67 = string.split(r'''
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0]
+"InstallDir"="C:\VS6\Common\IDE\IDE98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\ServicePacks]
+"sp5"=""
+"latest"=dword:00000005
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup]
+"VsCommonDir"="C:\VS6\Common"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Basic]
+"ProductDir"="C:\VS6\VB98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++]
+"ProductDir"="C:\VS6\VC98"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio]
+"ProductDir"="C:\VS6"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Microsoft VSEE Client]
+"ProductDir"="C:\VS6\Common\Tools"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\6.0\Setup\Visual Studio 98]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0]
+"InstallDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"Source Directories"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\crt\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\mfc\;C:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\src\atl\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\CrystalReports]
+@="#15007"
+"Package"="{F05E92C6-8346-11D3-B4AD-00A0C9B04E7B}"
+"ProductDetails"="#15009"
+"LogoID"="0"
+"PID"="#15008"
+"UseInterface"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual Basic.NET]
+@=""
+"DefaultProductAttribute"="VB"
+"Package"="{164B10B9-B200-11D0-8C61-00A0C91E29D5}"
+"UseInterface"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\Visual C#]
+@=""
+"Package"="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}"
+"UseInterface"=dword:00000001
+"DefaultProductAttribute"="C#"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\InstalledProducts\VisualC++]
+"UseInterface"=dword:00000001
+"Package"="{F1C25864-3097-11D2-A5C5-00C04F7968B4}"
+"DefaultProductAttribute"="VC"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup]
+"Dbghelp_path"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"dw_dir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\MSDN]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Msdn\1033\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Servicing\SKU]
+"Visual Studio .NET Professional - English"="{D0610409-7D65-11D5-A54F-0090278A1BB8}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VB]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vb7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\Vc7\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VC#]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\VC#\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\Visual Studio .NET Professional - English]
+"InstallSuccess"=dword:00000001
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS]
+"EnvironmentDirectory"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\"
+"EnvironmentPath"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
+"VS7EnvironmentLocation"="C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\devenv.exe"
+"MSMDir"="C:\Program Files\Common Files\Merge Modules\"
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
+"VS7CommonBinDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\Tools\"
+"VS7CommonDir"="C:\Program Files\Microsoft Visual Studio .NET\Common7\"
+"VSUpdateDir"="C:\Program Files\Microsoft Visual Studio .NET\Setup\VSUpdate\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\BuildNumber]
+"1033"="7.0.9466"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\Setup\VS\Pro]
+"ProductDir"="C:\Program Files\Microsoft Visual Studio .NET\"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO]
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32]
+@="{A54AAE91-30C2-11D3-87BF-A04A4CC10000}"
+[HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories]
+"Path Dirs"="$(VCInstallDir)bin;$(VSInstallDir)Common7\Tools\bin\prerelease;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;C:\Program Files\HTML Help Workshop\;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);C:\perl\bin;C:\cygwin\bin;c:\cygwin\usr\bin;C:\bin;C:\program files\perforce;C:\cygwin\usr\local\bin\i686-pc-cygwin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem"
+"Library Dirs"="$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)PlatformSDK\lib\prerelease;$(VCInstallDir)PlatformSDK\lib;$(FrameworkSDKDir)lib"
+"Include Dirs"="$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include\prerelease;$(VCInstallDir)PlatformSDK\include;$(FrameworkSDKDir)include"
+"Source Dirs"="$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src"
+"Reference Dirs"=""
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion]
+"ProgramFilesDir"="C:\Program Files"
+"CommonFilesDir"="C:\Program Files\Common Files"
+"MediaPath"="C:\WINDOWS\Media"
+''','\n')
+
+
+class DummyEnv:
+ def __init__(self, dict=None):
+ if dict:
+ self.dict = dict
+ else:
+ self.dict = {}
+
+ def Dictionary(self, key = None):
+ if not key:
+ return self.dict
+ return self.dict[key]
+
+ def __setitem__(self,key,value):
+ self.dict[key] = value
+
+ def __getitem__(self,key):
+ return self.dict[key]
+
+ def has_key(self,name):
+ return self.dict.has_key(name)
+
+class RegKey:
+ """key class for storing an 'open' registry key"""
+ def __init__(self,key):
+ self.key = key
+
+class RegNode:
+ """node in the dummy registry"""
+ def __init__(self,name):
+ self.valdict = {}
+ self.keydict = {}
+ self.keyarray = []
+ self.valarray = []
+ self.name = name
+
+ def value(self,val):
+ if self.valdict.has_key(val):
+ return (self.valdict[val],1)
+ else:
+ raise SCons.Util.RegError
+
+ def addValue(self,name,val):
+ self.valdict[name] = val
+ self.valarray.append(name)
+
+ def valindex(self,index):
+ rv = None
+ try:
+ rv = (self.valarray[index],self.valdict[self.valarray[index]],1)
+ except KeyError:
+ raise SCons.Util.RegError
+ return rv
+
+ def key(self,key,sep = '\\'):
+ if key.find(sep) != -1:
+ keyname, subkeys = key.split(sep,1)
+ else:
+ keyname = key
+ subkeys = ""
+ try:
+ # recurse, and return the lowest level key node
+ if subkeys:
+ return self.keydict[keyname].key(subkeys)
+ else:
+ return self.keydict[keyname]
+ except KeyError:
+ raise SCons.Util.RegError
+
+ def addKey(self,name,sep = '\\'):
+ if name.find(sep) != -1:
+ keyname, subkeys = name.split(sep,1)
+ else:
+ keyname = name
+ subkeys = ""
+
+ if not self.keydict.has_key(keyname):
+ self.keydict[keyname] = RegNode(keyname)
+ self.keyarray.append(keyname)
+
+ # recurse, and return the lowest level key node
+ if subkeys:
+ return self.keydict[keyname].addKey(subkeys)
+ else:
+ return self.keydict[keyname]
+
+ def keyindex(self,index):
+ return self.keydict[self.keyarray[index]]
+
+ def __str__(self):
+ return self._doStr()
+
+ def _doStr(self, indent = ''):
+ rv = ""
+ for value in self.valarray:
+ rv = rv + '%s"%s" = "%s"\n' % (indent, value, self.valdict[value])
+ for key in self.keyarray:
+ rv = rv + "%s%s: {\n"%(indent, key)
+ rv = rv + self.keydict[key]._doStr(indent + ' ')
+ rv = rv + indent + '}\n'
+ return rv
+
+class DummyRegistry:
+ """registry class for storing fake registry attributes"""
+ def __init__(self,data):
+ """parse input data into the fake registry"""
+ self.root = RegNode('REGISTRY')
+ self.root.addKey('HKEY_LOCAL_MACHINE')
+ self.root.addKey('HKEY_CURRENT_USER')
+ self.root.addKey('HKEY_USERS')
+ self.root.addKey('HKEY_CLASSES_ROOT')
+
+ self.parse(data)
+
+ def parse(self, data):
+ parent = self.root
+ keymatch = re.compile('^\[(.*)\]$')
+ valmatch = re.compile('^(?:"(.*)"|[@])="(.*)"$')
+ for line in data:
+ m1 = keymatch.match(line)
+ if m1:
+ # add a key, set it to current parent
+ parent = self.root.addKey(m1.group(1))
+ else:
+ m2 = valmatch.match(line)
+ if m2:
+ parent.addValue(m2.group(1),m2.group(2))
+
+ def OpenKeyEx(self,root,key):
+ if root == SCons.Util.HKEY_CLASSES_ROOT:
+ mykey = 'HKEY_CLASSES_ROOT\\' + key
+ if root == SCons.Util.HKEY_USERS:
+ mykey = 'HKEY_USERS\\' + key
+ if root == SCons.Util.HKEY_CURRENT_USER:
+ mykey = 'HKEY_CURRENT_USER\\' + key
+ if root == SCons.Util.HKEY_LOCAL_MACHINE:
+ mykey = 'HKEY_LOCAL_MACHINE\\' + key
+ #print "Open Key",mykey
+ return self.root.key(mykey)
+
+def DummyOpenKeyEx(root, key):
+ return registry.OpenKeyEx(root,key)
+
+def DummyEnumKey(key, index):
+ rv = None
+ try:
+ rv = key.keyarray[index]
+ except IndexError:
+ raise SCons.Util.RegError
+# print "Enum Key",key.name,"[",index,"] =>",rv
+ return rv
+
+def DummyEnumValue(key, index):
+ rv = key.valindex(index)
+# print "Enum Value",key.name,"[",index,"] =>",rv
+ return rv
+
+def DummyQueryValue(key, value):
+ rv = key.value(value)
+# print "Query Value",key.name+"\\"+value,"=>",rv
+ return rv
+
+def DummyExists(path):
+ return True
+
+class msvsTestCase(unittest.TestCase):
+ def test_get_default_visual_studio_version(self):
+ """Test retrieval of the default visual studio version"""
+ env = DummyEnv()
+ v1 = get_default_visualstudio_version(env)
+ assert env['MSVS_VERSION'] == default_version
+ assert env['MSVS']['VERSION'] == default_version
+ assert v1 == default_version
+
+ env = DummyEnv({'MSVS_VERSION':'7.0'})
+ v2 = get_default_visualstudio_version(env)
+ assert env['MSVS_VERSION'] == '7.0'
+ assert env['MSVS']['VERSION'] == '7.0'
+ assert v2 == '7.0'
+
+ def test_get_visual_studio_versions(self):
+ """Test retrieval of the list of visual studio versions"""
+ v1 = get_visualstudio_versions()
+ assert v1[0] == highest_version
+ assert len(v1) == number_of_versions
+
+ def test_get_msvs_install_dirs(self):
+ """Test retrieval of the list of visual studio installed locations"""
+ v1 = get_msvs_install_dirs()
+ v2 = get_msvs_install_dirs('7.0')
+ assert v1 == install_location1
+ assert v2 == install_location2
+
+if __name__ == "__main__":
+
+ # only makes sense to test this on win32
+ if sys.platform != 'win32':
+ sys.exit(0)
+
+ SCons.Util.RegOpenKeyEx = DummyOpenKeyEx
+ SCons.Util.RegEnumKey = DummyEnumKey
+ SCons.Util.RegEnumValue = DummyEnumValue
+ SCons.Util.RegQueryValueEx = DummyQueryValue
+ os.path.exists = DummyExists # make sure all files exist :-)
+
+ # try it for each possible setup.
+ suite = unittest.makeSuite(msvsTestCase, 'test_')
+ registry = DummyRegistry(regdata_6a)
+ default_version = '6.0'
+ highest_version = '6.0'
+ number_of_versions = 1
+ install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio\\VC98'}
+ install_location2 = {}
+ # print str(registry.root)
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
+
+ registry = DummyRegistry(regdata_6b)
+ default_version = '6.0'
+ highest_version = '6.0'
+ number_of_versions = 1
+ install_location1 = {'VSINSTALLDIR': 'C:\\VS6', 'VCINSTALLDIR': 'C:\\VS6\\VC98'}
+ install_location2 = {}
+ # print str(registry.root)
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
+
+ registry = DummyRegistry(regdata_67)
+ default_version = '7.0'
+ highest_version = '7.0'
+ number_of_versions = 2
+ install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
+ install_location2 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
+ # print str(registry.root)
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
+
+ registry = DummyRegistry(regdata_7)
+ default_version = '7.0'
+ highest_version = '7.0'
+ number_of_versions = 1
+ install_location1 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
+ install_location2 = {'VSINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\', 'VCINSTALLDIR': 'C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\'}
+ # print str(registry.root)
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
diff --git a/src/engine/SCons/Util.py b/src/engine/SCons/Util.py
index 2ebe0d9..06a3dac 100644
--- a/src/engine/SCons/Util.py
+++ b/src/engine/SCons/Util.py
@@ -737,6 +737,16 @@ if can_read_reg:
HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
HKEY_USERS = hkey_mod.HKEY_USERS
+ def RegGetValue(root, key):
+ """Returns a value in the registry without
+ having to open the key first."""
+ # I would use os.path.split here, but it's not a filesystem
+ # path...
+ p = key.rfind('\\') + 1
+ keyp = key[:p]
+ val = key[p:]
+ k = SCons.Util.RegOpenKeyEx(root, keyp)
+ return SCons.Util.RegQueryValueEx(k,val)
if sys.platform == 'win32':
@@ -803,6 +813,84 @@ else:
return os.path.normpath(f)
return None
+def PrependPath(oldpath, newpath, sep = os.pathsep):
+ """Prepend newpath elements to the given oldpath. Will only add
+ any particular path once (leaving the first one it encounters and
+ ignoring the rest, to preserve path order), and will normpath and
+ normcase all paths to help assure this. This can also handle the
+ case where the given oldpath variable is a list instead of a
+ string, in which case a list will be returned instead of a string.
+ """
+
+ orig = oldpath
+ is_list = 1
+ paths = orig
+ if not SCons.Util.is_List(orig):
+ paths = string.split(paths, sep)
+ is_list = 0
+
+ if SCons.Util.is_List(newpath):
+ newpaths = newpath
+ else:
+ newpaths = string.split(newpath, sep)
+
+ newpaths = newpaths + paths # prepend new paths
+
+ normpaths = []
+ paths = []
+ # now we add them only of they are unique
+ for path in newpaths:
+ normpath = os.path.normpath(os.path.normcase(path))
+ if path and not normpath in normpaths:
+ paths.append(path)
+ normpaths.append(normpath)
+
+ if is_list:
+ return paths
+ else:
+ return string.join(paths, sep)
+
+def AppendPath(oldpath, newpath, sep = os.pathsep):
+ """Append newpath elements to the given oldpath. Will only add
+ any particular path once (leaving the first one it encounters and
+ ignoring the rest, to preserve path order), and will normpath and
+ normcase all paths to help assure this. This can also handle the
+ case where the given oldpath variable is a list instead of a
+ string, in which case a list will be returned instead of a string.
+ """
+
+ orig = oldpath
+ is_list = 1
+ paths = orig
+ if not SCons.Util.is_List(orig):
+ paths = string.split(paths, sep)
+ is_list = 0
+
+ if SCons.Util.is_List(newpath):
+ newpaths = newpath
+ else:
+ newpaths = string.split(newpath, sep)
+
+ newpaths = paths + newpaths # append new paths
+ newpaths.reverse()
+
+ normpaths = []
+ paths = []
+ # now we add them only of they are unique
+ for path in newpaths:
+ normpath = os.path.normpath(os.path.normcase(path))
+ if path and not normpath in normpaths:
+ paths.append(path)
+ normpaths.append(normpath)
+
+ paths.reverse()
+
+ if is_list:
+ return paths
+ else:
+ return string.join(paths, sep)
+
+
def ParseConfig(env, command, function=None):
"""Use the specified function to parse the output of the command in order
to modify the specified environment. The 'command' can be a string or a
diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py
index 7f5f166..b7b41be 100644
--- a/src/engine/SCons/UtilTests.py
+++ b/src/engine/SCons/UtilTests.py
@@ -815,6 +815,30 @@ class UtilTestCase(unittest.TestCase):
SOURCES.sort()
assert SOURCES == ['rstr-s4', 's3'], d['SOURCES']
+ def test_PrependPath(self):
+ """Test prepending to a path"""
+ p1 = r'C:\dir\num\one;C:\dir\num\two'
+ p2 = r'C:\mydir\num\one;C:\mydir\num\two'
+ # have to include the pathsep here so that the test will work on UNIX too.
+ p1 = PrependPath(p1,r'C:\dir\num\two',sep = ';')
+ p1 = PrependPath(p1,r'C:\dir\num\three',sep = ';')
+ p2 = PrependPath(p2,r'C:\mydir\num\three',sep = ';')
+ p2 = PrependPath(p2,r'C:\mydir\num\one',sep = ';')
+ assert(p1 == r'C:\dir\num\three;C:\dir\num\two;C:\dir\num\one')
+ assert(p2 == r'C:\mydir\num\one;C:\mydir\num\three;C:\mydir\num\two')
+
+ def test_AppendPath(self):
+ """Test appending to a path."""
+ p1 = r'C:\dir\num\one;C:\dir\num\two'
+ p2 = r'C:\mydir\num\one;C:\mydir\num\two'
+ # have to include the pathsep here so that the test will work on UNIX too.
+ p1 = AppendPath(p1,r'C:\dir\num\two',sep = ';')
+ p1 = AppendPath(p1,r'C:\dir\num\three',sep = ';')
+ p2 = AppendPath(p2,r'C:\mydir\num\three',sep = ';')
+ p2 = AppendPath(p2,r'C:\mydir\num\one',sep = ';')
+ assert(p1 == r'C:\dir\num\one;C:\dir\num\two;C:\dir\num\three')
+ assert(p2 == r'C:\mydir\num\two;C:\mydir\num\three;C:\mydir\num\one')
+
def test_NodeList(self):
"""Test NodeList class"""
class TestClass:
diff --git a/test/import.py b/test/import.py
index d66658b..8dc3682 100644
--- a/test/import.py
+++ b/test/import.py
@@ -45,38 +45,61 @@ x = SCons.Platform.%s.generate
tools = [
# Can't import '386asm' directly due to initial '3' syntax error...
+ 'aixcc',
+ 'aixf77',
+ 'aixlink',
'ar',
'as',
+ 'BitKeeper',
'cc',
+ 'CVS',
'default',
'dvipdf',
'dvips',
+ 'f77',
+ # Can't import 'g++' directly due to '+' syntax error...
'g77',
'gas',
'gcc',
'gnulink',
- # Can't import 'g++' directly due to '+' syntax error...
+ 'gs',
+ 'hpcc',
+ 'hplink',
'icc',
'ifl',
'ilink',
+ 'jar',
+ 'javac',
+ 'javah',
'latex',
'lex',
'link',
# Can't import 'linkloc' everywhere due to Windows registry dependency...
'masm',
+ 'midl',
'mingw',
'mslib',
'mslink',
'msvc',
+ 'msvs',
'nasm',
'pdflatex',
'pdftex',
+ 'Perforce',
+ 'RCS',
+ 'rmic',
+ 'SCCS',
'sgiar',
'sgicc',
'sgilink',
+ 'sunar',
+ 'suncc',
+ 'sunlink',
+ 'Subversion',
'tar',
'tex',
'yacc',
+ 'zip',
]
for tool in tools:
diff --git a/test/midl.py b/test/midl.py
index 59fba57..2e48db2 100644
--- a/test/midl.py
+++ b/test/midl.py
@@ -63,7 +63,7 @@ local = env.Copy(WIN32_INSERT_DEF = 1)
barsrc = [
'BarObject.cpp',
'bar.cpp',
- local.RES('bar.rc', RCFLAGS= '/I\"${SOURCE.srcdir}\"'),
+ local.RES('bar.rc', RCFLAGS= '/I${SOURCE.srcdir}'),
]
local.TypeLibrary('bar.idl')
diff --git a/test/msvs.py b/test/msvs.py
new file mode 100644
index 0000000..03f08cb
--- /dev/null
+++ b/test/msvs.py
@@ -0,0 +1,415 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+import sys
+import re
+import os.path
+import os
+import TestCmd
+import time
+
+expected_dspfile = '''\
+# Microsoft Developer Studio Project File - Name="Test" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=Test - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Test.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Test.mak" CFG="Test - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Test - Win32 Release" (based on "Win32 (x86) External Target")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "Test - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "<WORKPATH>"
+# PROP BASE Intermediate_Dir "<WORKPATH>"
+# PROP BASE Cmd_Line "<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
+# PROP BASE Rebuild_Opt "-c && <PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
+# PROP BASE Target_File "<WORKPATH>\Test.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "<WORKPATH>"
+# PROP Intermediate_Dir "<WORKPATH>"
+# PROP Cmd_Line "<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
+# PROP Rebuild_Opt "-c && <PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
+# PROP Target_File "<WORKPATH>\Test.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "Test - Win32 Release"
+
+!IF "$(CFG)" == "Test - Win32 Release"
+
+!ENDIF
+
+# Begin Group " Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;l;y;def;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="test.cpp"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE="sdk.h"
+# End Source File
+# End Group
+# Begin Group "Local Headers"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE="test.h"
+# End Source File
+# End Group
+# Begin Group "Other Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE="readme.txt"
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE="test.rc"
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE="<WORKPATH>\SConstruct"
+# End Source File
+# End Target
+# End Project
+'''
+
+expected_dswfile = '''\
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Test"="<WORKPATH>\Test.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+'''
+
+expected_slnfile = '''\
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcproj", "{SLNGUID}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {SLNGUID}.Release.ActiveCfg = Release|Win32
+ {SLNGUID}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
+'''
+
+expected_vcprojfile = '''\
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="Test"
+ SccProjectName=""
+ SccLocalPath=""
+ Keyword="MakeFileProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="<WORKPATH>"
+ IntermediateDirectory="<WORKPATH>"
+ ConfigurationType="0"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe
+"
+ CleanCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe"
+ RebuildCommandLine="<PYTHON> <SCONS> -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe
+"
+ Output="<WORKPATH>\Test.exe"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name=" Source Files"
+ Filter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
+ <File
+ RelativePath="test.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="sdk.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Local Headers"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="test.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Other Files"
+ Filter="">
+ <File
+ RelativePath="readme.txt">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe">
+ <File
+ RelativePath="test.rc">
+ </File>
+ </Filter>
+ <File
+ RelativePath="<WORKPATH>\SConstruct">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
+'''
+
+test = TestSCons.TestSCons(match = TestCmd.match_re)
+
+if sys.platform != 'win32':
+ test.pass_test()
+
+####
+# Determine which environments are installed on the test machine.
+test.write('SConstruct','''
+env = Environment()
+
+f = open('versions','w')
+f.write('versions = ' + str(env['MSVS']['VERSIONS']))
+f.close()
+''')
+
+test.run()
+versions = []
+execfile(test.workpath('versions'))
+
+#####
+# Test v6.0 output
+
+if '6.0' in versions:
+ test.write('SConstruct','''
+env=Environment(MSVS_VERSION = '6.0')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+env.MSVSProject(target = 'Test.dsp',
+ srcs = testsrc,
+ incs = testincs,
+ localincs = testlocalincs,
+ resources = testresources,
+ misc = testmisc,
+ buildtarget = 'Test.exe',
+ variant = 'Release')
+ ''')
+
+ test.run(arguments="Test.dsp")
+
+ test.fail_test(not os.path.exists(test.workpath('Test.dsp')))
+ test.fail_test(not os.path.exists(test.workpath('Test.dsw')))
+
+ # check to see that we got what we expected:
+ expected_dspfile = expected_dspfile.replace(r'<WORKPATH>',test.workpath())
+ expected_dspfile = expected_dspfile.replace(r'<PYTHON>',sys.executable)
+ expected_dspfile = expected_dspfile.replace(r'<SCONS>',os.path.join(os.environ['SCONS_SCRIPT_DIR'],'scons.py'))
+ expected_dswfile = expected_dswfile.replace(r'<WORKPATH>',test.workpath())
+
+ f = open(test.workpath('Test.dsp'))
+ dsp = f.read()
+ f.close()
+
+ # don't compare the pickled data
+ assert dsp[:len(expected_dspfile)] == expected_dspfile
+
+ f = open(test.workpath('Test.dsw'))
+ dsw = f.read()
+ f.close()
+ assert dsw == expected_dswfile
+
+ test.run(arguments='-c .')
+
+ test.fail_test(os.path.exists(test.workpath('Test.dsp')))
+ test.fail_test(os.path.exists(test.workpath('Test.dsw')))
+
+ test.run(arguments='Test.dsp')
+
+ test.fail_test(not os.path.exists(test.workpath('Test.dsp')))
+ test.fail_test(not os.path.exists(test.workpath('Test.dsw')))
+
+ test.run(arguments='-c Test.dsw')
+
+ test.fail_test(os.path.exists(test.workpath('Test.dsp')))
+ test.fail_test(os.path.exists(test.workpath('Test.dsw')))
+
+#####
+# Test .NET output
+
+if '7.0' in versions:
+ test.write('SConstruct','''
+env=Environment(MSVS_VERSION = '7.0')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+env.MSVSProject(target = 'Test.vcproj',
+ slnguid = '{SLNGUID}',
+ srcs = testsrc,
+ incs = testincs,
+ localincs = testlocalincs,
+ resources = testresources,
+ misc = testmisc,
+ buildtarget = 'Test.exe',
+ variant = 'Release')
+ ''')
+
+ test.run(arguments="Test.vcproj")
+
+ test.fail_test(not os.path.exists(test.workpath('Test.vcproj')))
+ test.fail_test(not os.path.exists(test.workpath('Test.sln')))
+
+ f = open(test.workpath('Test.vcproj'))
+ vcproj = f.read()
+ f.close()
+ expected_vcprojfile = expected_vcprojfile.replace(r'<WORKPATH>',test.workpath())
+ expected_vcprojfile = expected_vcprojfile.replace(r'<PYTHON>',sys.executable)
+ expected_vcprojfile = expected_vcprojfile.replace(r'<SCONS>',os.path.join(os.environ['SCONS_SCRIPT_DIR'],'scons.py'))
+
+ # don't compare the pickled data
+ assert vcproj[:len(expected_vcprojfile)] == expected_vcprojfile
+
+ f = open(test.workpath('Test.sln'))
+ sln = f.read()
+ f.close()
+
+ assert sln[:len(expected_slnfile)] == expected_slnfile
+
+ test.run(arguments='-c .')
+
+ test.fail_test(os.path.exists(test.workpath('Test.vcproj')))
+ test.fail_test(os.path.exists(test.workpath('Test.sln')))
+
+ test.run(arguments='Test.vcproj')
+
+ test.fail_test(not os.path.exists(test.workpath('Test.vcproj')))
+ test.fail_test(not os.path.exists(test.workpath('Test.sln')))
+
+ test.run(arguments='-c Test.sln')
+
+ test.fail_test(os.path.exists(test.workpath('Test.vcproj')))
+ test.fail_test(os.path.exists(test.workpath('Test.sln')))
+
+test.pass_test()
+
+
+
+
+