From a551ee2c95ce5e0f95a01bf50fdfd97c68818e02 Mon Sep 17 00:00:00 2001 From: stevenknight Date: Sat, 8 Oct 2005 15:31:13 +0000 Subject: [PATCH] MSVC.py improvements: new MSVSSolution() Builder, new variables to contro generation of project and solution files. (Stanislav Baranov) git-svn-id: http://scons.tigris.org/svn/scons/trunk@1363 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- bin/restore.sh | 4 +- doc/man/scons.1 | 239 ++++++++++-- src/CHANGES.txt | 5 + src/engine/SCons/Tool/msvs.py | 666 ++++++++++++++++++++++++--------- src/engine/SCons/Tool/msvs.xml | 251 +++++++++++-- test/MSVS/vs-6.0-files.py | 123 ++++-- test/MSVS/vs-7.0-files.py | 115 ++++-- 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 d5dc6c18..d23d1d0c 100644 --- a/bin/restore.sh +++ b/bin/restore.sh @@ -14,7 +14,7 @@ fi for i in `find $DIRS -name '*.py'`; do ed $i < + -\t -\t\t -\t """ V7DSPConfiguration = """\ \t\t \t\t\t \t\t """ @@ -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\n') + for platform in self.platforms: + self.file.write( + '\t\t\n' % platform) + self.file.write('\t\n') def PrintProject(self): self.file.write('\t\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\n') if self.version >= 7.1: - self.file.write('\t\n' + self.file.write('\t\n' '\t\n') self.PrintSourceFiles() self.file.write('\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('\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('\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\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\n' % (kind, categories[kind])) - - for file in self.sources[kind]: - file = os.path.normpath(file) - self.file.write('\t\t\t\n' - '\t\t\t\n' % file) - - self.file.write('\t\t\n') - - # add the Conscript file outside of the groups + if len(cats) > 1: + self.file.write('\t\t\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\n' % (key)) + printSources(value) + self.file.write('\t\t\t\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\n' + '\t\t\t\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\n') + + # add the SConscript file outside of the groups self.file.write('\t\t\n' - '\t\t\n' - '\t\n' % str(self.source)) + '\t\t\n' % str(self.sconscript)) - self.file.write('\t\n' + self.file.write('\t\n' + '\t\n' '\t\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 4103ce1e..647acd56 100644 --- a/src/engine/SCons/Tool/msvs.xml +++ b/src/engine/SCons/Tool/msvs.xml @@ -7,62 +7,100 @@ XXX -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 .dsp -and +file. +For Visual Studio 7 (.NET), it will generate a +.dsp +file. + +By default, +this also generates a solution file +for the specified project, +a .dsw -files, for VS 7, it will -generate -.vcproj -and +file for Visual Studio 6 +or a .sln -files. +file for Visual Studio 7 (.NET). +This behavior may be disabled by specifying +auto_build_solution=0 +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 srcs, incs, localincs, resources, and misc. -These are pretty self explanatory, but it -should be noted that the srcs 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: + +target: The name of the target .dsp or .vcproj -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 +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 +| +(vertical pipe) +character: +Debug|Xbox. +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. +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 +buildtarget +entries must match the number of +variant +entries. Example usage: @@ -88,6 +126,60 @@ local.MSVSProject(target = 'Bar' + env['MSVSPROJECTSUFFIX'], + + +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 +dsw +file. +For Visual Studio 7 (.NET), it will +generate a +sln +file. + +The following values must be specified: + +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 +&cv-MSVSSOLUTIONSUFFIX; +will be defined to the correct value (see example below). + +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. + +projects: +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: + + +local.MSVSSolution(target = 'Bar' + env['MSVSSOLUTIONSUFFIX'], + projects = ['bar' + env['MSVSPROJECTSUFFIX']], + variant = 'Release') + + + + 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 MSVS_VERSION variable in the Environment initialization, setting it to the @@ -234,10 +328,36 @@ If the given version isn't installed, tool initialization will fail. + + +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. + + + + + +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. + + + + + +The encoding string placed in +a generated Microsoft Visual Studio project file. +The default is encoding +Windows-1252. + + + -The action used to generate Microsoft Visual Studio -project and solution files. +The action used to generate Microsoft Visual Studio project files. @@ -253,6 +373,63 @@ when using earlier versions of Visual Studio. + + +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. + + + + + +The SCons used in generated Microsoft Visual Studio project files. +The default is the version of SCons being +used to generate the project file. + + + + + +The SCons flags used in generated Microsoft Visual Studio +project files. + + + + + +The default SCons command used in generated Microsoft Visual Studio +project files. + + + + + +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. + + + + + +The action used to generate Microsoft Visual Studio solution files. + + + 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 8792cb09..e3f29942 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 "" -# PROP BASE Intermediate_Dir "" -# PROP BASE Cmd_Line "echo Starting SCons && "" -c "" -C -f SConstruct \Test.exe" -# PROP BASE Rebuild_Opt "-c && echo Starting SCons && "" -c "" -C -f SConstruct \Test.exe" -# PROP BASE Target_File "\Test.exe" +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Cmd_Line "echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +# PROP BASE Rebuild_Opt "-c && echo Starting SCons && "" -c "" -C -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 "" -# PROP Intermediate_Dir "" -# PROP Cmd_Line "echo Starting SCons && "" -c "" -C -f SConstruct \Test.exe" -# PROP Rebuild_Opt "-c && echo Starting SCons && "" -c "" -C -f SConstruct \Test.exe" -# PROP Target_File "\Test.exe" +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Cmd_Line "echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +# PROP Rebuild_Opt "-c && echo Starting SCons && "" -c "" -C -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="" @@ -156,7 +156,7 @@ Microsoft Developer Studio Workspace File, Format Version 6.00 ############################################################################### -Project: "Test"="\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 91445378..409501d6 100644 --- a/test/MSVS/vs-7.0-files.py +++ b/test/MSVS/vs-7.0-files.py @@ -79,28 +79,21 @@ expected_vcprojfile = """\ \t \t\t \t\t\t +\t\t\t\tBuildCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +\t\t\t\tCleanCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct -c Test.exe" +\t\t\t\tRebuildCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +\t\t\t\tOutput="Test.exe"/> \t\t \t \t \t\t -\t\t\t -\t\t\t -\t\t -\t\t \t\t\t \t\t\t \t\t +\t\t +\t\t\t +\t\t\t +\t\t \t\t \t\t @@ -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 5b5799b9..9cbab128 100644 --- a/test/MSVS/vs-7.1-files.py +++ b/test/MSVS/vs-7.1-files.py @@ -79,30 +79,23 @@ expected_vcprojfile = """\ \t \t\t \t\t\t +\t\t\t\tBuildCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +\t\t\t\tCleanCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct -c Test.exe" +\t\t\t\tRebuildCommandLine="echo Starting SCons && "" -c "" -C -f SConstruct Test.exe" +\t\t\t\tOutput="Test.exe"/> \t\t \t \t \t \t \t\t -\t\t\t -\t\t\t -\t\t -\t\t \t\t\t \t\t\t \t\t +\t\t +\t\t\t +\t\t\t +\t\t \t\t \t\t @@ -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() -- 2.26.2