3 Tool-specific initialization for Microsoft Visual Studio project files.
5 There normally shouldn't be any need to import this module directly.
6 It will usually be imported through the generic SCons.Tool.Tool()
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
46 import SCons.Platform.win32
47 import SCons.Script.SConscript
51 ##############################################################################
52 # Below here are the classes and functions for generation of
53 # DSP/DSW/SLN/VCPROJ files.
54 ##############################################################################
57 """Return a string as a string of hex characters.
59 # NOTE: This routine is a method in the Python 2.0 interface
60 # of the native md5 module, but we want SCons to operate all
61 # the way back to at least Python 1.5.2, which doesn't have it.
66 r = r + h[(i >> 4) & 0xF] + h[i & 0xF]
70 s = string.replace(s, "&", "&") # do this first
71 s = string.replace(s, "'", "'")
72 s = string.replace(s, '"', """)
75 external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}'
77 def _generateGUID(slnfile, name):
78 """This generates a dummy GUID for the sln file to use. It is
79 based on the MD5 signatures of the sln filename plus the name of
80 the project. It basically just needs to be unique, and not
81 change with each invocation."""
82 solution = _hexdigest(md5.new(str(slnfile)+str(name)).digest()).upper()
83 # convert most of the signature to GUID form (discard the rest)
84 solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}"
87 version_re = re.compile(r'(\d+\.\d+)(.*)')
89 def msvs_parse_version(s):
91 Split a Visual Studio version, which may in fact be something like
92 '7.0Exp', into is version number (returned as a float) and trailing
95 num, suite = version_re.match(s).groups()
96 return float(num), suite
98 # This is how we re-invoke SCons from inside MSVS Project files.
99 # The problem is that we might have been invoked as either scons.bat
100 # or scons.py. If we were invoked directly as scons.py, then we could
101 # use sys.argv[0] to find the SCons "executable," but that doesn't work
102 # if we were invoked as scons.bat, which uses "python -c" to execute
103 # things and ends up with "-c" as sys.argv[0]. Consequently, we have
104 # the MSVS Project file invoke SCons the same way that scons.bat does,
105 # which works regardless of how we were invoked.
106 def getExecScriptMain(env, xml=None):
107 scons_home = env.get('SCONS_HOME')
108 if not scons_home and os.environ.has_key('SCONS_LIB_DIR'):
109 scons_home = os.environ['SCONS_LIB_DIR']
111 exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home
113 version = SCons.__version__
114 exec_script_main = "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-%(version)s'), join(sys.prefix, 'scons-%(version)s'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons') ] + sys.path; import SCons.Script; SCons.Script.main()" % locals()
116 exec_script_main = xmlify(exec_script_main)
117 return exec_script_main
119 # The string for the Python executable we tell the Project file to use
120 # is either sys.executable or, if an external PYTHON_ROOT environment
121 # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to
122 # pluck the actual executable name from sys.executable).
124 python_root = os.environ['PYTHON_ROOT']
126 python_executable = sys.executable
128 python_executable = os.path.join('$$(PYTHON_ROOT)',
129 os.path.split(sys.executable)[1])
134 def splitFully(path):
135 dir, base = os.path.split(path)
136 if dir and dir != '' and dir != path:
137 return splitFully(dir)+[base]
142 def makeHierarchy(sources):
143 '''Break a list of files into a hierarchy; for each value, if it is a string,
144 then it is a file. If it is a dictionary, it is a folder. The string is
145 the original path of the file.'''
149 path = splitFully(file)
152 for part in path[:-1]:
153 if not dict.has_key(part):
156 dict[path[-1]] = file
158 # print 'Warning: failed to decompose path for '+str(file)
162 """ Base class for DSP generators """
171 def __init__(self, dspfile, source, env):
172 self.dspfile = str(dspfile)
174 get_abspath = dspfile.get_abspath
175 except AttributeError:
176 self.dspabs = os.path.abspath(dspfile)
178 self.dspabs = get_abspath()
180 if not env.has_key('variant'):
181 raise SCons.Errors.InternalError, \
182 "You must specify a 'variant' argument (i.e. 'Debug' or " +\
183 "'Release') to create an MSVSProject."
184 elif SCons.Util.is_String(env['variant']):
185 variants = [env['variant']]
186 elif SCons.Util.is_List(env['variant']):
187 variants = env['variant']
189 if not env.has_key('buildtarget') or env['buildtarget'] == None:
191 elif SCons.Util.is_String(env['buildtarget']):
192 buildtarget = [env['buildtarget']]
193 elif SCons.Util.is_List(env['buildtarget']):
194 if len(env['buildtarget']) != len(variants):
195 raise SCons.Errors.InternalError, \
196 "Sizes of 'buildtarget' and 'variant' lists must be the same."
198 for bt in env['buildtarget']:
199 if SCons.Util.is_String(bt):
200 buildtarget.append(bt)
202 buildtarget.append(bt.get_abspath())
204 buildtarget = [env['buildtarget'].get_abspath()]
205 if len(buildtarget) == 1:
209 buildtarget.append(bt)
211 if not env.has_key('outdir') or env['outdir'] == None:
213 elif SCons.Util.is_String(env['outdir']):
214 outdir = [env['outdir']]
215 elif SCons.Util.is_List(env['outdir']):
216 if len(env['outdir']) != len(variants):
217 raise SCons.Errors.InternalError, \
218 "Sizes of 'outdir' and 'variant' lists must be the same."
220 for s in env['outdir']:
221 if SCons.Util.is_String(s):
224 outdir.append(s.get_abspath())
226 outdir = [env['outdir'].get_abspath()]
233 if not env.has_key('runfile') or env['runfile'] == None:
234 runfile = buildtarget[-1:]
235 elif SCons.Util.is_String(env['runfile']):
236 runfile = [env['runfile']]
237 elif SCons.Util.is_List(env['runfile']):
238 if len(env['runfile']) != len(variants):
239 raise SCons.Errors.InternalError, \
240 "Sizes of 'runfile' and 'variant' lists must be the same."
242 for s in env['runfile']:
243 if SCons.Util.is_String(s):
246 runfile.append(s.get_abspath())
248 runfile = [env['runfile'].get_abspath()]
249 if len(runfile) == 1:
255 self.sconscript = env['MSVSSCONSCRIPT']
257 cmdargs = env.get('cmdargs', '')
261 if self.env.has_key('name'):
262 self.name = self.env['name']
264 self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
265 self.name = self.env.subst(self.name)
275 for n in sourcenames:
281 if env.has_key('nokeep') and env['variant'] != 0:
284 if self.nokeep == 0 and os.path.exists(self.dspabs):
287 for t in zip(sourcenames,self.srcargs):
288 if self.env.has_key(t[1]):
289 if SCons.Util.is_List(self.env[t[1]]):
290 for i in self.env[t[1]]:
291 if not i in self.sources[t[0]]:
292 self.sources[t[0]].append(i)
294 if not self.env[t[1]] in self.sources[t[0]]:
295 self.sources[t[0]].append(self.env[t[1]])
297 for n in sourcenames:
298 self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
300 def AddConfig(variant, buildtarget, outdir, runfile, cmdargs):
302 config.buildtarget = buildtarget
303 config.outdir = outdir
304 config.cmdargs = cmdargs
305 config.runfile = runfile
307 match = re.match('(.*)\|(.*)', variant)
309 config.variant = match.group(1)
310 config.platform = match.group(2)
312 config.variant = variant
313 config.platform = 'Win32'
315 self.configs[variant] = config
316 print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
318 for i in range(len(variants)):
319 AddConfig(variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs)
322 for key in self.configs.keys():
323 platform = self.configs[key].platform
324 if not platform in self.platforms:
325 self.platforms.append(platform)
331 # Microsoft Developer Studio Project File - Name="%(name)s" - Package Owner=<4>
332 # Microsoft Developer Studio Generated Build File, Format Version 6.00
335 # TARGTYPE "Win32 (x86) External Target" 0x0106
337 CFG=%(name)s - Win32 %(confkey)s
338 !MESSAGE This is not a valid makefile. To build this project using NMAKE,
339 !MESSAGE use the Export Makefile command and run
341 !MESSAGE NMAKE /f "%(name)s.mak".
343 !MESSAGE You can specify a configuration when running NMAKE
344 !MESSAGE by defining the macro CFG on the command line. For example:
346 !MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s"
348 !MESSAGE Possible choices for configuration are:
352 class _GenerateV6DSP(_DSPGenerator):
353 """Generates a Project file for MSVS 6.0"""
355 def PrintHeader(self):
356 # pick a default config
357 confkeys = self.configs.keys()
361 confkey = confkeys[0]
363 self.file.write(V6DSPHeader % locals())
365 for kind in confkeys:
366 self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind))
368 self.file.write('!MESSAGE \n\n')
370 def PrintProject(self):
372 self.file.write('# Begin Project\n'
373 '# PROP AllowPerConfigDependencies 0\n'
374 '# PROP Scc_ProjName ""\n'
375 '# PROP Scc_LocalPath ""\n\n')
378 confkeys = self.configs.keys()
380 for kind in confkeys:
381 outdir = self.configs[kind].outdir
382 buildtarget = self.configs[kind].buildtarget
384 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
387 self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
389 env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
390 if not env_has_buildtarget:
391 self.env['MSVSBUILDTARGET'] = buildtarget
393 # have to write this twice, once with the BASE settings, and once without
394 for base in ("BASE ",""):
395 self.file.write('# PROP %sUse_MFC 0\n'
396 '# PROP %sUse_Debug_Libraries ' % (base, base))
397 if kind.lower().find('debug') < 0:
398 self.file.write('0\n')
400 self.file.write('1\n')
401 self.file.write('# PROP %sOutput_Dir "%s"\n'
402 '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir))
403 cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1)
404 self.file.write('# PROP %sCmd_Line "%s"\n'
405 '# PROP %sRebuild_Opt "-c && %s"\n'
406 '# PROP %sTarget_File "%s"\n'
407 '# PROP %sBsc_Name ""\n'
408 '# PROP %sTarget_Dir ""\n'\
409 %(base,cmd,base,cmd,base,buildtarget,base,base))
411 if not env_has_buildtarget:
412 del self.env['MSVSBUILDTARGET']
414 self.file.write('\n!ENDIF\n\n'
415 '# Begin Target\n\n')
416 for kind in confkeys:
417 self.file.write('# Name "%s - Win32 %s"\n' % (name,kind))
418 self.file.write('\n')
420 for kind in confkeys:
422 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
425 self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
426 self.file.write('!ENDIF \n\n')
427 self.PrintSourceFiles()
428 self.file.write('# End Target\n'
432 # now we pickle some data and add it to the file -- MSDEV will ignore it.
433 pdata = pickle.dumps(self.configs,1)
434 pdata = base64.encodestring(pdata)
435 self.file.write(pdata + '\n')
436 pdata = pickle.dumps(self.sources,1)
437 pdata = base64.encodestring(pdata)
438 self.file.write(pdata + '\n')
440 def PrintSourceFiles(self):
441 categories = {'Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat',
442 'Header Files': 'h|hpp|hxx|hm|inl',
443 'Local Headers': 'h|hpp|hxx|hm|inl',
444 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe',
447 cats = categories.keys()
448 cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
450 if not self.sources[kind]:
451 continue # skip empty groups
453 self.file.write('# Begin Group "' + kind + '"\n\n')
454 typelist = categories[kind].replace('|',';')
455 self.file.write('# PROP Default_Filter "' + typelist + '"\n')
457 for file in self.sources[kind]:
458 file = os.path.normpath(file)
459 self.file.write('# Begin Source File\n\n'
460 'SOURCE="' + file + '"\n'
461 '# End Source File\n')
462 self.file.write('# End Group\n')
464 # add the SConscript file outside of the groups
465 self.file.write('# Begin Source File\n\n'
466 'SOURCE="' + str(self.sconscript) + '"\n'
467 '# End Source File\n')
471 dspfile = open(self.dspabs,'r')
473 return # doesn't exist yet, so can't add anything to configs.
475 line = dspfile.readline()
477 if line.find("# End Project") > -1:
479 line = dspfile.readline()
481 line = dspfile.readline()
483 while line and line != '\n':
484 line = dspfile.readline()
487 # OK, we've found our little pickled cache of data.
489 datas = base64.decodestring(datas)
490 data = pickle.loads(datas)
491 except KeyboardInterrupt:
494 return # unable to unpickle any data for some reason
496 self.configs.update(data)
499 line = dspfile.readline()
501 while line and line != '\n':
502 line = dspfile.readline()
505 # OK, we've found our little pickled cache of data.
506 # it has a "# " in front of it, so we strip that.
508 datas = base64.decodestring(datas)
509 data = pickle.loads(datas)
510 except KeyboardInterrupt:
513 return # unable to unpickle any data for some reason
515 self.sources.update(data)
519 self.file = open(self.dspabs,'w')
520 except IOError, detail:
521 raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
528 <?xml version="1.0" encoding = "%(encoding)s"?>
530 \tProjectType="Visual C++"
531 \tVersion="%(versionstr)s"
534 \tKeyword="MakeFileProj">
537 V7DSPConfiguration = """\
539 \t\t\tName="%(variant)s|%(platform)s"
540 \t\t\tOutputDirectory="%(outdir)s"
541 \t\t\tIntermediateDirectory="%(outdir)s"
542 \t\t\tConfigurationType="0"
544 \t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE">
546 \t\t\t\tName="VCNMakeTool"
547 \t\t\t\tBuildCommandLine="%(buildcmd)s"
548 \t\t\t\tCleanCommandLine="%(cleancmd)s"
549 \t\t\t\tRebuildCommandLine="%(rebuildcmd)s"
550 \t\t\t\tOutput="%(runfile)s"/>
555 <?xml version="1.0" encoding="%(encoding)s"?>
557 \tProjectType="Visual C++"
558 \tVersion="%(versionstr)s"
561 \tRootNamespace="%(name)s"
562 \tKeyword="MakeFileProj">
565 V8DSPConfiguration = """\
567 \t\t\tName="%(variant)s|Win32"
568 \t\t\tConfigurationType="0"
570 \t\t\tATLMinimizesCRunTimeLibraryUsage="false"
573 \t\t\t\tName="VCNMakeTool"
574 \t\t\t\tBuildCommandLine="%(buildcmd)s"
575 \t\t\t\tReBuildCommandLine="%(rebuildcmd)s"
576 \t\t\t\tCleanCommandLine="%(cleancmd)s"
577 \t\t\t\tOutput="%(runfile)s"
578 \t\t\t\tPreprocessorDefinitions=""
579 \t\t\t\tIncludeSearchPath=""
580 \t\t\t\tForcedIncludes=""
581 \t\t\t\tAssemblySearchPath=""
582 \t\t\t\tForcedUsingAssemblies=""
583 \t\t\t\tCompileAsManaged=""
587 class _GenerateV7DSP(_DSPGenerator):
588 """Generates a Project file for MSVS .NET"""
590 def __init__(self, dspfile, source, env):
591 _DSPGenerator.__init__(self, dspfile, source, env)
592 self.version = env['MSVS_VERSION']
593 self.version_num, self.suite = msvs_parse_version(self.version)
594 if self.version_num >= 8.0:
595 self.versionstr = '8.00'
596 self.dspheader = V8DSPHeader
597 self.dspconfiguration = V8DSPConfiguration
599 if self.version_num >= 7.1:
600 self.versionstr = '7.10'
602 self.versionstr = '7.00'
603 self.dspheader = V7DSPHeader
604 self.dspconfiguration = V7DSPConfiguration
607 def PrintHeader(self):
609 versionstr = self.versionstr
611 encoding = self.env.subst('$MSVSENCODING')
612 scc_provider = env.get('MSVS_SCC_PROVIDER', '')
613 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
614 scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
615 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
616 project_guid = env.get('MSVS_PROJECT_GUID', '')
617 if self.version_num >= 8.0 and not project_guid:
618 project_guid = _generateGUID(self.dspfile, '')
619 if scc_provider != '':
620 scc_attrs = ('\tProjectGUID="%s"\n'
621 '\tSccProjectName="%s"\n'
622 '\tSccAuxPath="%s"\n'
623 '\tSccLocalPath="%s"\n'
624 '\tSccProvider="%s"' % (project_guid, scc_project_name, scc_aux_path, scc_local_path, scc_provider))
626 scc_attrs = ('\tProjectGUID="%s"\n'
627 '\tSccProjectName="%s"\n'
628 '\tSccLocalPath="%s"' % (project_guid, scc_project_name, scc_local_path))
630 self.file.write(self.dspheader % locals())
632 self.file.write('\t<Platforms>\n')
633 for platform in self.platforms:
636 '\t\t\tName="%s"/>\n' % platform)
637 self.file.write('\t</Platforms>\n')
639 if self.version_num >= 8.0:
640 self.file.write('\t<ToolFiles>\n'
643 def PrintProject(self):
644 self.file.write('\t<Configurations>\n')
646 confkeys = self.configs.keys()
648 for kind in confkeys:
649 variant = self.configs[kind].variant
650 platform = self.configs[kind].platform
651 outdir = self.configs[kind].outdir
652 buildtarget = self.configs[kind].buildtarget
653 runfile = self.configs[kind].runfile
654 cmdargs = self.configs[kind].cmdargs
656 env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
657 if not env_has_buildtarget:
658 self.env['MSVSBUILDTARGET'] = buildtarget
660 starting = 'echo Starting SCons && '
662 cmdargs = ' ' + cmdargs
665 buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) + cmdargs)
666 rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs)
667 cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs)
669 if not env_has_buildtarget:
670 del self.env['MSVSBUILDTARGET']
672 self.file.write(self.dspconfiguration % locals())
674 self.file.write('\t</Configurations>\n')
676 if self.version_num >= 7.1:
677 self.file.write('\t<References>\n'
680 self.PrintSourceFiles()
682 self.file.write('</VisualStudioProject>\n')
685 # now we pickle some data and add it to the file -- MSDEV will ignore it.
686 pdata = pickle.dumps(self.configs,1)
687 pdata = base64.encodestring(pdata)
688 self.file.write('<!-- SCons Data:\n' + pdata + '\n')
689 pdata = pickle.dumps(self.sources,1)
690 pdata = base64.encodestring(pdata)
691 self.file.write(pdata + '-->\n')
693 def PrintSourceFiles(self):
694 categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
695 'Header Files': 'h;hpp;hxx;hm;inl',
696 'Local Headers': 'h;hpp;hxx;hm;inl',
697 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe',
700 self.file.write('\t<Files>\n')
702 cats = categories.keys()
703 cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
704 cats = filter(lambda k, s=self: s.sources[k], cats)
707 self.file.write('\t\t<Filter\n'
709 '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
712 def printSources(hierarchy, commonprefix):
713 sorteditems = hierarchy.items()
714 sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
716 # First folders, then files
717 for key, value in sorteditems:
718 if SCons.Util.is_Dict(value):
719 self.file.write('\t\t\t<Filter\n'
720 '\t\t\t\tName="%s"\n'
721 '\t\t\t\tFilter="">\n' % (key))
722 printSources(value, commonprefix)
723 self.file.write('\t\t\t</Filter>\n')
725 for key, value in sorteditems:
726 if SCons.Util.is_String(value):
729 file = os.path.join(commonprefix, value)
730 file = os.path.normpath(file)
731 self.file.write('\t\t\t<File\n'
732 '\t\t\t\tRelativePath="%s">\n'
733 '\t\t\t</File>\n' % (file))
735 sources = self.sources[kind]
737 # First remove any common prefix
740 s = map(os.path.normpath, sources)
741 cp = os.path.commonprefix(s)
742 if cp and s[0][len(cp)] == os.sep:
743 sources = map(lambda s, l=len(cp): s[l:], sources)
746 hierarchy = makeHierarchy(sources)
747 printSources(hierarchy, commonprefix=commonprefix)
750 self.file.write('\t\t</Filter>\n')
752 # add the SConscript file outside of the groups
753 self.file.write('\t\t<File\n'
754 '\t\t\tRelativePath="%s">\n'
755 '\t\t</File>\n' % str(self.sconscript))
757 self.file.write('\t</Files>\n'
763 dspfile = open(self.dspabs,'r')
765 return # doesn't exist yet, so can't add anything to configs.
767 line = dspfile.readline()
769 if line.find('<!-- SCons Data:') > -1:
771 line = dspfile.readline()
773 line = dspfile.readline()
775 while line and line != '\n':
776 line = dspfile.readline()
779 # OK, we've found our little pickled cache of data.
781 datas = base64.decodestring(datas)
782 data = pickle.loads(datas)
783 except KeyboardInterrupt:
786 return # unable to unpickle any data for some reason
788 self.configs.update(data)
791 line = dspfile.readline()
793 while line and line != '\n':
794 line = dspfile.readline()
797 # OK, we've found our little pickled cache of data.
799 datas = base64.decodestring(datas)
800 data = pickle.loads(datas)
801 except KeyboardInterrupt:
804 return # unable to unpickle any data for some reason
806 self.sources.update(data)
810 self.file = open(self.dspabs,'w')
811 except IOError, detail:
812 raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
819 """ Base class for DSW generators """
820 def __init__(self, dswfile, source, env):
821 self.dswfile = os.path.normpath(str(dswfile))
824 if not env.has_key('projects'):
825 raise SCons.Errors.UserError, \
826 "You must specify a 'projects' argument to create an MSVSSolution."
827 projects = env['projects']
828 if not SCons.Util.is_List(projects):
829 raise SCons.Errors.InternalError, \
830 "The 'projects' argument must be a list of nodes."
831 projects = SCons.Util.flatten(projects)
832 if len(projects) < 1:
833 raise SCons.Errors.UserError, \
834 "You must specify at least one project to create an MSVSSolution."
835 self.dspfiles = map(str, projects)
837 if self.env.has_key('name'):
838 self.name = self.env['name']
840 self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0])
841 self.name = self.env.subst(self.name)
846 class _GenerateV7DSW(_DSWGenerator):
847 """Generates a Solution file for MSVS .NET"""
848 def __init__(self, dswfile, source, env):
849 _DSWGenerator.__init__(self, dswfile, source, env)
852 self.version = self.env['MSVS_VERSION']
853 self.version_num, self.suite = msvs_parse_version(self.version)
854 self.versionstr = '7.00'
855 if self.version_num >= 8.0:
856 self.versionstr = '9.00'
857 elif self.version_num >= 7.1:
858 self.versionstr = '8.00'
859 if self.version_num >= 8.0:
860 self.versionstr = '9.00'
862 if env.has_key('slnguid') and env['slnguid']:
863 self.slnguid = env['slnguid']
865 self.slnguid = _generateGUID(dswfile, self.name)
870 if env.has_key('nokeep') and env['variant'] != 0:
873 if self.nokeep == 0 and os.path.exists(self.dswfile):
876 def AddConfig(variant):
879 match = re.match('(.*)\|(.*)', variant)
881 config.variant = match.group(1)
882 config.platform = match.group(2)
884 config.variant = variant
885 config.platform = 'Win32'
887 self.configs[variant] = config
888 print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
890 if not env.has_key('variant'):
891 raise SCons.Errors.InternalError, \
892 "You must specify a 'variant' argument (i.e. 'Debug' or " +\
893 "'Release') to create an MSVS Solution File."
894 elif SCons.Util.is_String(env['variant']):
895 AddConfig(env['variant'])
896 elif SCons.Util.is_List(env['variant']):
897 for variant in env['variant']:
901 for key in self.configs.keys():
902 platform = self.configs[key].platform
903 if not platform in self.platforms:
904 self.platforms.append(platform)
908 dswfile = open(self.dswfile,'r')
910 return # doesn't exist yet, so can't add anything to configs.
912 line = dswfile.readline()
914 if line[:9] == "EndGlobal":
916 line = dswfile.readline()
918 line = dswfile.readline()
921 line = dswfile.readline()
924 # OK, we've found our little pickled cache of data.
926 datas = base64.decodestring(datas)
927 data = pickle.loads(datas)
928 except KeyboardInterrupt:
931 return # unable to unpickle any data for some reason
933 self.configs.update(data)
935 def PrintSolution(self):
936 """Writes a solution file"""
937 self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr )
938 if self.version_num >= 8.0:
939 self.file.write('# Visual Studio 2005\n')
940 for p in self.dspfiles:
941 name = os.path.basename(p)
942 base, suffix = SCons.Util.splitext(name)
943 if suffix == '.vcproj':
945 guid = _generateGUID(p, '')
946 self.file.write('Project("%s") = "%s", "%s", "%s"\n'
947 % ( external_makefile_guid, name, p, guid ) )
948 if self.version_num >= 7.1 and self.version_num < 8.0:
949 self.file.write('\tProjectSection(ProjectDependencies) = postProject\n'
950 '\tEndProjectSection\n')
951 self.file.write('EndProject\n')
953 self.file.write('Global\n')
956 if env.has_key('MSVS_SCC_PROVIDER'):
957 dspfile_base = os.path.basename(self.dspfile)
958 slnguid = self.slnguid
959 scc_provider = env.get('MSVS_SCC_PROVIDER', '')
960 scc_provider = string.replace(scc_provider, ' ', r'\u0020')
961 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
962 # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
963 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
964 scc_project_base_path = env.get('MSVS_SCC_PROJECT_BASE_PATH', '')
965 # project_guid = env.get('MSVS_PROJECT_GUID', '')
967 self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n'
968 '\t\tSccNumberOfProjects = 2\n'
969 '\t\tSccProjectUniqueName0 = %(dspfile_base)s\n'
970 '\t\tSccLocalPath0 = %(scc_local_path)s\n'
971 '\t\tCanCheckoutShared = true\n'
972 '\t\tSccProjectFilePathRelativizedFromConnection0 = %(scc_project_base_path)s\n'
973 '\t\tSccProjectName1 = %(scc_project_name)s\n'
974 '\t\tSccLocalPath1 = %(scc_local_path)s\n'
975 '\t\tSccProvider1 = %(scc_provider)s\n'
976 '\t\tCanCheckoutShared = true\n'
977 '\t\tSccProjectFilePathRelativizedFromConnection1 = %(scc_project_base_path)s\n'
978 '\t\tSolutionUniqueID = %(slnguid)s\n'
979 '\tEndGlobalSection\n' % locals())
981 if self.version_num >= 8.0:
982 self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
984 self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
986 confkeys = self.configs.keys()
989 for name in confkeys:
990 variant = self.configs[name].variant
991 platform = self.configs[name].platform
992 if self.version_num >= 8.0:
993 self.file.write('\t\t%s|%s = %s|%s\n' % (variant, platform, variant, platform))
995 self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant))
997 self.file.write('\tEndGlobalSection\n')
998 if self.version_num < 7.1:
999 self.file.write('\tGlobalSection(ProjectDependencies) = postSolution\n'
1000 '\tEndGlobalSection\n')
1001 if self.version_num >= 8.0:
1002 self.file.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
1004 self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
1006 for name in confkeys:
1008 variant = self.configs[name].variant
1009 platform = self.configs[name].platform
1010 if self.version_num >= 8.0:
1011 for p in self.dspfiles:
1012 guid = _generateGUID(p, '')
1013 self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
1014 '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
1016 self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
1017 '\t\t%s.%s.Build.0 = %s|%s\n' %(self.slnguid,variant,variant,platform,self.slnguid,variant,variant,platform))
1019 self.file.write('\tEndGlobalSection\n')
1021 if self.version_num >= 8.0:
1022 self.file.write('\tGlobalSection(SolutionProperties) = preSolution\n'
1023 '\t\tHideSolutionNode = FALSE\n'
1024 '\tEndGlobalSection\n')
1026 self.file.write('\tGlobalSection(ExtensibilityGlobals) = postSolution\n'
1027 '\tEndGlobalSection\n'
1028 '\tGlobalSection(ExtensibilityAddIns) = postSolution\n'
1029 '\tEndGlobalSection\n')
1030 self.file.write('EndGlobal\n')
1031 if self.nokeep == 0:
1032 pdata = pickle.dumps(self.configs,1)
1033 pdata = base64.encodestring(pdata)
1034 self.file.write(pdata + '\n')
1038 self.file = open(self.dswfile,'w')
1039 except IOError, detail:
1040 raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
1042 self.PrintSolution()
1046 Microsoft Developer Studio Workspace File, Format Version 6.00
1047 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
1049 ###############################################################################
1051 Project: "%(name)s"="%(dspfile)s" - Package Owner=<4>
1061 ###############################################################################
1073 ###############################################################################
1076 class _GenerateV6DSW(_DSWGenerator):
1077 """Generates a Workspace file for MSVS 6.0"""
1079 def PrintWorkspace(self):
1080 """ writes a DSW file """
1082 dspfile = self.dspfiles[0]
1083 self.file.write(V6DSWHeader % locals())
1087 self.file = open(self.dswfile,'w')
1088 except IOError, detail:
1089 raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
1091 self.PrintWorkspace()
1095 def GenerateDSP(dspfile, source, env):
1096 """Generates a Project file based on the version of MSVS that is being used"""
1099 if env.has_key('MSVS_VERSION'):
1100 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1101 if version_num >= 7.0:
1102 g = _GenerateV7DSP(dspfile, source, env)
1105 g = _GenerateV6DSP(dspfile, source, env)
1108 def GenerateDSW(dswfile, source, env):
1109 """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
1112 if env.has_key('MSVS_VERSION'):
1113 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1114 if version_num >= 7.0:
1115 g = _GenerateV7DSW(dswfile, source, env)
1118 g = _GenerateV6DSW(dswfile, source, env)
1122 ##############################################################################
1123 # Above here are the classes and functions for generation of
1124 # DSP/DSW/SLN/VCPROJ files.
1125 ##############################################################################
1127 def get_default_visualstudio_version(env):
1128 """Returns the version set in the env, or the latest version
1129 installed, if it can find it, or '6.0' if all else fails. Also
1130 updated the environment with what it found."""
1133 versions = [version]
1135 if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
1138 if env['MSVS'].has_key('VERSIONS'):
1139 versions = env['MSVS']['VERSIONS']
1140 elif SCons.Util.can_read_reg:
1141 v = get_visualstudio_versions()
1144 if env.has_key('MSVS_VERSION'):
1145 version = env['MSVS_VERSION']
1147 version = versions[0] #use highest version by default
1149 env['MSVS_VERSION'] = version
1150 env['MSVS']['VERSIONS'] = versions
1151 env['MSVS']['VERSION'] = version
1153 version = env['MSVS']['VERSION']
1157 def get_visualstudio_versions():
1159 Get list of visualstudio versions from the Windows registry.
1160 Returns a list of strings containing version numbers. An empty list
1161 is returned if we were unable to accees the register (for example,
1162 we couldn't import the registry-access module) or the appropriate
1163 registry keys weren't found.
1166 if not SCons.Util.can_read_reg:
1169 HLM = SCons.Util.HKEY_LOCAL_MACHINE
1171 r'Software\Microsoft\VisualStudio' : '',
1172 r'Software\Microsoft\VCExpress' : 'Exp',
1175 for K, suite_suffix in KEYS.items():
1177 k = SCons.Util.RegOpenKeyEx(HLM, K)
1181 p = SCons.Util.RegEnumKey(k,i)
1182 except SCons.Util.RegError:
1185 if not p[0] in '123456789' or p in L:
1187 # Only add this version number if there is a valid
1188 # registry structure (includes the "Setup" key),
1189 # and at least some of the correct directories
1190 # exist. Sometimes VS uninstall leaves around
1191 # some registry/filesystem turds that we don't
1192 # want to trip over. Also, some valid registry
1193 # entries are MSDN entries, not MSVS ('7.1',
1194 # notably), and we want to skip those too.
1196 SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p + '\\Setup')
1197 except SCons.Util.RegError:
1201 idk = SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p)
1202 # This is not always here -- it only exists if the
1203 # user installed into a non-standard location (at
1204 # least in VS6 it works that way -- VS7 seems to
1207 id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1208 except SCons.Util.RegError:
1211 # If the InstallDir key doesn't exist,
1212 # then we check the default locations.
1213 # Note: The IDE's executable is not devenv.exe for VS8 Express.
1214 if not id or not id[0]:
1215 files_dir = SCons.Platform.win32.get_program_files_dir()
1216 version_num, suite = msvs_parse_version(p)
1217 if version_num < 7.0:
1218 vs = r'Microsoft Visual Studio\Common\MSDev98'
1219 elif version_num < 8.0:
1220 vs = r'Microsoft Visual Studio .NET\Common7\IDE'
1222 vs = r'Microsoft Visual Studio 8\Common7\IDE'
1223 id = [ os.path.join(files_dir, vs) ]
1224 if os.path.exists(id[0]):
1225 L.append(p + suite_suffix)
1226 except SCons.Util.RegError:
1232 # This is a hack to get around the fact that certain Visual Studio
1233 # patches place a "6.1" version in the registry, which does not have
1234 # any of the keys we need to find include paths, install directories,
1235 # etc. Therefore we ignore it if it is there, since it throws all
1247 def get_default_visualstudio8_suite(env):
1249 Returns the Visual Studio 2005 suite identifier set in the env, or the
1250 highest suite installed.
1252 if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
1255 if env.has_key('MSVS_SUITE'):
1256 suite = env['MSVS_SUITE'].upper()
1261 if SCons.Util.can_read_reg:
1262 suites = get_visualstudio8_suites()
1264 suite = suites[0] #use best suite by default
1266 env['MSVS_SUITE'] = suite
1267 env['MSVS']['SUITES'] = suites
1268 env['MSVS']['SUITE'] = suite
1272 def get_visualstudio8_suites():
1274 Returns a sorted list of all installed Visual Studio 2005 suites found
1275 in the registry. The highest version should be the first entry in the list.
1280 # Detect Standard, Professional and Team edition
1282 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1283 r'Software\Microsoft\VisualStudio\8.0')
1284 id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1285 editions = { 'PRO': r'Setup\VS\Pro' } # ToDo: add standard and team editions
1286 edition_name = 'STD'
1287 for name, key_suffix in editions.items():
1289 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1290 r'Software\Microsoft\VisualStudio\8.0' + '\\' + key_suffix )
1292 except SCons.Util.RegError:
1294 suites.append(edition_name)
1295 except SCons.Util.RegError:
1298 # Detect Express edition
1300 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1301 r'Software\Microsoft\VCExpress\8.0')
1302 id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1303 suites.append('EXPRESS')
1304 except SCons.Util.RegError:
1309 def is_msvs_installed():
1311 Check the registry for an installed visual studio.
1314 v = SCons.Tool.msvs.get_visualstudio_versions()
1316 except (SCons.Util.RegError, SCons.Errors.InternalError):
1319 def get_msvs_install_dirs(version = None, vs8suite = None):
1321 Get installed locations for various msvc-related products, like the .NET SDK
1322 and the Platform SDK.
1325 if not SCons.Util.can_read_reg:
1329 versions = get_visualstudio_versions()
1331 version = versions[0] #use highest version by default
1335 version_num, suite = msvs_parse_version(version)
1337 K = 'Software\\Microsoft\\VisualStudio\\' + str(version_num)
1338 if (version_num >= 8.0):
1339 if vs8suite == None:
1340 # We've been given no guidance about which Visual Studio 8
1341 # suite to use, so attempt to autodetect.
1342 suites = get_visualstudio8_suites()
1344 vs8suite = suites[0]
1346 if vs8suite == 'EXPRESS':
1347 K = 'Software\\Microsoft\\VCExpress\\' + str(version_num)
1351 if (version_num < 7.0):
1352 key = K + r'\Setup\Microsoft Visual C++\ProductDir'
1354 key = K + r'\Setup\VC\ProductDir'
1356 (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, key)
1357 except SCons.Util.RegError:
1360 # visual studio install dir
1361 if (version_num < 7.0):
1363 (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1364 K + r'\Setup\Microsoft Visual Studio\ProductDir')
1365 except SCons.Util.RegError:
1368 if not rv.has_key('VSINSTALLDIR') or not rv['VSINSTALLDIR']:
1369 if rv.has_key('VCINSTALLDIR') and rv['VCINSTALLDIR']:
1370 rv['VSINSTALLDIR'] = os.path.dirname(rv['VCINSTALLDIR'])
1372 rv['VSINSTALLDIR'] = os.path.join(SCons.Platform.win32.get_program_files_dir(),'Microsoft Visual Studio')
1375 (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1376 K + r'\Setup\VS\ProductDir')
1377 except SCons.Util.RegError:
1380 # .NET framework install dir
1382 (rv['FRAMEWORKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1383 r'Software\Microsoft\.NETFramework\InstallRoot')
1384 except SCons.Util.RegError:
1387 if rv.has_key('FRAMEWORKDIR'):
1388 # try and enumerate the installed versions of the .NET framework.
1389 contents = os.listdir(rv['FRAMEWORKDIR'])
1390 l = re.compile('v[0-9]+.*')
1392 for entry in contents:
1394 versions.append(entry)
1397 # since version numbers aren't really floats...
1402 c = int(bbl[0]) - int(aal[0])
1404 c = int(bbl[1]) - int(aal[1])
1406 c = int(bbl[2]) - int(aal[2])
1409 versions.sort(versrt)
1411 rv['FRAMEWORKVERSIONS'] = versions
1412 # assume that the highest version is the latest version installed
1413 rv['FRAMEWORKVERSION'] = versions[0]
1415 # .NET framework SDK install dir
1417 if rv.has_key('FRAMEWORKVERSION') and rv['FRAMEWORKVERSION'][:4] == 'v1.1':
1418 key = r'Software\Microsoft\.NETFramework\sdkInstallRootv1.1'
1420 key = r'Software\Microsoft\.NETFramework\sdkInstallRoot'
1422 (rv['FRAMEWORKSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,key)
1424 except SCons.Util.RegError:
1427 # MS Platform SDK dir
1429 (rv['PLATFORMSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1430 r'Software\Microsoft\MicrosoftSDK\Directories\Install Dir')
1431 except SCons.Util.RegError:
1434 if rv.has_key('PLATFORMSDKDIR'):
1435 # if we have a platform SDK, try and get some info on it.
1438 loc = r'Software\Microsoft\MicrosoftSDK\InstalledSDKs'
1439 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,loc)
1443 key = SCons.Util.RegEnumKey(k,i)
1444 sdk = SCons.Util.RegOpenKeyEx(k,key)
1451 (vk,vv,t) = SCons.Util.RegEnumValue(sdk,j)
1452 if vk.lower() == 'keyword':
1454 if vk.lower() == 'propagation_date':
1456 if vk.lower() == 'version':
1459 except SCons.Util.RegError:
1462 vers[name] = (date, version)
1464 except SCons.Util.RegError:
1466 rv['PLATFORMSDK_MODULES'] = vers
1467 except SCons.Util.RegError:
1472 def GetMSVSProjectSuffix(target, source, env, for_signature):
1473 return env['MSVS']['PROJECTSUFFIX']
1475 def GetMSVSSolutionSuffix(target, source, env, for_signature):
1476 return env['MSVS']['SOLUTIONSUFFIX']
1478 def GenerateProject(target, source, env):
1479 # generate the dsp file, according to the version of MSVS.
1480 builddspfile = target[0]
1481 dspfile = builddspfile.srcnode()
1483 # this detects whether or not we're using a BuildDir
1484 if not dspfile is builddspfile:
1486 bdsp = open(str(builddspfile), "w+")
1487 except IOError, detail:
1488 print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
1491 bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
1493 GenerateDSP(dspfile, source, env)
1495 if env.get('auto_build_solution', 1):
1496 builddswfile = target[1]
1497 dswfile = builddswfile.srcnode()
1499 if not dswfile is builddswfile:
1502 bdsw = open(str(builddswfile), "w+")
1503 except IOError, detail:
1504 print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
1507 bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
1509 GenerateDSW(dswfile, source, env)
1511 def GenerateSolution(target, source, env):
1512 GenerateDSW(target[0], source, env)
1514 def projectEmitter(target, source, env):
1515 """Sets up the DSP dependencies."""
1517 # todo: Not sure what sets source to what user has passed as target,
1518 # but this is what happens. When that is fixed, we also won't have
1519 # to make the user always append env['MSVSPROJECTSUFFIX'] to target.
1520 if source[0] == target[0]:
1523 # make sure the suffix is correct for the version of MSVS we're running.
1524 (base, suff) = SCons.Util.splitext(str(target[0]))
1525 suff = env.subst('$MSVSPROJECTSUFFIX')
1526 target[0] = base + suff
1529 source = 'prj_inputs:'
1530 source = source + env.subst('$MSVSSCONSCOM', 1)
1531 source = source + env.subst('$MSVSENCODING', 1)
1533 if env.has_key('buildtarget') and env['buildtarget'] != None:
1534 if SCons.Util.is_String(env['buildtarget']):
1535 source = source + ' "%s"' % env['buildtarget']
1536 elif SCons.Util.is_List(env['buildtarget']):
1537 for bt in env['buildtarget']:
1538 if SCons.Util.is_String(bt):
1539 source = source + ' "%s"' % bt
1541 try: source = source + ' "%s"' % bt.get_abspath()
1542 except AttributeError: raise SCons.Errors.InternalError, \
1543 "buildtarget can be a string, a node, a list of strings or nodes, or None"
1545 try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
1546 except AttributeError: raise SCons.Errors.InternalError, \
1547 "buildtarget can be a string, a node, a list of strings or nodes, or None"
1549 if env.has_key('outdir') and env['outdir'] != None:
1550 if SCons.Util.is_String(env['outdir']):
1551 source = source + ' "%s"' % env['outdir']
1552 elif SCons.Util.is_List(env['outdir']):
1553 for s in env['outdir']:
1554 if SCons.Util.is_String(s):
1555 source = source + ' "%s"' % s
1557 try: source = source + ' "%s"' % s.get_abspath()
1558 except AttributeError: raise SCons.Errors.InternalError, \
1559 "outdir can be a string, a node, a list of strings or nodes, or None"
1561 try: source = source + ' "%s"' % env['outdir'].get_abspath()
1562 except AttributeError: raise SCons.Errors.InternalError, \
1563 "outdir can be a string, a node, a list of strings or nodes, or None"
1565 if env.has_key('name'):
1566 if SCons.Util.is_String(env['name']):
1567 source = source + ' "%s"' % env['name']
1569 raise SCons.Errors.InternalError, "name must be a string"
1571 if env.has_key('variant'):
1572 if SCons.Util.is_String(env['variant']):
1573 source = source + ' "%s"' % env['variant']
1574 elif SCons.Util.is_List(env['variant']):
1575 for variant in env['variant']:
1576 if SCons.Util.is_String(variant):
1577 source = source + ' "%s"' % variant
1579 raise SCons.Errors.InternalError, "name must be a string or a list of strings"
1581 raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
1583 raise SCons.Errors.InternalError, "variant must be specified"
1585 for s in _DSPGenerator.srcargs:
1587 if SCons.Util.is_String(env[s]):
1588 source = source + ' "%s' % env[s]
1589 elif SCons.Util.is_List(env[s]):
1591 if SCons.Util.is_String(t):
1592 source = source + ' "%s"' % t
1594 raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
1596 raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
1598 source = source + ' "%s"' % str(target[0])
1599 source = [SCons.Node.Python.Value(source)]
1601 targetlist = [target[0]]
1604 if env.get('auto_build_solution', 1):
1605 env['projects'] = targetlist
1606 t, s = solutionEmitter(target, target, env)
1607 targetlist = targetlist + t
1609 return (targetlist, sourcelist)
1611 def solutionEmitter(target, source, env):
1612 """Sets up the DSW dependencies."""
1614 # todo: Not sure what sets source to what user has passed as target,
1615 # but this is what happens. When that is fixed, we also won't have
1616 # to make the user always append env['MSVSSOLUTIONSUFFIX'] to target.
1617 if source[0] == target[0]:
1620 # make sure the suffix is correct for the version of MSVS we're running.
1621 (base, suff) = SCons.Util.splitext(str(target[0]))
1622 suff = env.subst('$MSVSSOLUTIONSUFFIX')
1623 target[0] = base + suff
1626 source = 'sln_inputs:'
1628 if env.has_key('name'):
1629 if SCons.Util.is_String(env['name']):
1630 source = source + ' "%s"' % env['name']
1632 raise SCons.Errors.InternalError, "name must be a string"
1634 if env.has_key('variant'):
1635 if SCons.Util.is_String(env['variant']):
1636 source = source + ' "%s"' % env['variant']
1637 elif SCons.Util.is_List(env['variant']):
1638 for variant in env['variant']:
1639 if SCons.Util.is_String(variant):
1640 source = source + ' "%s"' % variant
1642 raise SCons.Errors.InternalError, "name must be a string or a list of strings"
1644 raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
1646 raise SCons.Errors.InternalError, "variant must be specified"
1648 if env.has_key('slnguid'):
1649 if SCons.Util.is_String(env['slnguid']):
1650 source = source + ' "%s"' % env['slnguid']
1652 raise SCons.Errors.InternalError, "slnguid must be a string"
1654 if env.has_key('projects'):
1655 if SCons.Util.is_String(env['projects']):
1656 source = source + ' "%s"' % env['projects']
1657 elif SCons.Util.is_List(env['projects']):
1658 for t in env['projects']:
1659 if SCons.Util.is_String(t):
1660 source = source + ' "%s"' % t
1662 source = source + ' "%s"' % str(target[0])
1663 source = [SCons.Node.Python.Value(source)]
1665 return ([target[0]], source)
1667 projectAction = SCons.Action.Action(GenerateProject, None)
1669 solutionAction = SCons.Action.Action(GenerateSolution, None)
1671 projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM',
1672 suffix = '$MSVSPROJECTSUFFIX',
1673 emitter = projectEmitter)
1675 solutionBuilder = SCons.Builder.Builder(action = '$MSVSSOLUTIONCOM',
1676 suffix = '$MSVSSOLUTIONSUFFIX',
1677 emitter = solutionEmitter)
1679 default_MSVS_SConscript = None
1682 """Add Builders and construction variables for Microsoft Visual
1683 Studio project files to an Environment."""
1685 env['BUILDERS']['MSVSProject']
1687 env['BUILDERS']['MSVSProject'] = projectBuilder
1690 env['BUILDERS']['MSVSSolution']
1692 env['BUILDERS']['MSVSSolution'] = solutionBuilder
1694 env['MSVSPROJECTCOM'] = projectAction
1695 env['MSVSSOLUTIONCOM'] = solutionAction
1697 if SCons.Script.call_stack:
1698 # XXX Need to find a way to abstract this; the build engine
1699 # shouldn't depend on anything in SCons.Script.
1700 env['MSVSSCONSCRIPT'] = SCons.Script.call_stack[0].sconscript
1702 global default_MSVS_SConscript
1703 if default_MSVS_SConscript is None:
1704 default_MSVS_SConscript = env.File('SConstruct')
1705 env['MSVSSCONSCRIPT'] = default_MSVS_SConscript
1707 env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
1708 env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.abspath}" -f ${MSVSSCONSCRIPT.name}'
1709 env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
1710 env['MSVSBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
1711 env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM $MSVSBUILDTARGET'
1712 env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c $MSVSBUILDTARGET'
1713 env['MSVSENCODING'] = 'Windows-1252'
1716 version = get_default_visualstudio_version(env)
1717 # keep a record of some of the MSVS info so the user can use it.
1718 dirs = get_msvs_install_dirs(version)
1719 env['MSVS'].update(dirs)
1720 except (SCons.Util.RegError, SCons.Errors.InternalError):
1721 # we don't care if we can't do this -- if we can't, it's
1722 # because we don't have access to the registry, or because the
1723 # tools aren't installed. In either case, the user will have to
1724 # find them on their own.
1727 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1728 if (version_num < 7.0):
1729 env['MSVS']['PROJECTSUFFIX'] = '.dsp'
1730 env['MSVS']['SOLUTIONSUFFIX'] = '.dsw'
1732 env['MSVS']['PROJECTSUFFIX'] = '.vcproj'
1733 env['MSVS']['SOLUTIONSUFFIX'] = '.sln'
1735 env['GET_MSVSPROJECTSUFFIX'] = GetMSVSProjectSuffix
1736 env['GET_MSVSSOLUTIONSUFFIX'] = GetMSVSSolutionSuffix
1737 env['MSVSPROJECTSUFFIX'] = '${GET_MSVSPROJECTSUFFIX}'
1738 env['MSVSSOLUTIONSUFFIX'] = '${GET_MSVSSOLUTIONSUFFIX}'
1739 env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
1743 v = SCons.Tool.msvs.get_visualstudio_versions()
1744 except (SCons.Util.RegError, SCons.Errors.InternalError):
1749 if env.has_key('MSVS_VERSION'):
1750 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1751 if version_num >= 7.0:
1752 return env.Detect('devenv')
1754 return env.Detect('msdev')
1756 # there's at least one version of MSVS installed.