diff options
-rw-r--r-- | bin/restore.sh | 4 | ||||
-rw-r--r-- | doc/man/scons.1 | 239 | ||||
-rw-r--r-- | src/CHANGES.txt | 5 | ||||
-rw-r--r-- | src/engine/SCons/Tool/msvs.py | 666 | ||||
-rw-r--r-- | src/engine/SCons/Tool/msvs.xml | 251 | ||||
-rw-r--r-- | test/MSVS/vs-6.0-files.py | 123 | ||||
-rw-r--r-- | test/MSVS/vs-7.0-files.py | 115 | ||||
-rw-r--r-- | test/MSVS/vs-7.1-files.py | 115 |
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, "'", "'") # 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 && "%s" -c "%s" -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, "&", "&") # do this first + cmd = string.replace(cmd, "'", "'") + cmd = string.replace(cmd, '"', """) + 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 && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -\t\t\t\tCleanCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe" -\t\t\t\tRebuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -\t\t\t\tOutput="<WORKPATH>\Test.exe"/> +\t\t\t\tBuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct Test.exe" +\t\t\t\tCleanCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct -c Test.exe" +\t\t\t\tRebuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -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 && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -\t\t\t\tCleanCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct -c <WORKPATH>\Test.exe" -\t\t\t\tRebuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct <WORKPATH>\Test.exe" -\t\t\t\tOutput="<WORKPATH>\Test.exe"/> +\t\t\t\tBuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct Test.exe" +\t\t\t\tCleanCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -C <WORKPATH> -f SConstruct -c Test.exe" +\t\t\t\tRebuildCommandLine="echo Starting SCons && "<PYTHON>" -c "<SCONS_SCRIPT_MAIN_XML>" -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() |