summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/restore.sh4
-rw-r--r--doc/man/scons.1239
-rw-r--r--src/CHANGES.txt5
-rw-r--r--src/engine/SCons/Tool/msvs.py666
-rw-r--r--src/engine/SCons/Tool/msvs.xml251
-rw-r--r--test/MSVS/vs-6.0-files.py123
-rw-r--r--test/MSVS/vs-7.0-files.py115
-rw-r--r--test/MSVS/vs-7.1-files.py115
8 files changed, 1177 insertions, 341 deletions
diff --git a/bin/restore.sh b/bin/restore.sh
index d5dc6c1..d23d1d0 100644
--- a/bin/restore.sh
+++ b/bin/restore.sh
@@ -14,7 +14,7 @@ fi
for i in `find $DIRS -name '*.py'`; do
ed $i <<EOF
/^__revision__ = /s/= .*/= "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"/p
-/Copyright (c) 2001.*SCons Foundation/s/.*/__COPYRIGHT__/p
+/Copyright (c) 2001.*SCons Foundation.*/s//__COPYRIGHT__/p
w
q
EOF
@@ -23,7 +23,7 @@ done
for i in `find $DIRS -name '*.txt'`; do
ed $i <<EOF
/# [^ ]* 0.96.[CD][0-9]* [0-9\/]* [0-9:]* knight$/s/.*/# __FILE__ __REVISION__ __DATE__ __DEVELOPER__/p
-/Copyright (c) 2001.*SCons Foundation/s/.*/__COPYRIGHT__/p
+/Copyright (c) 2001.*SCons Foundation.*/s//__COPYRIGHT__/p
w
q
EOF
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index a0b4694..d8fe258 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -31,7 +31,7 @@
.fi
.RE
..
-.TH SCONS 1 "January 2005"
+.TH SCONS 1 "October 2005"
.SH NAME
scons \- a software construction tool
.SH SYNOPSIS
@@ -1739,55 +1739,101 @@ env.Moc('foo.cpp') # generates foo.moc
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.IP MSVSProject()
.IP env.MSVSProject()
-Builds Microsoft Visual Studio project files.
+Builds a Microsoft Visual Studio project file,
+and by default builds a solution file as well.
+
This builds a Visual Studio project file, based on the version of
Visual Studio that is configured (either the latest installed version,
-or the version set by
+or the version specified by
.B MSVS_VERSION
-in the Environment constructor).
-For VS 6, it will generate
+in the construction environment).
+For Visual Studio 6, it will generate a
.B .dsp
-and
-.B .dsw
-files, for VS 7, it will
-generate
+file.
+For Visual Studio 7 (.NET), it will
+generate a
.B .vcproj
-and
+file.
+
+By default,
+this also generates a solution file
+for the specified project,
+a
+.B .dsw
+file for Visual Studio 6
+or a
.B .sln
-files.
+file for Visual Studio 7 (.NET).
+This behavior may be disabled by specifying
+.B auto_build_solution=0
+when you call
+.BR MSVSProject (),
+in which case you presumably want to
+build the solution file(s)
+by calling the
+.BR MSVSSolution ()
+Builder (see below).
It takes several lists of filenames to be placed into the project
-file, currently these are limited to
-.B srcs, incs, localincs, resources,
+file.
+These are currently limited to
+.BR srcs ,
+.BR incs ,
+.BR localincs ,
+.BR resources ,
and
-.B misc.
-These are pretty self explanatory, but it
-should be noted that the 'srcs' list is NOT added to the $SOURCES
-environment variable. This is because it represents a list of files
-to be added to the project file, not the source used to build the
-project file (in this case, the 'source' is the SConscript file used
-to call MSVSProject).
-
-In addition to these values (which are all optional, although not
-specifying any of them results in an empty project file), the
-following values must be specified:
-
-target: The name of the target .dsp or .vcproj file. The correct
-suffix for the version of Visual Studio must be used, but the value
-
-env['MSVSPROJECTSUFFIX']
-
+.BR misc .
+These are pretty self-explanatory, but it should be noted that these
+lists are added to the $SOURCES construction variable as strings,
+NOT as SCons File Nodes. This is because they represent file
+names to be added to the project file, not the source files used to
+build the project file.
+
+In addition to the above lists of values (which are all optional,
+although not specifying any of them results in an empty project file),
+the following values may be specified:
+
+.BR target :
+The name of the target
+.B .dsp
+or
+.B .vcproj
+file.
+The correct
+suffix for the version of Visual Studio must be used, but the
+.B env['MSVSPROJECTSUFFIX']
+construction variable
will be defined to the correct value (see example below).
-variant: The name of this particular variant. These are typically
-things like "Debug" or "Release", but really can be anything you want.
-Multiple calls to MSVSProject with different variants are allowed: all
-variants will be added to the project file with their appropriate
+.BR variant :
+The name of this particular variant.
+For Visual Studio 7 projects,
+this can also be a list of variant names.
+These are typically things like "Debug" or "Release", but really
+can be anything you want.
+For Visual Studio 7 projects,
+they may also specify a target platform
+separated from the variant name by a
+.B |
+(vertical pipe)
+character:
+.BR Debug|Xbox .
+The default target platform is Win32.
+Multiple calls to
+.BR MSVSProject ()
+with different variants are allowed;
+all variants will be added to the project file with their appropriate
build targets and sources.
-buildtarget: A list of SCons.Node.FS objects which is returned from
-the command which builds the target. This is used to tell SCons what
-to build when the 'build' button is pressed inside of the IDE.
+.BR buildtarget :
+An optional string, node, or list of strings or nodes
+(one per build variant), to tell the Visual Studio debugger
+what output target to use in what build variant.
+The number of
+.B buildtarget
+entries must match the number of
+.B variant
+entries.
Example Usage:
@@ -1812,6 +1858,59 @@ Example Usage:
.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.IP MSVSSolution()
+.IP env.MSVSSolution()
+Builds a Microsoft Visual Studio solution file.
+
+This builds a Visual Studio solution file,
+based on the version of Visual Studio that is configured
+(either the latest installed version,
+or the version specified by
+.B MSVS_VERSION
+in the construction environment).
+For Visual Studio 6, it will generate a
+.B .dsw
+file.
+For Visual Studio 7 (.NET), it will
+generate a
+.B .sln
+file.
+
+The following values must be specified:
+
+.BR target :
+The name of the target .dsw or .sln file. The correct
+suffix for the version of Visual Studio must be used, but the value
+.B env['MSVSSOLUTIONSUFFIX']
+will be defined to the correct value (see example below).
+
+.BR variant :
+The name of this particular variant, or a list of variant
+names (the latter is only supported for MSVS 7 solutions). These are
+typically things like "Debug" or "Release", but really can be anything
+you want. For MSVS 7 they may also specify target platform, like this
+"Debug|Xbox". Default platform is Win32.
+
+.BR projects :
+A list of project file names, or Project nodes returned by calls to the
+.BR MSVSProject ()
+Builder,
+to be placed into the solution file.
+(NOTE: Currently only one project is supported per solution.)
+It should be noted that these file names are NOT added to the $SOURCES
+environment variable in form of files, but rather as strings. This
+is because they represent file names to be added to the solution file,
+not the source files used to build the solution file.
+
+Example Usage:
+
+.ES
+ local.MSVSSolution(target = 'Bar' + env['MSVSSOLUTIONSUFFIX'],
+ projects = ['bar' + env['MSVSPROJECTSUFFIX']],
+ variant = 'Release')
+.EE
+
+'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.IP Object()
.IP env.Object()
A synonym for the
@@ -6448,17 +6547,36 @@ environment variables are set explictly.
Sets the preferred version of MSVS to use.
SCons will (by default) select the latest version of MSVS
-installed on your machine. So, if you have version 6 and version 7
-(MSVS .NET) installed, it will prefer version 7. You can override this by
+installed on your machine.
+So, if you have version 6 and version 7 (MSVS .NET) installed,
+it will prefer version 7.
+You can override this by
specifying the
.B MSVS_VERSION
variable in the Environment initialization, setting it to the
appropriate version ('6.0' or '7.0', for example).
If the given version isn't installed, tool initialization will fail.
+.IP MSVSBUILDCOM
+The build command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with any specified
+build targets.
+
+.IP MSVSCLEANCOM
+The clean command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with the -c option
+to remove any specified targets.
+
+.IP MSVSENCODING
+The encoding string placed in
+a generated Microsoft Visual Studio project file.
+The default is encoding
+.BR Windows-1252 .
+
.IP MSVSPROJECTCOM
-The action used to generate Microsoft Visual Studio
-project and solution files.
+The action used to generate Microsoft Visual Studio project files.
.IP MSVSPROJECTSUFFIX
The suffix used for Microsoft Visual Studio project (DSP) files.
@@ -6469,6 +6587,45 @@ and
.B .dsp
when using earlier versions of Visual Studio.
+.IP MSVSREBUILDCOM
+The rebuild command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with any specified
+rebuild targets.
+
+.IP MSVSSCONS
+The SCons used in generated Microsoft Visual Studio project files.
+The default is the version of SCons being
+used to generate the project file.
+
+.IP MSVSSCONSFLAGS
+The SCons flags used in generated Microsoft Visual Studio
+project files.
+
+.IP MSVSSCONSCOM
+The default SCons command used in generated Microsoft Visual Studio
+project files.
+
+.IP MSVSSCONSCRIPT
+The sconscript file
+(that is,
+.B SConstruct
+or
+.B SConscript
+file)
+that will be invoked by Visual Studio
+project files
+(through the
+.B MSVSSCONSCOM
+variable).
+The default is the same sconscript file
+that contains the call to
+.BR MSVSProject ()
+to build the project file.
+
+.IP MSVSSOLUTIONCOM
+The action used to generate Microsoft Visual Studio solution files.
+
.IP MSVSSOLUTIONSUFFIX
The suffix used for Microsoft Visual Studio solution (DSW) files.
The default value is
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 68d1b48..0d1cf5f 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -46,6 +46,11 @@ RELEASE 0.97 - XXX
- Allow SConscript files to modify BUILD_TARGETS.
+ - Add a separate MSVSSolution() Builder, with support for the
+ following new construction variables: $MSVSBUILDCOM, $MSVSCLEANCOM,
+ $MSVSENCODING, $MSVSREBUILDCOM, $MSVSSCONS, $MSVSSCONSCOM,
+ $MSVSSCONSFLAGS, $MSVSSCONSCRIPT and $MSVSSOLUTIONCOM.
+
From Timothee Besset:
- Add support for Objective C/C++ .m and .mm file suffixes (for
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index fb4f1b3..280c456 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -40,12 +40,11 @@ import pickle
import re
import string
import sys
-import types
import SCons.Builder
import SCons.Node.FS
import SCons.Platform.win32
-import SCons.Script
+import SCons.Script.SConscript
import SCons.Util
import SCons.Warnings
@@ -86,7 +85,6 @@ def _generateGUID(slnfile, name):
# the MSVS Project file invoke SCons the same way that scons.bat does,
# which works regardless of how we were invoked.
exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-__VERSION__'), join(sys.prefix, 'scons-__VERSION__'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()"
-exec_script_main_xml = string.replace(exec_script_main, "'", "&apos;")
# The string for the Python executable we tell the Project file to use
# is either sys.executable or, if an external PYTHON_ROOT environment
@@ -97,52 +95,109 @@ try:
except KeyError:
python_executable = sys.executable
else:
- python_executable = os.path.join('$(PYTHON_ROOT)',
+ python_executable = os.path.join('$$(PYTHON_ROOT)',
os.path.split(sys.executable)[1])
class Config:
pass
+def splitFully(path):
+ dir, base = os.path.split(path)
+ if dir and dir != '' and dir != path:
+ return splitFully(dir)+[base]
+ if base == '':
+ return []
+ return [base]
+
+def makeHierarchy(sources):
+ '''Break a list of files into a hierarchy; for each value, if it is a string,
+ then it is a file. If it is a dictionary, it is a folder. The string is
+ the original path of the file.'''
+
+ hierarchy = {}
+ for file in sources:
+ path = splitFully(file)
+ if len(path):
+ dict = hierarchy
+ for part in path[:-1]:
+ if not dict.has_key(part):
+ dict[part] = {}
+ dict = dict[part]
+ dict[path[-1]] = file
+ #else:
+ # print 'Warning: failed to decompose path for '+str(file)
+ return hierarchy
+
class _DSPGenerator:
""" Base class for DSP generators """
+
+ srcargs = [
+ 'srcs',
+ 'incs',
+ 'localincs',
+ 'resources',
+ 'misc']
+
def __init__(self, dspfile, source, env):
- if type(dspfile) == types.StringType:
+ if SCons.Util.is_String(dspfile):
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:
+ if not env.has_key('variant'):
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()
+ elif SCons.Util.is_String(env['variant']):
+ variants = [env['variant']]
+ elif SCons.Util.is_List(env['variant']):
+ variants = env['variant']
+
+ if not env.has_key('buildtarget') or env['buildtarget'] == None:
+ buildtarget = ['']
+ elif SCons.Util.is_String(env['buildtarget']):
+ buildtarget = [env['buildtarget']]
+ elif SCons.Util.is_List(env['buildtarget']):
+ if len(env['buildtarget']) != len(variants):
+ raise SCons.Errors.InternalError, \
+ "Sizes of 'buildtarget' and 'variant' lists must be the same."
+ buildtarget = []
+ for bt in env['buildtarget']:
+ if SCons.Util.is_String(bt):
+ buildtarget.append(bt)
+ else:
+ buildtarget.append(bt.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])
+ buildtarget = [env['buildtarget'].get_abspath()]
+ if len(buildtarget) == 1:
+ bt = buildtarget[0]
+ buildtarget = []
+ for v in variants:
+ buildtarget.append(bt)
+
+ if not env.has_key('outdir') or env['outdir'] == None:
+ outdir = ['']
+ elif SCons.Util.is_String(env['outdir']):
+ outdir = [env['outdir']]
+ elif SCons.Util.is_List(env['outdir']):
+ if len(env['outdir']) != len(variants):
+ raise SCons.Errors.InternalError, \
+ "Sizes of 'outdir' and 'variant' lists must be the same."
+ outdir = []
+ for s in env['outdir']:
+ if SCons.Util.is_String(s):
+ outdir.append(s)
+ else:
+ outdir.append(s.get_abspath())
else:
- self.source = source[0].get_abspath()
+ outdir = [env['outdir'].get_abspath()]
+ if len(outdir) == 1:
+ s = outdir[0]
+ outdir = []
+ for v in variants:
+ outdir.append(s)
+
+ self.sconscript = env['MSVSSCONSCRIPT']
self.env = env
@@ -151,34 +206,29 @@ class _DSPGenerator:
else:
self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
- print "Adding '" + self.name + ' - ' + self.config.variant + "' to Visual Studio Project '" + str(dspfile) + "'"
-
sourcenames = [
- ' Source Files',
+ '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.nokeep = 0
+ if env.has_key('nokeep') and env['variant'] != 0:
+ self.nokeep = 1
+
+ if self.nokeep == 0 and os.path.exists(self.dspfile):
self.Parse()
- for t in zip(sourcenames,srcargs):
+ for t in zip(sourcenames,self.srcargs):
if self.env.has_key(t[1]):
- if type(self.env[t[1]]) == types.ListType:
+ if SCons.Util.is_List(self.env[t[1]]):
for i in self.env[t[1]]:
if not i in self.sources[t[0]]:
self.sources[t[0]].append(i)
@@ -187,9 +237,32 @@ class _DSPGenerator:
self.sources[t[0]].append(self.env[t[1]])
for n in sourcenames:
- self.sources[n].sort()
+ self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
+
+ def AddConfig(variant, buildtarget, outdir):
+ config = Config()
+ config.buildtarget = buildtarget
+ config.outdir = outdir
- self.configs[self.config.variant] = self.config
+ match = re.match('(.*)\|(.*)', variant)
+ if match:
+ config.variant = match.group(1)
+ config.platform = match.group(2)
+ else:
+ config.variant = variant
+ config.platform = 'Win32';
+
+ self.configs[variant] = config
+ print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
+
+ for i in range(len(variants)):
+ AddConfig(variants[i], buildtarget[i], outdir[i])
+
+ self.platforms = []
+ for key in self.configs.keys():
+ platform = self.configs[key].platform
+ if not platform in self.platforms:
+ self.platforms.append(platform)
def Build(self):
pass
@@ -253,6 +326,10 @@ class _GenerateV6DSP(_DSPGenerator):
else:
self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
+ env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
+ if not env_has_buildtarget:
+ self.env['MSVSBUILDTARGET'] = buildtarget
+
# 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'
@@ -263,16 +340,17 @@ class _GenerateV6DSP(_DSPGenerator):
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 = 'echo Starting SCons && "%s" -c "%s" -C %s -f %s %s'
- cmd = cmd % (python_executable, exec_script_main, d, c, buildtarget)
- self.file.write('# PROP %sCmd_Line "%s"\n'
+ cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1)
+ 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))
+ if not env_has_buildtarget:
+ del self.env['MSVSBUILDTARGET']
+
self.file.write('\n!ENDIF\n\n'
'# Begin Target\n\n')
for kind in confkeys:
@@ -290,23 +368,24 @@ class _GenerateV6DSP(_DSPGenerator):
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,1)
- pdata = base64.encodestring(pdata)
- self.file.write(pdata + '\n')
- pdata = pickle.dumps(self.sources,1)
- pdata = base64.encodestring(pdata)
- self.file.write(pdata + '\n')
+ if self.nokeep == 0:
+ # now we pickle some data and add it to the file -- MSDEV will ignore it.
+ pdata = pickle.dumps(self.configs,1)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '\n')
+ pdata = pickle.dumps(self.sources,1)
+ 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',
+ 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()
+ cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
for kind in cats:
if not self.sources[kind]:
continue # skip empty groups
@@ -322,9 +401,9 @@ class _GenerateV6DSP(_DSPGenerator):
'# End Source File\n')
self.file.write('# End Group\n')
- # add the Conscript file outside of the groups
+ # add the SConscript file outside of the groups
self.file.write('# Begin Source File\n\n'
- 'SOURCE="' + str(self.source) + '"\n'
+ 'SOURCE="' + str(self.sconscript) + '"\n'
'# End Source File\n')
def Parse(self):
@@ -386,7 +465,7 @@ class _GenerateV6DSP(_DSPGenerator):
self.file.close()
V7DSPHeader = """\
-<?xml version="1.0" encoding = "Windows-1252"?>
+<?xml version="1.0" encoding = "%(encoding)s"?>
<VisualStudioProject
\tProjectType="Visual C++"
\tVersion="%(versionstr)s"
@@ -394,15 +473,11 @@ V7DSPHeader = """\
\tSccProjectName=""
\tSccLocalPath=""
\tKeyword="MakeFileProj">
-\t<Platforms>
-\t\t<Platform
-\t\t\tName="Win32"/>
-\t</Platforms>
"""
V7DSPConfiguration = """\
\t\t<Configuration
-\t\t\tName="%(capitalized_kind)s|Win32"
+\t\t\tName="%(variant)s|Win32"
\t\t\tOutputDirectory="%(outdir)s"
\t\t\tIntermediateDirectory="%(outdir)s"
\t\t\tConfigurationType="0"
@@ -410,9 +485,9 @@ V7DSPConfiguration = """\
\t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE">
\t\t\t<Tool
\t\t\t\tName="VCNMakeTool"
-\t\t\t\tBuildCommandLine="%(cmd)s"
+\t\t\t\tBuildCommandLine="%(buildcmd)s"
\t\t\t\tCleanCommandLine="%(cleancmd)s"
-\t\t\t\tRebuildCommandLine="%(cmd)s"
+\t\t\t\tRebuildCommandLine="%(rebuildcmd)s"
\t\t\t\tOutput="%(buildtarget)s"/>
\t\t</Configuration>
"""
@@ -428,7 +503,18 @@ class _GenerateV7DSP(_DSPGenerator):
self.versionstr = '7.10'
def PrintHeader(self):
- self.file.write(V7DSPHeader % self.__dict__)
+ versionstr = self.versionstr
+ name = self.name
+ encoding = self.env.subst('$MSVSENCODING')
+
+ self.file.write(V7DSPHeader % locals())
+
+ self.file.write('\t<Platforms>\n')
+ for platform in self.platforms:
+ self.file.write(
+ '\t\t<Platform\n'
+ '\t\t\tName="%s"/>\n' % platform)
+ self.file.write('\t</Platforms>\n')
def PrintProject(self):
self.file.write('\t<Configurations>\n')
@@ -436,39 +522,52 @@ class _GenerateV7DSP(_DSPGenerator):
confkeys = self.configs.keys()
confkeys.sort()
for kind in confkeys:
- capitalized_kind = kind.capitalize()
+ variant = self.configs[kind].variant
+ platform = self.configs[kind].platform
outdir = self.configs[kind].outdir
buildtarget = self.configs[kind].buildtarget
- (d,c) = os.path.split(str(self.conspath))
- fmt = 'echo Starting SCons &amp;&amp; &quot;%s&quot; -c &quot;%s&quot; -C %s -f %s%s %s'
- cmd = fmt % (python_executable, exec_script_main_xml,
- d, c, '', buildtarget)
- cleancmd = fmt % (python_executable, exec_script_main_xml,
- d, c, ' -c', buildtarget)
+ def xmlify(cmd):
+ cmd = string.replace(cmd, "&", "&amp;") # do this first
+ cmd = string.replace(cmd, "'", "&apos;")
+ cmd = string.replace(cmd, '"', "&quot;")
+ return cmd
+
+ env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
+ if not env_has_buildtarget:
+ self.env['MSVSBUILDTARGET'] = buildtarget
+
+ starting = 'echo Starting SCons && '
+ buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1))
+ rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1))
+ cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1))
+
+ if not env_has_buildtarget:
+ del self.env['MSVSBUILDTARGET']
self.file.write(V7DSPConfiguration % locals())
self.file.write('\t</Configurations>\n')
if self.version >= 7.1:
- self.file.write('\t<References>\n'
+ self.file.write('\t<References>\n'
'\t</References>\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,1)
- pdata = base64.encodestring(pdata)
- self.file.write('<!-- SCons Data:\n' + pdata + '\n')
- pdata = pickle.dumps(self.sources,1)
- pdata = base64.encodestring(pdata)
- self.file.write(pdata + '-->\n')
+ if self.nokeep == 0:
+ # now we pickle some data and add it to the file -- MSDEV will ignore it.
+ pdata = pickle.dumps(self.configs,1)
+ pdata = base64.encodestring(pdata)
+ self.file.write('<!-- SCons Data:\n' + pdata + '\n')
+ pdata = pickle.dumps(self.sources,1)
+ 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',
+ 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',
@@ -477,30 +576,61 @@ class _GenerateV7DSP(_DSPGenerator):
self.file.write('\t<Files>\n')
cats = categories.keys()
- cats.sort()
+ cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
+ cats = filter(lambda k, s=self: s.sources[k], cats)
for kind in cats:
- if not self.sources[kind]:
- continue # skip empty groups
-
- self.file.write('\t\t<Filter\n'
- '\t\t\tName="%s"\n'
- '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
-
- for file in self.sources[kind]:
- file = os.path.normpath(file)
- self.file.write('\t\t\t<File\n'
- '\t\t\t\tRelativePath="%s">\n'
- '\t\t\t</File>\n' % file)
-
- self.file.write('\t\t</Filter>\n')
-
- # add the Conscript file outside of the groups
+ if len(cats) > 1:
+ self.file.write('\t\t<Filter\n'
+ '\t\t\tName="%s"\n'
+ '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
+
+
+ def printSources(hierarchy):
+ sorteditems = hierarchy.items()
+ sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
+
+ # First folders, then files
+ for key, value in sorteditems:
+ if SCons.Util.is_Dict(value):
+ self.file.write('\t\t\t<Filter\n'
+ '\t\t\t\tName="%s"\n'
+ '\t\t\t\tFilter="">\n' % (key))
+ printSources(value)
+ self.file.write('\t\t\t</Filter>\n')
+
+ for key, value in sorteditems:
+ if SCons.Util.is_String(value):
+ file = value
+ if commonprefix:
+ file = os.path.join(commonprefix, value)
+ file = os.path.normpath(file)
+ self.file.write('\t\t\t<File\n'
+ '\t\t\t\tRelativePath="%s">\n'
+ '\t\t\t</File>\n' % (file))
+
+ sources = self.sources[kind]
+
+ # First remove any common prefix
+ commonprefix = None
+ if len(sources) > 1:
+ commonprefix = os.path.commonprefix(sources)
+ prefixlen = len(commonprefix)
+ if prefixlen:
+ sources = map(lambda s, p=prefixlen: s[p:], sources)
+
+ hierarchy = makeHierarchy(sources)
+ printSources(hierarchy)
+
+ if len(cats)>1:
+ self.file.write('\t\t</Filter>\n')
+
+ # add the SConscript file outside of the groups
self.file.write('\t\t<File\n'
'\t\t\tRelativePath="%s">\n'
- '\t\t</File>\n'
- '\t</Files>\n' % str(self.source))
+ '\t\t</File>\n' % str(self.sconscript))
- self.file.write('\t<Globals>\n'
+ self.file.write('\t</Files>\n'
+ '\t<Globals>\n'
'\t</Globals>\n')
def Parse(self):
@@ -562,11 +692,26 @@ class _GenerateV7DSP(_DSPGenerator):
class _DSWGenerator:
""" Base class for DSW generators """
- def __init__(self, dswfile, dspfile, source, env):
+ def __init__(self, dswfile, source, env):
self.dswfile = os.path.normpath(str(dswfile))
- self.dspfile = os.path.abspath(str(dspfile))
self.env = env
+ if not env.has_key('projects'):
+ raise SCons.Errors.UserError, \
+ "You must specify a 'projects' argument to create an MSVSSolution."
+ projects = env['projects']
+ if not SCons.Util.is_List(projects):
+ raise SCons.Errors.InternalError, \
+ "The 'projects' argument must be a list of nodes."
+ projects = SCons.Util.flatten(projects)
+ if len(projects) < 1:
+ raise SCons.Errors.UserError, \
+ "You must specify at least one project to create an MSVSSolution."
+ if len(projects) > 1:
+ raise SCons.Errors.UserError, \
+ "Currently you can specify at most one project to create an MSVSSolution."
+ self.dspfile = str(projects[0])
+
if self.env.has_key('name'):
self.name = self.env['name']
else:
@@ -577,8 +722,8 @@ class _DSWGenerator:
class _GenerateV7DSW(_DSWGenerator):
"""Generates a Solution file for MSVS .NET"""
- def __init__(self, dswfile, dspfile, source, env):
- _DSWGenerator.__init__(self, dswfile, dspfile, source, env)
+ def __init__(self, dswfile, source, env):
+ _DSWGenerator.__init__(self, dswfile, source, env)
self.version = float(self.env['MSVS_VERSION'])
self.versionstr = '7.00'
@@ -590,20 +735,44 @@ class _GenerateV7DSW(_DSWGenerator):
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.nokeep = 0
+ if env.has_key('nokeep') and env['variant'] != 0:
+ self.nokeep = 1
+
+ if self.nokeep == 0 and os.path.exists(self.dswfile):
self.Parse()
- self.configs[self.config.variant] = self.config
+ def AddConfig(variant):
+ config = Config()
+
+ match = re.match('(.*)\|(.*)', variant)
+ if match:
+ config.variant = match.group(1)
+ config.platform = match.group(2)
+ else:
+ config.variant = variant
+ config.platform = 'Win32';
+
+ self.configs[variant] = config
+ print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
+
+ if not env.has_key('variant'):
+ raise SCons.Errors.InternalError, \
+ "You must specify a 'variant' argument (i.e. 'Debug' or " +\
+ "'Release') to create an MSVS Solution File."
+ elif SCons.Util.is_String(env['variant']):
+ AddConfig(env['variant'])
+ elif SCons.Util.is_List(env['variant']):
+ for variant in env['variant']:
+ AddConfig(variant)
+
+ self.platforms = []
+ for key in self.configs.keys():
+ platform = self.configs[key].platform
+ if not platform in self.platforms:
+ self.platforms.append(platform)
def Parse(self):
try:
@@ -650,7 +819,8 @@ class _GenerateV7DSW(_DSWGenerator):
confkeys.sort()
cnt = 0
for name in confkeys:
- self.file.write('\t\tConfigName.%d = %s\n' % (cnt, name.capitalize()))
+ variant = self.configs[name].variant
+ self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant))
cnt = cnt + 1
self.file.write('\tEndGlobalSection\n')
if self.version < 7.1:
@@ -658,18 +828,21 @@ class _GenerateV7DSW(_DSWGenerator):
'\tEndGlobalSection\n')
self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
for name in confkeys:
- name = name.capitalize()
- self.file.write('\t\t%s.%s.ActiveCfg = %s|Win32\n'
- '\t\t%s.%s.Build.0 = %s|Win32\n' %(self.slnguid,name,name,self.slnguid,name,name))
+ name = name
+ variant = self.configs[name].variant
+ platform = self.configs[name].platform
+ self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
+ '\t\t%s.%s.Build.0 = %s|%s\n' %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform))
self.file.write('\tEndGlobalSection\n'
'\tGlobalSection(ExtensibilityGlobals) = postSolution\n'
'\tEndGlobalSection\n'
'\tGlobalSection(ExtensibilityAddIns) = postSolution\n'
'\tEndGlobalSection\n'
'EndGlobal\n')
- pdata = pickle.dumps(self.configs,1)
- pdata = base64.encodestring(pdata)
- self.file.write(pdata + '\n')
+ if self.nokeep == 0:
+ pdata = pickle.dumps(self.configs,1)
+ pdata = base64.encodestring(pdata)
+ self.file.write(pdata + '\n')
def Build(self):
try:
@@ -716,7 +889,9 @@ class _GenerateV6DSW(_DSWGenerator):
def PrintWorkspace(self):
""" writes a DSW file """
- self.file.write(V6DSWHeader % self.__dict__)
+ name = self.name
+ dspfile = self.dspfile
+ self.file.write(V6DSWHeader % locals())
def Build(self):
try:
@@ -738,14 +913,14 @@ def GenerateDSP(dspfile, source, env):
g = _GenerateV6DSP(dspfile, source, env)
g.Build()
-def GenerateDSW(dswfile, dspfile, source, env):
+def GenerateDSW(dswfile, source, env):
"""Generates a Solution/Workspace file based on the version of MSVS that is being used"""
if env.has_key('MSVS_VERSION') and float(env['MSVS_VERSION']) >= 7.0:
- g = _GenerateV7DSW(dswfile, dspfile, source, env)
+ g = _GenerateV7DSW(dswfile, source, env)
g.Build()
else:
- g = _GenerateV6DSW(dswfile, dspfile, source, env)
+ g = _GenerateV6DSW(dswfile, source, env)
g.Build()
@@ -761,7 +936,7 @@ def get_default_visualstudio_version(env):
version = '6.0'
versions = [version]
- if not env.has_key('MSVS') or type(env['MSVS']) != types.DictType:
+ if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
env['MSVS'] = {}
if env.has_key('MSVS_VERSION'):
@@ -1022,19 +1197,10 @@ def GetMSVSSolutionSuffix(target, source, env, for_signature):
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))):
+ if not dspfile is builddspfile:
try:
bdsp = open(str(builddspfile), "w+")
except IOError, detail:
@@ -1043,20 +1209,33 @@ def GenerateProject(target, source, env):
bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
- try:
- bdsw = open(str(builddswfile), "w+")
- except IOError, detail:
- print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
- raise
+ GenerateDSP(dspfile, source, env)
- bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
+ if env.get('auto_build_solution', 1):
+ builddswfile = target[1]
+ dswfile = builddswfile.srcnode()
- GenerateDSP(dspfile, source, env)
- GenerateDSW(dswfile, dspfile, source, env)
+ if not dswfile is builddswfile:
+
+ try:
+ bdsw = open(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())
+
+ GenerateDSW(dswfile, source, env)
+
+def GenerateSolution(target, source, env):
+ GenerateDSW(target[0], source, env)
def projectEmitter(target, source, env):
- """Sets up the DSP and DSW dependencies for an SConscript file."""
+ """Sets up the DSP dependencies."""
+ # todo: Not sure what sets source to what user has passed as target,
+ # but this is what happens. When that is fixed, we also won't have
+ # to make the user always append env['MSVSPROJECTSUFFIX'] to target.
if source[0] == target[0]:
source = []
@@ -1065,36 +1244,157 @@ def projectEmitter(target, source, env):
suff = env.subst('$MSVSPROJECTSUFFIX')
target[0] = base + suff
- dspfile = env.File(target[0]).srcnode()
- dswfile = env.File(SCons.Util.splitext(str(dspfile))[0] + env.subst('$MSVSSOLUTIONSUFFIX'))
+ if not source:
+ source = 'prj_inputs:'
+ source = source + env.subst('$MSVSSCONSCOM', 1)
+ source = source + env.subst('$MSVSENCODING', 1)
+
+ if env.has_key('buildtarget') and env['buildtarget'] != None:
+ if SCons.Util.is_String(env['buildtarget']):
+ source = source + ' "%s"' % env['buildtarget']
+ elif SCons.Util.is_List(env['buildtarget']):
+ for bt in env['buildtarget']:
+ if SCons.Util.is_String(bt):
+ source = source + ' "%s"' % bt
+ else:
+ try: source = source + ' "%s"' % bt.get_abspath()
+ except AttributeError: raise SCons.Errors.InternalError, \
+ "buildtarget can be a string, a node, a list of strings or nodes, or None"
+ else:
+ try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
+ except AttributeError: raise SCons.Errors.InternalError, \
+ "buildtarget can be a string, a node, a list of strings or nodes, or None"
+
+ if env.has_key('outdir') and env['outdir'] != None:
+ if SCons.Util.is_String(env['outdir']):
+ source = source + ' "%s"' % env['outdir']
+ elif SCons.Util.is_List(env['outdir']):
+ for s in env['outdir']:
+ if SCons.Util.is_String(s):
+ source = source + ' "%s"' % s
+ else:
+ try: source = source + ' "%s"' % s.get_abspath()
+ except AttributeError: raise SCons.Errors.InternalError, \
+ "outdir can be a string, a node, a list of strings or nodes, or None"
+ else:
+ try: source = source + ' "%s"' % env['outdir'].get_abspath()
+ except AttributeError: raise SCons.Errors.InternalError, \
+ "outdir can be a string, a node, a list of strings or nodes, or None"
+
+ if env.has_key('name'):
+ if SCons.Util.is_String(env['name']):
+ source = source + ' "%s"' % env['name']
+ else:
+ raise SCons.Errors.InternalError, "name must be a string"
+
+ if env.has_key('variant'):
+ if SCons.Util.is_String(env['variant']):
+ source = source + ' "%s"' % env['variant']
+ elif SCons.Util.is_List(env['variant']):
+ for variant in env['variant']:
+ if SCons.Util.is_String(variant):
+ source = source + ' "%s"' % variant
+ else:
+ raise SCons.Errors.InternalError, "name must be a string or a list of strings"
+ else:
+ raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
+ else:
+ raise SCons.Errors.InternalError, "variant must be specified"
+
+ for s in _DSPGenerator.srcargs:
+ if env.has_key(s):
+ if SCons.Util.is_String(env[s]):
+ source = source + ' "%s' % env[s]
+ elif SCons.Util.is_List(env[s]):
+ for t in env[s]:
+ if SCons.Util.is_String(t):
+ source = source + ' "%s"' % t
+ else:
+ raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
+ else:
+ raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
+
+ source = source + ' "%s"' % str(target[0])
+ source = [SCons.Node.Python.Value(source)]
+
+ targetlist = [target[0]]
+ sourcelist = source
+
+ if env.get('auto_build_solution', 1):
+ env['projects'] = targetlist
+ t, s = solutionEmitter(target, target, env)
+ targetlist = targetlist + t
+
+ return (targetlist, sourcelist)
+
+def solutionEmitter(target, source, env):
+ """Sets up the DSW dependencies."""
+
+ # todo: Not sure what sets source to what user has passed as target,
+ # but this is what happens. When that is fixed, we also won't have
+ # to make the user always append env['MSVSSOLUTIONSUFFIX'] to target.
+ if source[0] == target[0]:
+ source = []
+
+ # make sure the suffix is correct for the version of MSVS we're running.
+ (base, suff) = SCons.Util.splitext(str(target[0]))
+ suff = env.subst('$MSVSSOLUTIONSUFFIX')
+ target[0] = base + suff
- # XXX Need to find a way to abstract this; the build engine
- # shouldn't depend on anything in SCons.Script.
- stack = SCons.Script.call_stack
if not source:
- source = [stack[-1].sconscript.srcnode()]
- source[0].attributes.sconstruct = stack[0].sconscript
+ source = 'sln_inputs:'
- bdswpath = SCons.Util.splitext(str(target[0]))[0] + env.subst('$MSVSSOLUTIONSUFFIX')
- bdswfile = env.File(bdswpath)
+ if env.has_key('name'):
+ if SCons.Util.is_String(env['name']):
+ source = source + ' "%s"' % env['name']
+ else:
+ raise SCons.Errors.InternalError, "name must be a string"
- # 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])
+ if env.has_key('variant'):
+ if SCons.Util.is_String(env['variant']):
+ source = source + ' "%s"' % env['variant']
+ elif SCons.Util.is_List(env['variant']):
+ for variant in env['variant']:
+ if SCons.Util.is_String(variant):
+ source = source + ' "%s"' % variant
+ else:
+ raise SCons.Errors.InternalError, "name must be a string or a list of strings"
+ else:
+ raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
+ else:
+ raise SCons.Errors.InternalError, "variant must be specified"
- return ([target[0],bdswfile], source)
+ if env.has_key('slnguid'):
+ if SCons.Util.is_String(env['slnguid']):
+ source = source + ' "%s"' % env['slnguid']
+ else:
+ raise SCons.Errors.InternalError, "slnguid must be a string"
+
+ if env.has_key('projects'):
+ if SCons.Util.is_String(env['projects']):
+ source = source + ' "%s"' % env['projects']
+ elif SCons.Util.is_List(env['projects']):
+ for t in env['projects']:
+ if SCons.Util.is_String(t):
+ source = source + ' "%s"' % t
+
+ source = source + ' "%s"' % str(target[0])
+ source = [SCons.Node.Python.Value(source)]
+
+ return ([target[0]], source)
-projectGeneratorAction = SCons.Action.Action(GenerateProject, None)
+projectAction = SCons.Action.Action(GenerateProject, None)
+
+solutionAction = SCons.Action.Action(GenerateSolution, None)
projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM',
suffix = '$MSVSPROJECTSUFFIX',
emitter = projectEmitter)
+solutionBuilder = SCons.Builder.Builder(action = '$MSVSSOLUTIONCOM',
+ suffix = '$MSVSSOLUTIONSUFFIX',
+ emitter = solutionEmitter)
+
def generate(env):
"""Add Builders and construction variables for Microsoft Visual
Studio project files to an Environment."""
@@ -1103,7 +1403,28 @@ def generate(env):
except KeyError:
env['BUILDERS']['MSVSProject'] = projectBuilder
- env['MSVSPROJECTCOM'] = projectGeneratorAction
+ try:
+ env['BUILDERS']['MSVSSolution']
+ except KeyError:
+ env['BUILDERS']['MSVSSolution'] = solutionBuilder
+
+ env['MSVSPROJECTCOM'] = projectAction
+ env['MSVSSOLUTIONCOM'] = solutionAction
+
+ if SCons.Script.call_stack:
+ # XXX Need to find a way to abstract this; the build engine
+ # shouldn't depend on anything in SCons.Script.
+ env['MSVSSCONSCRIPT'] = SCons.Script.call_stack[0].sconscript
+ else:
+ env['MSVSSCONSCRIPT'] = env.File('SConstruct')
+
+ env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, exec_script_main)
+ env['MSVSSCONSFLAGS'] = '-C ${MSVSSCONSCRIPT.dir.abspath} -f ${MSVSSCONSCRIPT.name}'
+ env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
+ env['MSVSBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
+ env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
+ env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c $MSVSBUILDTARGET'
+ env['MSVSENCODING'] = 'Windows-1252'
try:
version = get_default_visualstudio_version(env)
@@ -1143,4 +1464,3 @@ def exists(env):
else:
# there's at least one version of MSVS installed.
return 1
-
diff --git a/src/engine/SCons/Tool/msvs.xml b/src/engine/SCons/Tool/msvs.xml
index 4103ce1..647acd5 100644
--- a/src/engine/SCons/Tool/msvs.xml
+++ b/src/engine/SCons/Tool/msvs.xml
@@ -7,62 +7,100 @@ XXX
<builder name ="MSVSProject">
<summary>
-Builds Microsoft Visual Studio project files.
+Builds a Microsoft Visual Studio project file,
+and by default builds a solution file as well.
+
This builds a Visual Studio project file, based on the version of
Visual Studio that is configured (either the latest installed version,
-or the version set by
+or the version specified by
&cv-MSVS_VERSION;
in the Environment constructor).
-For VS 6, it will generate
+For Visual Studio 6, it will generate a
<filename>.dsp</filename>
-and
+file.
+For Visual Studio 7 (.NET), it will generate a
+<filename>.dsp</filename>
+file.
+
+By default,
+this also generates a solution file
+for the specified project,
+a
<filename>.dsw</filename>
-files, for VS 7, it will
-generate
-<filename>.vcproj</filename>
-and
+file for Visual Studio 6
+or a
<filename>.sln</filename>
-files.
+file for Visual Studio 7 (.NET).
+This behavior may be disabled by specifying
+<literal>auto_build_solution=0</literal>
+when you call
+&b-MSVSProject;,
+in which case you presumably want to
+build the solution file(s)
+by calling the
+&b-MSVSSolution;
+Builder (see below).
It takes several lists of filenames to be placed into the project
-file, currently these are limited to
+file.
+These are currently these are limited to
<literal>srcs</literal>,
<literal>incs</literal>,
<literal>localincs</literal>,
<literal>resources</literal>,
and
<literal>misc</literal>.
-These are pretty self explanatory, but it
-should be noted that the <literal>srcs</literal> list
-is NOT added to the &cv-SOURCES;
-construction variable. This is because it represents a list of files
-to be added to the project file, not the source used to build the
-project file (in this case, the "source" is the &SConscript; file used
-to call MSVSProject).
-
-In addition to these values (which are all optional, although not
-specifying any of them results in an empty project file), the
-following values must be specified:
-
-target: The name of the target
+These are pretty self-explanatory, but it should be noted that these
+lists are added to the &cv-SOURCES; construction variable as strings,
+NOT as SCons File Nodes. This is because they represent file
+names to be added to the project file, not the source files used to
+build the project file.
+
+In addition to the above lists of values (which are all optional,
+although not specifying any of them results in an empty project file),
+the following values may be specified:
+
+<literal>target</literal>: The name of the target
<filename>.dsp</filename>
or
<filename>.vcproj</filename>
-file. The correct
-suffix for the version of Visual Studio must be used, but the
+file.
+The correct
+suffix for the version of Visual Studio must be used,
+but the
&cv-MSVSPROJECTSUFFIX;
-construction value
+construction variable
will be defined to the correct value (see example below).
-variant: The name of this particular variant. These are typically
-things like "Debug" or "Release", but really can be anything you want.
-Multiple calls to MSVSProject with different variants are allowed: all
-variants will be added to the project file with their appropriate
+<literal>variant</literal>:
+The name of this particular variant.
+For Visual Studio 7 projects,
+this can also be a list of variant names.
+These are typically things like "Debug" or "Release", but really
+can be anything you want.
+For Visual Studio 7 projects,
+they may also specify a target platform
+separated from the variant name by a
+<literal>|</literal>
+(vertical pipe)
+character:
+<literal>Debug|Xbox</literal>.
+The default target platform is Win32.
+Multiple calls to
+&b-MSVSProject;
+ with different variants are allowed;
+all variants will be added to the project file with their appropriate
build targets and sources.
-buildtarget: A list of SCons.Node.FS objects which is returned from
-the command which builds the target. This is used to tell SCons what
-to build when the 'build' button is pressed inside of the IDE.
+<literal>buildtarget</literal>:
+An optional string, node, or list of strings or nodes
+(one per build variant), to tell the Visual Studio debugger
+what output target to use in what build variant.
+The number of
+<literal>buildtarget</literal>
+entries must match the number of
+<literal>variant</literal>
+entries.
Example usage:
@@ -88,6 +126,60 @@ local.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'],
</summary>
</builder>
+<builder name ="MSVSSolution">
+<summary>
+Builds a Microsoft Visual Studio solution file.
+
+This builds a Visual Studio solution file,
+based on the version of Visual Studio that is configured
+(either the latest installed version,
+or the version specified by
+&cv-MSVS_VERSION;
+in the construction environment).
+For Visual Studio 6, it will generate a
+<filename>dsw</filename>
+file.
+For Visual Studio 7 (.NET), it will
+generate a
+<filename>sln</filename>
+file.
+
+The following values must be specified:
+
+<literal>target</literal>:
+The name of the target .dsw or .sln file. The correct
+suffix for the version of Visual Studio must be used, but the value
+&cv-MSVSSOLUTIONSUFFIX;
+will be defined to the correct value (see example below).
+
+<literal>variant</literal>:
+The name of this particular variant, or a list of variant
+names (the latter is only supported for MSVS 7 solutions). These are
+typically things like "Debug" or "Release", but really can be anything
+you want. For MSVS 7 they may also specify target platform, like this
+"Debug|Xbox". Default platform is Win32.
+
+<literal>projects</literal>:
+A list of project file names, or Project nodes returned by calls to the
+&b-MSVSProject;
+Builder,
+to be placed into the solution file.
+(NOTE: Currently only one project is supported per solution.)
+It should be noted that these file names are NOT added to the $SOURCES
+environment variable in form of files, but rather as strings. This
+is because they represent file names to be added to the solution file,
+not the source files used to build the solution file.
+
+Example Usage:
+
+<example>
+local.MSVSSolution(target = 'Bar' + env['MSVSSOLUTIONSUFFIX'],
+ projects = ['bar' + env['MSVSPROJECTSUFFIX']],
+ variant = 'Release')
+</example>
+</summary>
+</builder>
+
<cvar name="MSVS">
<summary>
When the Microsoft Visual Studio tools are initialized, they set up
@@ -224,8 +316,10 @@ environment variables are set explictly.
Sets the preferred version of MSVS to use.
SCons will (by default) select the latest version of MSVS
-installed on your machine. So, if you have version 6 and version 7
-(MSVS .NET) installed, it will prefer version 7. You can override this by
+installed on your machine.
+So, if you have version 6 and version 7 (MSVS .NET) installed,
+it will prefer version 7.
+You can override this by
specifying the
<envar>MSVS_VERSION</envar>
variable in the Environment initialization, setting it to the
@@ -234,10 +328,36 @@ If the given version isn't installed, tool initialization will fail.
</summary>
</cvar>
+<cvar name="MSVSBUILDCOM">
+<summary>
+The build command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with any specified
+build targets.
+</summary>
+</cvar>
+
+<cvar name="MSVSCLEANCOM">
+<summary>
+The clean command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with the -c option
+to remove any specified targets.
+</summary>
+</cvar>
+
+<cvar name="MSVSENCODING">
+<summary>
+The encoding string placed in
+a generated Microsoft Visual Studio project file.
+The default is encoding
+<literal>Windows-1252</literal>.
+</summary>
+</cvar>
+
<cvar name="MSVSPROJECTCOM">
<summary>
-The action used to generate Microsoft Visual Studio
-project and solution files.
+The action used to generate Microsoft Visual Studio project files.
</summary>
</cvar>
@@ -253,6 +373,63 @@ when using earlier versions of Visual Studio.
</summary>
</cvar>
+<cvar name="MSVSREBUILDCOM">
+<summary>
+The rebuild command line placed in
+a generated Microsoft Visual Studio project file.
+The default is to have Visual Studio invoke SCons with any specified
+rebuild targets.
+</summary>
+</cvar>
+
+<cvar name="MSVSSCONS">
+<summary>
+The SCons used in generated Microsoft Visual Studio project files.
+The default is the version of SCons being
+used to generate the project file.
+</summary>
+</cvar>
+
+<cvar name="MSVSSCONSFLAGS">
+<summary>
+The SCons flags used in generated Microsoft Visual Studio
+project files.
+</summary>
+</cvar>
+
+<cvar name="MSVSSCONSCOM">
+<summary>
+The default SCons command used in generated Microsoft Visual Studio
+project files.
+</summary>
+</cvar>
+
+<cvar name="MSVSSCONSCRIPT">
+<summary>
+The sconscript file
+(that is,
+&SConstruct;
+or
+&SConscript;
+file)
+that will be invoked by Visual Studio
+project files
+(through the
+&cv-MSVSSCONSCOM;
+variable).
+The default is the same sconscript file
+that contains the call to
+&b-MSVSProject;
+to build the project file.
+</summary>
+</cvar>
+
+<cvar name="MSVSSOLUTIONCOM">
+<summary>
+The action used to generate Microsoft Visual Studio solution files.
+</summary>
+</cvar>
+
<cvar name="MSVSSOLUTIONSUFFIX">
<summary>
The suffix used for Microsoft Visual Studio solution (DSW) files.
diff --git a/test/MSVS/vs-6.0-files.py b/test/MSVS/vs-6.0-files.py
index 8792cb0..e3f2994 100644
--- a/test/MSVS/vs-6.0-files.py
+++ b/test/MSVS/vs-6.0-files.py
@@ -75,20 +75,20 @@ 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 "echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-# PROP BASE Rebuild_Opt "-c && echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-# PROP BASE Target_File "<WORKPATH>\Test.exe"
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct Test.exe"
+# PROP BASE Rebuild_Opt "-c && echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct Test.exe"
+# PROP BASE Target_File "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 "echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-# PROP Rebuild_Opt "-c && echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-# PROP Target_File "<WORKPATH>\Test.exe"
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct Test.exe"
+# PROP Rebuild_Opt "-c && echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN>" -C <WORKPATH> -f SConstruct Test.exe"
+# PROP Target_File "Test.exe"
# PROP Bsc_Name ""
# PROP Target_Dir ""
@@ -102,14 +102,6 @@ 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.c"
-# End Source File
-# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
@@ -142,6 +134,14 @@ SOURCE="readme.txt"
SOURCE="test.rc"
# End Source File
# End Group
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;l;y;def;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="test.c"
+# End Source File
+# End Group
# Begin Source File
SOURCE="<SCONSCRIPT>"
@@ -156,7 +156,7 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
###############################################################################
-Project: "Test"="<WORKPATH>\Test.dsp" - Package Owner=<4>
+Project: "Test"="Test.dsp" - Package Owner=<4>
Package=<5>
{{{
@@ -212,15 +212,13 @@ test.run(chdir='work1', arguments="Test.dsp")
test.must_exist(test.workpath('work1', 'Test.dsp'))
dsp = test.read(['work1', 'Test.dsp'], 'r')
-expect = test.msvs_substitute(expected_dspfile, '6.0', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_dspfile, '6.0', 'work1', 'SConstruct')
# don't compare the pickled data
assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp)
test.must_exist(test.workpath('work1', 'Test.dsw'))
dsw = test.read(['work1', 'Test.dsw'], 'r')
-expect = test.msvs_substitute(expected_dswfile, '6.0', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_dswfile, '6.0', 'work1', 'SConstruct')
assert dsw == expect, test.diff_substr(expect, dsw)
test.run(chdir='work1', arguments='-c .')
@@ -250,6 +248,17 @@ test.write(['work2', 'src', 'SConscript'], SConscript_contents)
test.run(chdir='work2', arguments=".")
+dsp = test.read(['work2', 'src', 'Test.dsp'], 'r')
+expect = test.msvs_substitute(expected_dspfile, '6.0', 'work2', 'SConstruct')
+# don't compare the pickled data
+assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp)
+
+test.must_exist(test.workpath('work2', 'src', 'Test.dsw'))
+dsw = test.read(['work2', 'src', 'Test.dsw'], 'r')
+expect = test.msvs_substitute(expected_dswfile, '6.0',
+ os.path.join('work2', 'src'))
+assert dsw == expect, test.diff_substr(expect, dsw)
+
test.must_match(['work2', 'build', 'Test.dsp'], """\
This is just a placeholder file.
The real project file is here:
@@ -257,12 +266,6 @@ The real project file is here:
""" % test.workpath('work2', 'src', 'Test.dsp'),
mode='r')
-dsp = test.read(['work2', 'src', 'Test.dsp'], 'r')
-expect = test.msvs_substitute(expected_dspfile, '6.0', 'work2',
- test.workpath('work2', 'src', 'SConscript'))
-# don't compare the pickled data
-assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp)
-
test.must_match(['work2', 'build', 'Test.dsw'], """\
This is just a placeholder file.
The real workspace file is here:
@@ -270,11 +273,67 @@ The real workspace file is here:
""" % test.workpath('work2', 'src', 'Test.dsw'),
mode='r')
-test.must_exist(test.workpath('work2', 'src', 'Test.dsw'))
-dsw = test.read(['work2', 'src', 'Test.dsw'], 'r')
-expect = test.msvs_substitute(expected_dswfile, '6.0', 'work2\\src')
+
+
+test.subdir('work3')
+
+test.write(['work3', 'SConstruct'], """\
+env=Environment(MSVS_VERSION = '6.0')
+
+testsrc = ['test.c']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+p = env.MSVSProject(target = 'Test.dsp',
+ srcs = testsrc,
+ incs = testincs,
+ localincs = testlocalincs,
+ resources = testresources,
+ misc = testmisc,
+ buildtarget = 'Test.exe',
+ variant = 'Release',
+ auto_build_solution = 0)
+
+env.MSVSSolution(target = 'Test.dsw',
+ slnguid = '{SLNGUID}',
+ projects = [p],
+ variant = 'Release')
+""")
+
+test.run(chdir='work3', arguments=".")
+
+test.must_exist(test.workpath('work3', 'Test.dsp'))
+dsp = test.read(['work3', 'Test.dsp'], 'r')
+expect = test.msvs_substitute(expected_dspfile, '6.0', 'work3', 'SConstruct')
+# don't compare the pickled data
+assert dsp[:len(expect)] == expect, test.diff_substr(expect, dsp)
+
+test.must_exist(test.workpath('work3', 'Test.dsw'))
+dsw = test.read(['work3', 'Test.dsw'], 'r')
+expect = test.msvs_substitute(expected_dswfile, '6.0', 'work3', 'SConstruct')
assert dsw == expect, test.diff_substr(expect, dsw)
+test.run(chdir='work3', arguments='-c .')
+
+test.must_not_exist(test.workpath('work3', 'Test.dsp'))
+test.must_not_exist(test.workpath('work3', 'Test.dsw'))
+
+test.run(chdir='work3', arguments='.')
+
+test.must_exist(test.workpath('work3', 'Test.dsp'))
+test.must_exist(test.workpath('work3', 'Test.dsw'))
+
+test.run(chdir='work3', arguments='-c Test.dsw')
+
+test.must_exist(test.workpath('work3', 'Test.dsp'))
+test.must_not_exist(test.workpath('work3', 'Test.dsw'))
+
+test.run(chdir='work3', arguments='-c Test.dsp')
+
+test.must_not_exist(test.workpath('work3', 'Test.dsp'))
+
test.pass_test()
diff --git a/test/MSVS/vs-7.0-files.py b/test/MSVS/vs-7.0-files.py
index 9144537..409501d 100644
--- a/test/MSVS/vs-7.0-files.py
+++ b/test/MSVS/vs-7.0-files.py
@@ -79,28 +79,21 @@ expected_vcprojfile = """\
\t<Configurations>
\t\t<Configuration
\t\t\tName="Release|Win32"
-\t\t\tOutputDirectory="<WORKPATH>"
-\t\t\tIntermediateDirectory="<WORKPATH>"
+\t\t\tOutputDirectory=""
+\t\t\tIntermediateDirectory=""
\t\t\tConfigurationType="0"
\t\t\tUseOfMFC="0"
\t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE">
\t\t\t<Tool
\t\t\t\tName="VCNMakeTool"
-\t\t\t\tBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-\t\t\t\tCleanCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe"
-\t\t\t\tRebuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-\t\t\t\tOutput="<WORKPATH>\Test.exe"/>
+\t\t\t\tBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct Test.exe"
+\t\t\t\tCleanCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct -c Test.exe"
+\t\t\t\tRebuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct Test.exe"
+\t\t\t\tOutput="Test.exe"/>
\t\t</Configuration>
\t</Configurations>
\t<Files>
\t\t<Filter
-\t\t\tName=" Source Files"
-\t\t\tFilter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
-\t\t\t<File
-\t\t\t\tRelativePath="test.cpp">
-\t\t\t</File>
-\t\t</Filter>
-\t\t<Filter
\t\t\tName="Header Files"
\t\t\tFilter="h;hpp;hxx;hm;inl">
\t\t\t<File
@@ -128,6 +121,13 @@ expected_vcprojfile = """\
\t\t\t\tRelativePath="test.rc">
\t\t\t</File>
\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Source Files"
+\t\t\tFilter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
+\t\t\t<File
+\t\t\t\tRelativePath="test.cpp">
+\t\t\t</File>
+\t\t</Filter>
\t\t<File
\t\t\tRelativePath="<SCONSCRIPT>">
\t\t</File>
@@ -169,15 +169,13 @@ test.run(chdir='work1', arguments="Test.vcproj")
test.must_exist(test.workpath('work1', 'Test.vcproj'))
vcproj = test.read(['work1', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work1', 'SConstruct')
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
test.must_exist(test.workpath('work1', 'Test.sln'))
sln = test.read(['work1', 'Test.sln'], 'r')
-expect = test.msvs_substitute(expected_slnfile, '7.0', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_slnfile, '7.0', 'work1', 'SConstruct')
# don't compare the pickled data
assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
@@ -208,8 +206,7 @@ python = os.path.join('$(PYTHON_ROOT)', os.path.split(sys.executable)[1])
test.must_exist(test.workpath('work1', 'Test.vcproj'))
vcproj = test.read(['work1', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work1',
- test.workpath('work1', 'SConstruct'),
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work1', 'SConstruct',
python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
@@ -228,6 +225,18 @@ test.write(['work2', 'src', 'SConscript'], SConscript_contents)
test.run(chdir='work2', arguments=".")
+vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
+sln = test.read(['work2', 'src', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '7.0',
+ os.path.join('work2', 'src'))
+# don't compare the pickled data
+assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+
test.must_match(['work2', 'build', 'Test.vcproj'], """\
This is just a placeholder file.
The real project file is here:
@@ -235,12 +244,6 @@ The real project file is here:
""" % test.workpath('work2', 'src', 'Test.vcproj'),
mode='r')
-vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2',
- test.workpath('work2', 'src', 'SConscript'))
-# don't compare the pickled data
-assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
-
test.must_match(['work2', 'build', 'Test.sln'], """\
This is just a placeholder file.
The real workspace file is here:
@@ -248,12 +251,68 @@ The real workspace file is here:
""" % test.workpath('work2', 'src', 'Test.sln'),
mode='r')
-test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
-sln = test.read(['work2', 'src', 'Test.sln'], 'r')
-expect = test.msvs_substitute(expected_slnfile, '7.0', 'work2\\src')
+
+
+test.subdir('work3')
+
+test.write(['work3', 'SConstruct'], """\
+env=Environment(MSVS_VERSION = '7.0')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+p = env.MSVSProject(target = 'Test.vcproj',
+ srcs = testsrc,
+ incs = testincs,
+ localincs = testlocalincs,
+ resources = testresources,
+ misc = testmisc,
+ buildtarget = 'Test.exe',
+ variant = 'Release',
+ auto_build_solution = 0)
+
+env.MSVSSolution(target = 'Test.sln',
+ slnguid = '{SLNGUID}',
+ projects = [p],
+ variant = 'Release')
+""")
+
+test.run(chdir='work3', arguments=".")
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+vcproj = test.read(['work3', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work3', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work3', 'Test.sln'))
+sln = test.read(['work3', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '7.0', 'work3', 'SConstruct')
# don't compare the pickled data
assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+test.run(chdir='work3', arguments='-c .')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='.')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.sln')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.vcproj')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+
test.pass_test()
diff --git a/test/MSVS/vs-7.1-files.py b/test/MSVS/vs-7.1-files.py
index 5b5799b..9cbab12 100644
--- a/test/MSVS/vs-7.1-files.py
+++ b/test/MSVS/vs-7.1-files.py
@@ -79,30 +79,23 @@ expected_vcprojfile = """\
\t<Configurations>
\t\t<Configuration
\t\t\tName="Release|Win32"
-\t\t\tOutputDirectory="<WORKPATH>"
-\t\t\tIntermediateDirectory="<WORKPATH>"
+\t\t\tOutputDirectory=""
+\t\t\tIntermediateDirectory=""
\t\t\tConfigurationType="0"
\t\t\tUseOfMFC="0"
\t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE">
\t\t\t<Tool
\t\t\t\tName="VCNMakeTool"
-\t\t\t\tBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-\t\t\t\tCleanCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe"
-\t\t\t\tRebuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe"
-\t\t\t\tOutput="<WORKPATH>\Test.exe"/>
+\t\t\t\tBuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct Test.exe"
+\t\t\t\tCleanCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct -c Test.exe"
+\t\t\t\tRebuildCommandLine="echo Starting SCons &amp;&amp; &quot;<PYTHON>&quot; -c &quot;<SCONS_SCRIPT_MAIN_XML>&quot; -C <WORKPATH> -f SConstruct Test.exe"
+\t\t\t\tOutput="Test.exe"/>
\t\t</Configuration>
\t</Configurations>
\t<References>
\t</References>
\t<Files>
\t\t<Filter
-\t\t\tName=" Source Files"
-\t\t\tFilter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
-\t\t\t<File
-\t\t\t\tRelativePath="test.cpp">
-\t\t\t</File>
-\t\t</Filter>
-\t\t<Filter
\t\t\tName="Header Files"
\t\t\tFilter="h;hpp;hxx;hm;inl">
\t\t\t<File
@@ -130,6 +123,13 @@ expected_vcprojfile = """\
\t\t\t\tRelativePath="test.rc">
\t\t\t</File>
\t\t</Filter>
+\t\t<Filter
+\t\t\tName="Source Files"
+\t\t\tFilter="cpp;c;cxx;l;y;def;odl;idl;hpj;bat">
+\t\t\t<File
+\t\t\t\tRelativePath="test.cpp">
+\t\t\t</File>
+\t\t</Filter>
\t\t<File
\t\t\tRelativePath="<SCONSCRIPT>">
\t\t</File>
@@ -171,15 +171,13 @@ test.run(chdir='work1', arguments="Test.vcproj")
test.must_exist(test.workpath('work1', 'Test.vcproj'))
vcproj = test.read(['work1', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work1', 'SConstruct')
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
test.must_exist(test.workpath('work1', 'Test.sln'))
sln = test.read(['work1', 'Test.sln'], 'r')
-expect = test.msvs_substitute(expected_slnfile, '7.1', 'work1',
- test.workpath('work1', 'SConstruct'))
+expect = test.msvs_substitute(expected_slnfile, '7.1', 'work1', 'SConstruct')
# don't compare the pickled data
assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
@@ -210,8 +208,7 @@ python = os.path.join('$(PYTHON_ROOT)', os.path.split(sys.executable)[1])
test.must_exist(test.workpath('work1', 'Test.vcproj'))
vcproj = test.read(['work1', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work1',
- test.workpath('work1', 'SConstruct'),
+expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work1', 'SConstruct',
python=python)
# don't compare the pickled data
assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
@@ -230,6 +227,18 @@ test.write(['work2', 'src', 'SConscript'], SConscript_contents)
test.run(chdir='work2', arguments=".")
+vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
+sln = test.read(['work2', 'src', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '7.0',
+ os.path.join('work2', 'src'))
+# don't compare the pickled data
+assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+
test.must_match(['work2', 'build', 'Test.vcproj'], """\
This is just a placeholder file.
The real project file is here:
@@ -237,12 +246,6 @@ The real project file is here:
""" % test.workpath('work2', 'src', 'Test.vcproj'),
mode='r')
-vcproj = test.read(['work2', 'src', 'Test.vcproj'], 'r')
-expect = test.msvs_substitute(expected_vcprojfile, '7.0', 'work2',
- test.workpath('work2', 'src', 'SConscript'))
-# don't compare the pickled data
-assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
-
test.must_match(['work2', 'build', 'Test.sln'], """\
This is just a placeholder file.
The real workspace file is here:
@@ -250,12 +253,68 @@ The real workspace file is here:
""" % test.workpath('work2', 'src', 'Test.sln'),
mode='r')
-test.must_exist(test.workpath('work2', 'src', 'Test.sln'))
-sln = test.read(['work2', 'src', 'Test.sln'], 'r')
-expect = test.msvs_substitute(expected_slnfile, '7.0', 'work2\\src')
+
+
+test.subdir('work3')
+
+test.write(['work3', 'SConstruct'], """\
+env=Environment(MSVS_VERSION = '7.1')
+
+testsrc = ['test.cpp']
+testincs = ['sdk.h']
+testlocalincs = ['test.h']
+testresources = ['test.rc']
+testmisc = ['readme.txt']
+
+p = env.MSVSProject(target = 'Test.vcproj',
+ srcs = testsrc,
+ incs = testincs,
+ localincs = testlocalincs,
+ resources = testresources,
+ misc = testmisc,
+ buildtarget = 'Test.exe',
+ variant = 'Release',
+ auto_build_solution = 0)
+
+env.MSVSSolution(target = 'Test.sln',
+ slnguid = '{SLNGUID}',
+ projects = [p],
+ variant = 'Release')
+""")
+
+test.run(chdir='work3', arguments=".")
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+vcproj = test.read(['work3', 'Test.vcproj'], 'r')
+expect = test.msvs_substitute(expected_vcprojfile, '7.1', 'work3', 'SConstruct')
+# don't compare the pickled data
+assert vcproj[:len(expect)] == expect, test.diff_substr(expect, vcproj)
+
+test.must_exist(test.workpath('work3', 'Test.sln'))
+sln = test.read(['work3', 'Test.sln'], 'r')
+expect = test.msvs_substitute(expected_slnfile, '7.1', 'work3', 'SConstruct')
# don't compare the pickled data
assert sln[:len(expect)] == expect, test.diff_substr(expect, sln)
+test.run(chdir='work3', arguments='-c .')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='.')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.sln')
+
+test.must_exist(test.workpath('work3', 'Test.vcproj'))
+test.must_not_exist(test.workpath('work3', 'Test.sln'))
+
+test.run(chdir='work3', arguments='-c Test.vcproj')
+
+test.must_not_exist(test.workpath('work3', 'Test.vcproj'))
+
test.pass_test()