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()
12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
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__ = "src/engine/SCons/Tool/msvs.py 3842 2008/12/20 22:59:52 scons"
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."""
83 m.update(str(slnfile) + str(name))
85 #solution = m.hexdigest().upper()
86 solution = string.upper(_hexdigest(m.digest()))
87 # convert most of the signature to GUID form (discard the rest)
88 solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16] + "-" + solution[16:20] + "-" + solution[20:32] + "}"
91 version_re = re.compile(r'(\d+\.\d+)(.*)')
93 def msvs_parse_version(s):
95 Split a Visual Studio version, which may in fact be something like
96 '7.0Exp', into is version number (returned as a float) and trailing
99 num, suite = version_re.match(s).groups()
100 return float(num), suite
102 # This is how we re-invoke SCons from inside MSVS Project files.
103 # The problem is that we might have been invoked as either scons.bat
104 # or scons.py. If we were invoked directly as scons.py, then we could
105 # use sys.argv[0] to find the SCons "executable," but that doesn't work
106 # if we were invoked as scons.bat, which uses "python -c" to execute
107 # things and ends up with "-c" as sys.argv[0]. Consequently, we have
108 # the MSVS Project file invoke SCons the same way that scons.bat does,
109 # which works regardless of how we were invoked.
110 def getExecScriptMain(env, xml=None):
111 scons_home = env.get('SCONS_HOME')
112 if not scons_home and os.environ.has_key('SCONS_LIB_DIR'):
113 scons_home = os.environ['SCONS_LIB_DIR']
115 exec_script_main = "from os.path import join; import sys; sys.path = [ r'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home
117 version = SCons.__version__
118 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()
120 exec_script_main = xmlify(exec_script_main)
121 return exec_script_main
123 # The string for the Python executable we tell the Project file to use
124 # is either sys.executable or, if an external PYTHON_ROOT environment
125 # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to
126 # pluck the actual executable name from sys.executable).
128 python_root = os.environ['PYTHON_ROOT']
130 python_executable = sys.executable
132 python_executable = os.path.join('$$(PYTHON_ROOT)',
133 os.path.split(sys.executable)[1])
138 def splitFully(path):
139 dir, base = os.path.split(path)
140 if dir and dir != '' and dir != path:
141 return splitFully(dir)+[base]
146 def makeHierarchy(sources):
147 '''Break a list of files into a hierarchy; for each value, if it is a string,
148 then it is a file. If it is a dictionary, it is a folder. The string is
149 the original path of the file.'''
153 path = splitFully(file)
156 for part in path[:-1]:
157 if not dict.has_key(part):
160 dict[path[-1]] = file
162 # print 'Warning: failed to decompose path for '+str(file)
166 """ Base class for DSP generators """
175 def __init__(self, dspfile, source, env):
176 self.dspfile = str(dspfile)
178 get_abspath = dspfile.get_abspath
179 except AttributeError:
180 self.dspabs = os.path.abspath(dspfile)
182 self.dspabs = get_abspath()
184 if not env.has_key('variant'):
185 raise SCons.Errors.InternalError, \
186 "You must specify a 'variant' argument (i.e. 'Debug' or " +\
187 "'Release') to create an MSVSProject."
188 elif SCons.Util.is_String(env['variant']):
189 variants = [env['variant']]
190 elif SCons.Util.is_List(env['variant']):
191 variants = env['variant']
193 if not env.has_key('buildtarget') or env['buildtarget'] == None:
195 elif SCons.Util.is_String(env['buildtarget']):
196 buildtarget = [env['buildtarget']]
197 elif SCons.Util.is_List(env['buildtarget']):
198 if len(env['buildtarget']) != len(variants):
199 raise SCons.Errors.InternalError, \
200 "Sizes of 'buildtarget' and 'variant' lists must be the same."
202 for bt in env['buildtarget']:
203 if SCons.Util.is_String(bt):
204 buildtarget.append(bt)
206 buildtarget.append(bt.get_abspath())
208 buildtarget = [env['buildtarget'].get_abspath()]
209 if len(buildtarget) == 1:
213 buildtarget.append(bt)
215 if not env.has_key('outdir') or env['outdir'] == None:
217 elif SCons.Util.is_String(env['outdir']):
218 outdir = [env['outdir']]
219 elif SCons.Util.is_List(env['outdir']):
220 if len(env['outdir']) != len(variants):
221 raise SCons.Errors.InternalError, \
222 "Sizes of 'outdir' and 'variant' lists must be the same."
224 for s in env['outdir']:
225 if SCons.Util.is_String(s):
228 outdir.append(s.get_abspath())
230 outdir = [env['outdir'].get_abspath()]
237 if not env.has_key('runfile') or env['runfile'] == None:
238 runfile = buildtarget[-1:]
239 elif SCons.Util.is_String(env['runfile']):
240 runfile = [env['runfile']]
241 elif SCons.Util.is_List(env['runfile']):
242 if len(env['runfile']) != len(variants):
243 raise SCons.Errors.InternalError, \
244 "Sizes of 'runfile' and 'variant' lists must be the same."
246 for s in env['runfile']:
247 if SCons.Util.is_String(s):
250 runfile.append(s.get_abspath())
252 runfile = [env['runfile'].get_abspath()]
253 if len(runfile) == 1:
259 self.sconscript = env['MSVSSCONSCRIPT']
261 cmdargs = env.get('cmdargs', '')
265 if self.env.has_key('name'):
266 self.name = self.env['name']
268 self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0])
269 self.name = self.env.subst(self.name)
279 for n in sourcenames:
285 if env.has_key('nokeep') and env['variant'] != 0:
288 if self.nokeep == 0 and os.path.exists(self.dspabs):
291 for t in zip(sourcenames,self.srcargs):
292 if self.env.has_key(t[1]):
293 if SCons.Util.is_List(self.env[t[1]]):
294 for i in self.env[t[1]]:
295 if not i in self.sources[t[0]]:
296 self.sources[t[0]].append(i)
298 if not self.env[t[1]] in self.sources[t[0]]:
299 self.sources[t[0]].append(self.env[t[1]])
301 for n in sourcenames:
303 #self.sources[n].sort(lambda a, b: cmp(a.lower(), b.lower()))
304 self.sources[n].sort(lambda a, b: cmp(string.lower(a), string.lower(b)))
306 def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspfile=dspfile):
308 config.buildtarget = buildtarget
309 config.outdir = outdir
310 config.cmdargs = cmdargs
311 config.runfile = runfile
313 match = re.match('(.*)\|(.*)', variant)
315 config.variant = match.group(1)
316 config.platform = match.group(2)
318 config.variant = variant
319 config.platform = 'Win32'
321 self.configs[variant] = config
322 print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dspfile) + "'"
324 for i in range(len(variants)):
325 AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i], cmdargs)
328 for key in self.configs.keys():
329 platform = self.configs[key].platform
330 if not platform in self.platforms:
331 self.platforms.append(platform)
337 # Microsoft Developer Studio Project File - Name="%(name)s" - Package Owner=<4>
338 # Microsoft Developer Studio Generated Build File, Format Version 6.00
341 # TARGTYPE "Win32 (x86) External Target" 0x0106
343 CFG=%(name)s - Win32 %(confkey)s
344 !MESSAGE This is not a valid makefile. To build this project using NMAKE,
345 !MESSAGE use the Export Makefile command and run
347 !MESSAGE NMAKE /f "%(name)s.mak".
349 !MESSAGE You can specify a configuration when running NMAKE
350 !MESSAGE by defining the macro CFG on the command line. For example:
352 !MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s"
354 !MESSAGE Possible choices for configuration are:
358 class _GenerateV6DSP(_DSPGenerator):
359 """Generates a Project file for MSVS 6.0"""
361 def PrintHeader(self):
362 # pick a default config
363 confkeys = self.configs.keys()
367 confkey = confkeys[0]
369 self.file.write(V6DSPHeader % locals())
371 for kind in confkeys:
372 self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) External Target")\n' % (name, kind))
374 self.file.write('!MESSAGE \n\n')
376 def PrintProject(self):
378 self.file.write('# Begin Project\n'
379 '# PROP AllowPerConfigDependencies 0\n'
380 '# PROP Scc_ProjName ""\n'
381 '# PROP Scc_LocalPath ""\n\n')
384 confkeys = self.configs.keys()
386 for kind in confkeys:
387 outdir = self.configs[kind].outdir
388 buildtarget = self.configs[kind].buildtarget
390 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
393 self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name, kind))
395 env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
396 if not env_has_buildtarget:
397 self.env['MSVSBUILDTARGET'] = buildtarget
399 # have to write this twice, once with the BASE settings, and once without
400 for base in ("BASE ",""):
401 self.file.write('# PROP %sUse_MFC 0\n'
402 '# PROP %sUse_Debug_Libraries ' % (base, base))
404 #if kind.lower().find('debug') < 0:
405 if string.find(string.lower(kind), 'debug') < 0:
406 self.file.write('0\n')
408 self.file.write('1\n')
409 self.file.write('# PROP %sOutput_Dir "%s"\n'
410 '# PROP %sIntermediate_Dir "%s"\n' % (base,outdir,base,outdir))
411 cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM', 1)
412 self.file.write('# PROP %sCmd_Line "%s"\n'
413 '# PROP %sRebuild_Opt "-c && %s"\n'
414 '# PROP %sTarget_File "%s"\n'
415 '# PROP %sBsc_Name ""\n'
416 '# PROP %sTarget_Dir ""\n'\
417 %(base,cmd,base,cmd,base,buildtarget,base,base))
419 if not env_has_buildtarget:
420 del self.env['MSVSBUILDTARGET']
422 self.file.write('\n!ENDIF\n\n'
423 '# Begin Target\n\n')
424 for kind in confkeys:
425 self.file.write('# Name "%s - Win32 %s"\n' % (name,kind))
426 self.file.write('\n')
428 for kind in confkeys:
430 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
433 self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,kind))
434 self.file.write('!ENDIF \n\n')
435 self.PrintSourceFiles()
436 self.file.write('# End Target\n'
440 # now we pickle some data and add it to the file -- MSDEV will ignore it.
441 pdata = pickle.dumps(self.configs,1)
442 pdata = base64.encodestring(pdata)
443 self.file.write(pdata + '\n')
444 pdata = pickle.dumps(self.sources,1)
445 pdata = base64.encodestring(pdata)
446 self.file.write(pdata + '\n')
448 def PrintSourceFiles(self):
449 categories = {'Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat',
450 'Header Files': 'h|hpp|hxx|hm|inl',
451 'Local Headers': 'h|hpp|hxx|hm|inl',
452 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rtf|gif|jpg|jpeg|jpe',
455 cats = categories.keys()
457 #cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
458 cats.sort(lambda a, b: cmp(string.lower(a), string.lower(b)))
460 if not self.sources[kind]:
461 continue # skip empty groups
463 self.file.write('# Begin Group "' + kind + '"\n\n')
465 #typelist = categories[kind].replace('|', ';')
466 typelist = string.replace(categories[kind], '|', ';')
467 self.file.write('# PROP Default_Filter "' + typelist + '"\n')
469 for file in self.sources[kind]:
470 file = os.path.normpath(file)
471 self.file.write('# Begin Source File\n\n'
472 'SOURCE="' + file + '"\n'
473 '# End Source File\n')
474 self.file.write('# End Group\n')
476 # add the SConscript file outside of the groups
477 self.file.write('# Begin Source File\n\n'
478 'SOURCE="' + str(self.sconscript) + '"\n'
479 '# End Source File\n')
483 dspfile = open(self.dspabs,'r')
485 return # doesn't exist yet, so can't add anything to configs.
487 line = dspfile.readline()
490 #if line.find("# End Project") > -1:
491 if string.find(line, "# End Project") > -1:
493 line = dspfile.readline()
495 line = dspfile.readline()
497 while line and line != '\n':
498 line = dspfile.readline()
501 # OK, we've found our little pickled cache of data.
503 datas = base64.decodestring(datas)
504 data = pickle.loads(datas)
505 except KeyboardInterrupt:
508 return # unable to unpickle any data for some reason
510 self.configs.update(data)
513 line = dspfile.readline()
515 while line and line != '\n':
516 line = dspfile.readline()
519 # OK, we've found our little pickled cache of data.
520 # it has a "# " in front of it, so we strip that.
522 datas = base64.decodestring(datas)
523 data = pickle.loads(datas)
524 except KeyboardInterrupt:
527 return # unable to unpickle any data for some reason
529 self.sources.update(data)
533 self.file = open(self.dspabs,'w')
534 except IOError, detail:
535 raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
542 <?xml version="1.0" encoding = "%(encoding)s"?>
544 \tProjectType="Visual C++"
545 \tVersion="%(versionstr)s"
548 \tKeyword="MakeFileProj">
551 V7DSPConfiguration = """\
553 \t\t\tName="%(variant)s|%(platform)s"
554 \t\t\tOutputDirectory="%(outdir)s"
555 \t\t\tIntermediateDirectory="%(outdir)s"
556 \t\t\tConfigurationType="0"
558 \t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE">
560 \t\t\t\tName="VCNMakeTool"
561 \t\t\t\tBuildCommandLine="%(buildcmd)s"
562 \t\t\t\tCleanCommandLine="%(cleancmd)s"
563 \t\t\t\tRebuildCommandLine="%(rebuildcmd)s"
564 \t\t\t\tOutput="%(runfile)s"/>
569 <?xml version="1.0" encoding="%(encoding)s"?>
571 \tProjectType="Visual C++"
572 \tVersion="%(versionstr)s"
575 \tRootNamespace="%(name)s"
576 \tKeyword="MakeFileProj">
579 V8DSPConfiguration = """\
581 \t\t\tName="%(variant)s|Win32"
582 \t\t\tConfigurationType="0"
584 \t\t\tATLMinimizesCRunTimeLibraryUsage="false"
587 \t\t\t\tName="VCNMakeTool"
588 \t\t\t\tBuildCommandLine="%(buildcmd)s"
589 \t\t\t\tReBuildCommandLine="%(rebuildcmd)s"
590 \t\t\t\tCleanCommandLine="%(cleancmd)s"
591 \t\t\t\tOutput="%(runfile)s"
592 \t\t\t\tPreprocessorDefinitions=""
593 \t\t\t\tIncludeSearchPath=""
594 \t\t\t\tForcedIncludes=""
595 \t\t\t\tAssemblySearchPath=""
596 \t\t\t\tForcedUsingAssemblies=""
597 \t\t\t\tCompileAsManaged=""
601 class _GenerateV7DSP(_DSPGenerator):
602 """Generates a Project file for MSVS .NET"""
604 def __init__(self, dspfile, source, env):
605 _DSPGenerator.__init__(self, dspfile, source, env)
606 self.version = env['MSVS_VERSION']
607 self.version_num, self.suite = msvs_parse_version(self.version)
608 if self.version_num >= 8.0:
609 self.versionstr = '8.00'
610 self.dspheader = V8DSPHeader
611 self.dspconfiguration = V8DSPConfiguration
613 if self.version_num >= 7.1:
614 self.versionstr = '7.10'
616 self.versionstr = '7.00'
617 self.dspheader = V7DSPHeader
618 self.dspconfiguration = V7DSPConfiguration
621 def PrintHeader(self):
623 versionstr = self.versionstr
625 encoding = self.env.subst('$MSVSENCODING')
626 scc_provider = env.get('MSVS_SCC_PROVIDER', '')
627 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
628 scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
629 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
630 project_guid = env.get('MSVS_PROJECT_GUID', '')
631 if self.version_num >= 8.0 and not project_guid:
632 project_guid = _generateGUID(self.dspfile, '')
633 if scc_provider != '':
634 scc_attrs = ('\tProjectGUID="%s"\n'
635 '\tSccProjectName="%s"\n'
636 '\tSccAuxPath="%s"\n'
637 '\tSccLocalPath="%s"\n'
638 '\tSccProvider="%s"' % (project_guid, scc_project_name, scc_aux_path, scc_local_path, scc_provider))
640 scc_attrs = ('\tProjectGUID="%s"\n'
641 '\tSccProjectName="%s"\n'
642 '\tSccLocalPath="%s"' % (project_guid, scc_project_name, scc_local_path))
644 self.file.write(self.dspheader % locals())
646 self.file.write('\t<Platforms>\n')
647 for platform in self.platforms:
650 '\t\t\tName="%s"/>\n' % platform)
651 self.file.write('\t</Platforms>\n')
653 if self.version_num >= 8.0:
654 self.file.write('\t<ToolFiles>\n'
657 def PrintProject(self):
658 self.file.write('\t<Configurations>\n')
660 confkeys = self.configs.keys()
662 for kind in confkeys:
663 variant = self.configs[kind].variant
664 platform = self.configs[kind].platform
665 outdir = self.configs[kind].outdir
666 buildtarget = self.configs[kind].buildtarget
667 runfile = self.configs[kind].runfile
668 cmdargs = self.configs[kind].cmdargs
670 env_has_buildtarget = self.env.has_key('MSVSBUILDTARGET')
671 if not env_has_buildtarget:
672 self.env['MSVSBUILDTARGET'] = buildtarget
674 starting = 'echo Starting SCons && '
676 cmdargs = ' ' + cmdargs
679 buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) + cmdargs)
680 rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1) + cmdargs)
681 cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) + cmdargs)
683 if not env_has_buildtarget:
684 del self.env['MSVSBUILDTARGET']
686 self.file.write(self.dspconfiguration % locals())
688 self.file.write('\t</Configurations>\n')
690 if self.version_num >= 7.1:
691 self.file.write('\t<References>\n'
694 self.PrintSourceFiles()
696 self.file.write('</VisualStudioProject>\n')
699 # now we pickle some data and add it to the file -- MSDEV will ignore it.
700 pdata = pickle.dumps(self.configs,1)
701 pdata = base64.encodestring(pdata)
702 self.file.write('<!-- SCons Data:\n' + pdata + '\n')
703 pdata = pickle.dumps(self.sources,1)
704 pdata = base64.encodestring(pdata)
705 self.file.write(pdata + '-->\n')
707 def printSources(self, hierarchy, commonprefix):
708 sorteditems = hierarchy.items()
710 #sorteditems.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
711 sorteditems.sort(lambda a, b: cmp(string.lower(a[0]), string.lower(b[0])))
713 # First folders, then files
714 for key, value in sorteditems:
715 if SCons.Util.is_Dict(value):
716 self.file.write('\t\t\t<Filter\n'
717 '\t\t\t\tName="%s"\n'
718 '\t\t\t\tFilter="">\n' % (key))
719 self.printSources(value, commonprefix)
720 self.file.write('\t\t\t</Filter>\n')
722 for key, value in sorteditems:
723 if SCons.Util.is_String(value):
726 file = os.path.join(commonprefix, value)
727 file = os.path.normpath(file)
728 self.file.write('\t\t\t<File\n'
729 '\t\t\t\tRelativePath="%s">\n'
730 '\t\t\t</File>\n' % (file))
732 def PrintSourceFiles(self):
733 categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat',
734 'Header Files': 'h;hpp;hxx;hm;inl',
735 'Local Headers': 'h;hpp;hxx;hm;inl',
736 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe',
739 self.file.write('\t<Files>\n')
741 cats = categories.keys()
743 #cats.sort(lambda a, b: cmp(a.lower(), b.lower()))
744 cats.sort(lambda a, b: cmp(string.lower(a), string.lower(b)))
745 cats = filter(lambda k, s=self: s.sources[k], cats)
748 self.file.write('\t\t<Filter\n'
750 '\t\t\tFilter="%s">\n' % (kind, categories[kind]))
752 sources = self.sources[kind]
754 # First remove any common prefix
757 s = map(os.path.normpath, sources)
758 # take the dirname because the prefix may include parts
759 # of the filenames (e.g. if you have 'dir\abcd' and
760 # 'dir\acde' then the cp will be 'dir\a' )
761 cp = os.path.dirname( os.path.commonprefix(s) )
762 if cp and s[0][len(cp)] == os.sep:
763 # +1 because the filename starts after the separator
764 sources = map(lambda s, l=len(cp)+1: s[l:], sources)
766 elif len(sources) == 1:
767 commonprefix = os.path.dirname( sources[0] )
768 sources[0] = os.path.basename( sources[0] )
770 hierarchy = makeHierarchy(sources)
771 self.printSources(hierarchy, commonprefix=commonprefix)
774 self.file.write('\t\t</Filter>\n')
776 # add the SConscript file outside of the groups
777 self.file.write('\t\t<File\n'
778 '\t\t\tRelativePath="%s">\n'
779 '\t\t</File>\n' % str(self.sconscript))
781 self.file.write('\t</Files>\n'
787 dspfile = open(self.dspabs,'r')
789 return # doesn't exist yet, so can't add anything to configs.
791 line = dspfile.readline()
794 #if line.find('<!-- SCons Data:') > -1:
795 if string.find(line, '<!-- SCons Data:') > -1:
797 line = dspfile.readline()
799 line = dspfile.readline()
801 while line and line != '\n':
802 line = dspfile.readline()
805 # OK, we've found our little pickled cache of data.
807 datas = base64.decodestring(datas)
808 data = pickle.loads(datas)
809 except KeyboardInterrupt:
812 return # unable to unpickle any data for some reason
814 self.configs.update(data)
817 line = dspfile.readline()
819 while line and line != '\n':
820 line = dspfile.readline()
823 # OK, we've found our little pickled cache of data.
825 datas = base64.decodestring(datas)
826 data = pickle.loads(datas)
827 except KeyboardInterrupt:
830 return # unable to unpickle any data for some reason
832 self.sources.update(data)
836 self.file = open(self.dspabs,'w')
837 except IOError, detail:
838 raise SCons.Errors.InternalError, 'Unable to open "' + self.dspabs + '" for writing:' + str(detail)
845 """ Base class for DSW generators """
846 def __init__(self, dswfile, source, env):
847 self.dswfile = os.path.normpath(str(dswfile))
850 if not env.has_key('projects'):
851 raise SCons.Errors.UserError, \
852 "You must specify a 'projects' argument to create an MSVSSolution."
853 projects = env['projects']
854 if not SCons.Util.is_List(projects):
855 raise SCons.Errors.InternalError, \
856 "The 'projects' argument must be a list of nodes."
857 projects = SCons.Util.flatten(projects)
858 if len(projects) < 1:
859 raise SCons.Errors.UserError, \
860 "You must specify at least one project to create an MSVSSolution."
861 self.dspfiles = map(str, projects)
863 if self.env.has_key('name'):
864 self.name = self.env['name']
866 self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0])
867 self.name = self.env.subst(self.name)
872 class _GenerateV7DSW(_DSWGenerator):
873 """Generates a Solution file for MSVS .NET"""
874 def __init__(self, dswfile, source, env):
875 _DSWGenerator.__init__(self, dswfile, source, env)
878 self.version = self.env['MSVS_VERSION']
879 self.version_num, self.suite = msvs_parse_version(self.version)
880 self.versionstr = '7.00'
881 if self.version_num >= 8.0:
882 self.versionstr = '9.00'
883 elif self.version_num >= 7.1:
884 self.versionstr = '8.00'
885 if self.version_num >= 8.0:
886 self.versionstr = '9.00'
888 if env.has_key('slnguid') and env['slnguid']:
889 self.slnguid = env['slnguid']
891 self.slnguid = _generateGUID(dswfile, self.name)
896 if env.has_key('nokeep') and env['variant'] != 0:
899 if self.nokeep == 0 and os.path.exists(self.dswfile):
902 def AddConfig(self, variant, dswfile=dswfile):
905 match = re.match('(.*)\|(.*)', variant)
907 config.variant = match.group(1)
908 config.platform = match.group(2)
910 config.variant = variant
911 config.platform = 'Win32'
913 self.configs[variant] = config
914 print "Adding '" + self.name + ' - ' + config.variant + '|' + config.platform + "' to '" + str(dswfile) + "'"
916 if not env.has_key('variant'):
917 raise SCons.Errors.InternalError, \
918 "You must specify a 'variant' argument (i.e. 'Debug' or " +\
919 "'Release') to create an MSVS Solution File."
920 elif SCons.Util.is_String(env['variant']):
921 AddConfig(self, env['variant'])
922 elif SCons.Util.is_List(env['variant']):
923 for variant in env['variant']:
924 AddConfig(self, variant)
927 for key in self.configs.keys():
928 platform = self.configs[key].platform
929 if not platform in self.platforms:
930 self.platforms.append(platform)
934 dswfile = open(self.dswfile,'r')
936 return # doesn't exist yet, so can't add anything to configs.
938 line = dswfile.readline()
940 if line[:9] == "EndGlobal":
942 line = dswfile.readline()
944 line = dswfile.readline()
947 line = dswfile.readline()
950 # OK, we've found our little pickled cache of data.
952 datas = base64.decodestring(datas)
953 data = pickle.loads(datas)
954 except KeyboardInterrupt:
957 return # unable to unpickle any data for some reason
959 self.configs.update(data)
961 def PrintSolution(self):
962 """Writes a solution file"""
963 self.file.write('Microsoft Visual Studio Solution File, Format Version %s\n' % self.versionstr )
964 if self.version_num >= 8.0:
965 self.file.write('# Visual Studio 2005\n')
966 for p in self.dspfiles:
967 name = os.path.basename(p)
968 base, suffix = SCons.Util.splitext(name)
969 if suffix == '.vcproj':
971 guid = _generateGUID(p, '')
972 self.file.write('Project("%s") = "%s", "%s", "%s"\n'
973 % ( external_makefile_guid, name, p, guid ) )
974 if self.version_num >= 7.1 and self.version_num < 8.0:
975 self.file.write('\tProjectSection(ProjectDependencies) = postProject\n'
976 '\tEndProjectSection\n')
977 self.file.write('EndProject\n')
979 self.file.write('Global\n')
982 if env.has_key('MSVS_SCC_PROVIDER'):
983 dspfile_base = os.path.basename(self.dspfile)
984 slnguid = self.slnguid
985 scc_provider = env.get('MSVS_SCC_PROVIDER', '')
986 scc_provider = string.replace(scc_provider, ' ', r'\u0020')
987 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '')
988 # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '')
989 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '')
990 scc_project_base_path = env.get('MSVS_SCC_PROJECT_BASE_PATH', '')
991 # project_guid = env.get('MSVS_PROJECT_GUID', '')
993 self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n'
994 '\t\tSccNumberOfProjects = 2\n'
995 '\t\tSccProjectUniqueName0 = %(dspfile_base)s\n'
996 '\t\tSccLocalPath0 = %(scc_local_path)s\n'
997 '\t\tCanCheckoutShared = true\n'
998 '\t\tSccProjectFilePathRelativizedFromConnection0 = %(scc_project_base_path)s\n'
999 '\t\tSccProjectName1 = %(scc_project_name)s\n'
1000 '\t\tSccLocalPath1 = %(scc_local_path)s\n'
1001 '\t\tSccProvider1 = %(scc_provider)s\n'
1002 '\t\tCanCheckoutShared = true\n'
1003 '\t\tSccProjectFilePathRelativizedFromConnection1 = %(scc_project_base_path)s\n'
1004 '\t\tSolutionUniqueID = %(slnguid)s\n'
1005 '\tEndGlobalSection\n' % locals())
1007 if self.version_num >= 8.0:
1008 self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n')
1010 self.file.write('\tGlobalSection(SolutionConfiguration) = preSolution\n')
1012 confkeys = self.configs.keys()
1015 for name in confkeys:
1016 variant = self.configs[name].variant
1017 platform = self.configs[name].platform
1018 if self.version_num >= 8.0:
1019 self.file.write('\t\t%s|%s = %s|%s\n' % (variant, platform, variant, platform))
1021 self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant))
1023 self.file.write('\tEndGlobalSection\n')
1024 if self.version_num < 7.1:
1025 self.file.write('\tGlobalSection(ProjectDependencies) = postSolution\n'
1026 '\tEndGlobalSection\n')
1027 if self.version_num >= 8.0:
1028 self.file.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n')
1030 self.file.write('\tGlobalSection(ProjectConfiguration) = postSolution\n')
1032 for name in confkeys:
1033 variant = self.configs[name].variant
1034 platform = self.configs[name].platform
1035 if self.version_num >= 8.0:
1036 for p in self.dspfiles:
1037 guid = _generateGUID(p, '')
1038 self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n'
1039 '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,variant,platform,variant,platform,guid,variant,platform,variant,platform))
1041 for p in self.dspfiles:
1042 guid = _generateGUID(p, '')
1043 self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n'
1044 '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,variant,variant,platform,guid,variant,variant,platform))
1046 self.file.write('\tEndGlobalSection\n')
1048 if self.version_num >= 8.0:
1049 self.file.write('\tGlobalSection(SolutionProperties) = preSolution\n'
1050 '\t\tHideSolutionNode = FALSE\n'
1051 '\tEndGlobalSection\n')
1053 self.file.write('\tGlobalSection(ExtensibilityGlobals) = postSolution\n'
1054 '\tEndGlobalSection\n'
1055 '\tGlobalSection(ExtensibilityAddIns) = postSolution\n'
1056 '\tEndGlobalSection\n')
1057 self.file.write('EndGlobal\n')
1058 if self.nokeep == 0:
1059 pdata = pickle.dumps(self.configs,1)
1060 pdata = base64.encodestring(pdata)
1061 self.file.write(pdata + '\n')
1065 self.file = open(self.dswfile,'w')
1066 except IOError, detail:
1067 raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
1069 self.PrintSolution()
1073 Microsoft Developer Studio Workspace File, Format Version 6.00
1074 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
1076 ###############################################################################
1078 Project: "%(name)s"="%(dspfile)s" - Package Owner=<4>
1088 ###############################################################################
1100 ###############################################################################
1103 class _GenerateV6DSW(_DSWGenerator):
1104 """Generates a Workspace file for MSVS 6.0"""
1106 def PrintWorkspace(self):
1107 """ writes a DSW file """
1109 dspfile = self.dspfiles[0]
1110 self.file.write(V6DSWHeader % locals())
1114 self.file = open(self.dswfile,'w')
1115 except IOError, detail:
1116 raise SCons.Errors.InternalError, 'Unable to open "' + self.dswfile + '" for writing:' + str(detail)
1118 self.PrintWorkspace()
1122 def GenerateDSP(dspfile, source, env):
1123 """Generates a Project file based on the version of MSVS that is being used"""
1126 if env.has_key('MSVS_VERSION'):
1127 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1128 if version_num >= 7.0:
1129 g = _GenerateV7DSP(dspfile, source, env)
1132 g = _GenerateV6DSP(dspfile, source, env)
1135 def GenerateDSW(dswfile, source, env):
1136 """Generates a Solution/Workspace file based on the version of MSVS that is being used"""
1139 if env.has_key('MSVS_VERSION'):
1140 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1141 if version_num >= 7.0:
1142 g = _GenerateV7DSW(dswfile, source, env)
1145 g = _GenerateV6DSW(dswfile, source, env)
1149 ##############################################################################
1150 # Above here are the classes and functions for generation of
1151 # DSP/DSW/SLN/VCPROJ files.
1152 ##############################################################################
1154 def get_default_visualstudio_version(env):
1155 """Returns the version set in the env, or the latest version
1156 installed, if it can find it, or '6.0' if all else fails. Also
1157 updates the environment with what it found."""
1161 if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
1162 v = get_visualstudio_versions()
1165 env['MSVS'] = {'VERSIONS' : versions}
1167 versions = env['MSVS'].get('VERSIONS', versions)
1169 if not env.has_key('MSVS_VERSION'):
1170 env['MSVS_VERSION'] = versions[0] #use highest version by default
1172 env['MSVS']['VERSION'] = env['MSVS_VERSION']
1174 return env['MSVS_VERSION']
1176 def get_visualstudio_versions():
1178 Get list of visualstudio versions from the Windows registry.
1179 Returns a list of strings containing version numbers. An empty list
1180 is returned if we were unable to accees the register (for example,
1181 we couldn't import the registry-access module) or the appropriate
1182 registry keys weren't found.
1185 if not SCons.Util.can_read_reg:
1188 HLM = SCons.Util.HKEY_LOCAL_MACHINE
1190 r'Software\Microsoft\VisualStudio' : '',
1191 r'Software\Microsoft\VCExpress' : 'Exp',
1194 for K, suite_suffix in KEYS.items():
1196 k = SCons.Util.RegOpenKeyEx(HLM, K)
1200 p = SCons.Util.RegEnumKey(k,i)
1201 except SCons.Util.RegError:
1204 if not p[0] in '123456789' or p in L:
1206 # Only add this version number if there is a valid
1207 # registry structure (includes the "Setup" key),
1208 # and at least some of the correct directories
1209 # exist. Sometimes VS uninstall leaves around
1210 # some registry/filesystem turds that we don't
1211 # want to trip over. Also, some valid registry
1212 # entries are MSDN entries, not MSVS ('7.1',
1213 # notably), and we want to skip those too.
1215 SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p + '\\Setup')
1216 except SCons.Util.RegError:
1220 idk = SCons.Util.RegOpenKeyEx(HLM, K + '\\' + p)
1221 # This is not always here -- it only exists if the
1222 # user installed into a non-standard location (at
1223 # least in VS6 it works that way -- VS7 seems to
1226 id = SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1227 except SCons.Util.RegError:
1230 # If the InstallDir key doesn't exist,
1231 # then we check the default locations.
1232 # Note: The IDE's executable is not devenv.exe for VS8 Express.
1233 if not id or not id[0]:
1234 files_dir = SCons.Platform.win32.get_program_files_dir()
1235 version_num, suite = msvs_parse_version(p)
1236 if version_num < 7.0:
1237 vs = r'Microsoft Visual Studio\Common\MSDev98'
1238 elif version_num < 8.0:
1239 vs = r'Microsoft Visual Studio .NET\Common7\IDE'
1241 vs = r'Microsoft Visual Studio 8\Common7\IDE'
1242 id = [ os.path.join(files_dir, vs) ]
1243 if os.path.exists(id[0]):
1244 L.append(p + suite_suffix)
1245 except SCons.Util.RegError:
1251 # This is a hack to get around the fact that certain Visual Studio
1252 # patches place a "6.1" version in the registry, which does not have
1253 # any of the keys we need to find include paths, install directories,
1254 # etc. Therefore we ignore it if it is there, since it throws all
1266 def get_default_visualstudio8_suite(env):
1268 Returns the Visual Studio 2005 suite identifier set in the env, or the
1269 highest suite installed.
1271 if not env.has_key('MSVS') or not SCons.Util.is_Dict(env['MSVS']):
1274 if env.has_key('MSVS_SUITE'):
1276 #suite = env['MSVS_SUITE'].upper()
1277 suite = string.upper(env['MSVS_SUITE'])
1282 if SCons.Util.can_read_reg:
1283 suites = get_visualstudio8_suites()
1285 suite = suites[0] #use best suite by default
1287 env['MSVS_SUITE'] = suite
1288 env['MSVS']['SUITES'] = suites
1289 env['MSVS']['SUITE'] = suite
1293 def get_visualstudio8_suites():
1295 Returns a sorted list of all installed Visual Studio 2005 suites found
1296 in the registry. The highest version should be the first entry in the list.
1301 # Detect Standard, Professional and Team edition
1303 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1304 r'Software\Microsoft\VisualStudio\8.0')
1305 SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1306 editions = { 'PRO': r'Setup\VS\Pro' } # ToDo: add standard and team editions
1307 edition_name = 'STD'
1308 for name, key_suffix in editions.items():
1310 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1311 r'Software\Microsoft\VisualStudio\8.0' + '\\' + key_suffix )
1313 except SCons.Util.RegError:
1315 suites.append(edition_name)
1316 except SCons.Util.RegError:
1319 # Detect Express edition
1321 idk = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
1322 r'Software\Microsoft\VCExpress\8.0')
1323 SCons.Util.RegQueryValueEx(idk, 'InstallDir')
1324 suites.append('EXPRESS')
1325 except SCons.Util.RegError:
1330 def is_msvs_installed():
1332 Check the registry for an installed visual studio.
1335 v = SCons.Tool.msvs.get_visualstudio_versions()
1337 except (SCons.Util.RegError, SCons.Errors.InternalError):
1340 def get_msvs_install_dirs(version = None, vs8suite = None):
1342 Get installed locations for various msvc-related products, like the .NET SDK
1343 and the Platform SDK.
1346 if not SCons.Util.can_read_reg:
1350 versions = get_visualstudio_versions()
1352 version = versions[0] #use highest version by default
1356 version_num, suite = msvs_parse_version(version)
1358 K = 'Software\\Microsoft\\VisualStudio\\' + str(version_num)
1359 if (version_num >= 8.0):
1360 if vs8suite == None:
1361 # We've been given no guidance about which Visual Studio 8
1362 # suite to use, so attempt to autodetect.
1363 suites = get_visualstudio8_suites()
1365 vs8suite = suites[0]
1367 if vs8suite == 'EXPRESS':
1368 K = 'Software\\Microsoft\\VCExpress\\' + str(version_num)
1372 if (version_num < 7.0):
1373 key = K + r'\Setup\Microsoft Visual C++\ProductDir'
1375 key = K + r'\Setup\VC\ProductDir'
1377 (rv['VCINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, key)
1378 except SCons.Util.RegError:
1381 # visual studio install dir
1382 if (version_num < 7.0):
1384 (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1385 K + r'\Setup\Microsoft Visual Studio\ProductDir')
1386 except SCons.Util.RegError:
1389 if not rv.has_key('VSINSTALLDIR') or not rv['VSINSTALLDIR']:
1390 if rv.has_key('VCINSTALLDIR') and rv['VCINSTALLDIR']:
1391 rv['VSINSTALLDIR'] = os.path.dirname(rv['VCINSTALLDIR'])
1393 rv['VSINSTALLDIR'] = os.path.join(SCons.Platform.win32.get_program_files_dir(),'Microsoft Visual Studio')
1396 (rv['VSINSTALLDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1397 K + r'\Setup\VS\ProductDir')
1398 except SCons.Util.RegError:
1401 # .NET framework install dir
1403 (rv['FRAMEWORKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1404 r'Software\Microsoft\.NETFramework\InstallRoot')
1405 except SCons.Util.RegError:
1408 if rv.has_key('FRAMEWORKDIR'):
1409 # try and enumerate the installed versions of the .NET framework.
1410 contents = os.listdir(rv['FRAMEWORKDIR'])
1411 l = re.compile('v[0-9]+.*')
1412 installed_framework_versions = filter(lambda e, l=l: l.match(e), contents)
1415 # since version numbers aren't really floats...
1418 aal = string.split(aa, '.')
1419 bbl = string.split(bb, '.')
1420 # sequence comparison in python is lexicographical
1421 # which is exactly what we want.
1422 # Note we sort backwards so the highest version is first.
1425 installed_framework_versions.sort(versrt)
1427 rv['FRAMEWORKVERSIONS'] = installed_framework_versions
1429 # TODO: allow a specific framework version to be set
1431 # Choose a default framework version based on the Visual
1433 DefaultFrameworkVersionMap = {
1437 # TODO: Does .NET 3.0 need to be worked into here somewhere?
1440 default_framework_version = DefaultFrameworkVersionMap[version[:3]]
1441 except (KeyError, TypeError):
1444 # Look for the first installed directory in FRAMEWORKDIR that
1445 # begins with the framework version string that's appropriate
1446 # for the Visual Studio version we're using.
1447 for v in installed_framework_versions:
1448 if v[:4] == default_framework_version:
1449 rv['FRAMEWORKVERSION'] = v
1452 # If the framework version couldn't be worked out by the previous
1453 # code then fall back to using the latest version of the .NET
1455 if not rv.has_key('FRAMEWORKVERSION'):
1456 rv['FRAMEWORKVERSION'] = installed_framework_versions[0]
1458 # .NET framework SDK install dir
1459 if rv.has_key('FRAMEWORKVERSION'):
1460 # The .NET SDK version used must match the .NET version used,
1461 # so we deliberately don't fall back to other .NET framework SDK
1462 # versions that might be present.
1463 ver = rv['FRAMEWORKVERSION'][:4]
1464 key = r'Software\Microsoft\.NETFramework\sdkInstallRoot' + ver
1466 (rv['FRAMEWORKSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1468 except SCons.Util.RegError:
1471 # MS Platform SDK dir
1473 (rv['PLATFORMSDKDIR'], t) = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE,
1474 r'Software\Microsoft\MicrosoftSDK\Directories\Install Dir')
1475 except SCons.Util.RegError:
1478 if rv.has_key('PLATFORMSDKDIR'):
1479 # if we have a platform SDK, try and get some info on it.
1482 loc = r'Software\Microsoft\MicrosoftSDK\InstalledSDKs'
1483 k = SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,loc)
1487 key = SCons.Util.RegEnumKey(k,i)
1488 sdk = SCons.Util.RegOpenKeyEx(k,key)
1495 (vk,vv,t) = SCons.Util.RegEnumValue(sdk,j)
1497 #if vk.lower() == 'keyword':
1499 #if vk.lower() == 'propagation_date':
1501 #if vk.lower() == 'version':
1503 if string.lower(vk) == 'keyword':
1505 if string.lower(vk) == 'propagation_date':
1507 if string.lower(vk) == 'version':
1510 except SCons.Util.RegError:
1513 vers[name] = (date, version)
1515 except SCons.Util.RegError:
1517 rv['PLATFORMSDK_MODULES'] = vers
1518 except SCons.Util.RegError:
1523 def GetMSVSProjectSuffix(target, source, env, for_signature):
1524 return env['MSVS']['PROJECTSUFFIX']
1526 def GetMSVSSolutionSuffix(target, source, env, for_signature):
1527 return env['MSVS']['SOLUTIONSUFFIX']
1529 def GenerateProject(target, source, env):
1530 # generate the dsp file, according to the version of MSVS.
1531 builddspfile = target[0]
1532 dspfile = builddspfile.srcnode()
1534 # this detects whether or not we're using a VariantDir
1535 if not dspfile is builddspfile:
1537 bdsp = open(str(builddspfile), "w+")
1538 except IOError, detail:
1539 print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
1542 bdsp.write("This is just a placeholder file.\nThe real project file is here:\n%s\n" % dspfile.get_abspath())
1544 GenerateDSP(dspfile, source, env)
1546 if env.get('auto_build_solution', 1):
1547 builddswfile = target[1]
1548 dswfile = builddswfile.srcnode()
1550 if not dswfile is builddswfile:
1553 bdsw = open(str(builddswfile), "w+")
1554 except IOError, detail:
1555 print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\n'
1558 bdsw.write("This is just a placeholder file.\nThe real workspace file is here:\n%s\n" % dswfile.get_abspath())
1560 GenerateDSW(dswfile, source, env)
1562 def GenerateSolution(target, source, env):
1563 GenerateDSW(target[0], source, env)
1565 def projectEmitter(target, source, env):
1566 """Sets up the DSP dependencies."""
1568 # todo: Not sure what sets source to what user has passed as target,
1569 # but this is what happens. When that is fixed, we also won't have
1570 # to make the user always append env['MSVSPROJECTSUFFIX'] to target.
1571 if source[0] == target[0]:
1574 # make sure the suffix is correct for the version of MSVS we're running.
1575 (base, suff) = SCons.Util.splitext(str(target[0]))
1576 suff = env.subst('$MSVSPROJECTSUFFIX')
1577 target[0] = base + suff
1580 source = 'prj_inputs:'
1581 source = source + env.subst('$MSVSSCONSCOM', 1)
1582 source = source + env.subst('$MSVSENCODING', 1)
1584 if env.has_key('buildtarget') and env['buildtarget'] != None:
1585 if SCons.Util.is_String(env['buildtarget']):
1586 source = source + ' "%s"' % env['buildtarget']
1587 elif SCons.Util.is_List(env['buildtarget']):
1588 for bt in env['buildtarget']:
1589 if SCons.Util.is_String(bt):
1590 source = source + ' "%s"' % bt
1592 try: source = source + ' "%s"' % bt.get_abspath()
1593 except AttributeError: raise SCons.Errors.InternalError, \
1594 "buildtarget can be a string, a node, a list of strings or nodes, or None"
1596 try: source = source + ' "%s"' % env['buildtarget'].get_abspath()
1597 except AttributeError: raise SCons.Errors.InternalError, \
1598 "buildtarget can be a string, a node, a list of strings or nodes, or None"
1600 if env.has_key('outdir') and env['outdir'] != None:
1601 if SCons.Util.is_String(env['outdir']):
1602 source = source + ' "%s"' % env['outdir']
1603 elif SCons.Util.is_List(env['outdir']):
1604 for s in env['outdir']:
1605 if SCons.Util.is_String(s):
1606 source = source + ' "%s"' % s
1608 try: source = source + ' "%s"' % s.get_abspath()
1609 except AttributeError: raise SCons.Errors.InternalError, \
1610 "outdir can be a string, a node, a list of strings or nodes, or None"
1612 try: source = source + ' "%s"' % env['outdir'].get_abspath()
1613 except AttributeError: raise SCons.Errors.InternalError, \
1614 "outdir can be a string, a node, a list of strings or nodes, or None"
1616 if env.has_key('name'):
1617 if SCons.Util.is_String(env['name']):
1618 source = source + ' "%s"' % env['name']
1620 raise SCons.Errors.InternalError, "name must be a string"
1622 if env.has_key('variant'):
1623 if SCons.Util.is_String(env['variant']):
1624 source = source + ' "%s"' % env['variant']
1625 elif SCons.Util.is_List(env['variant']):
1626 for variant in env['variant']:
1627 if SCons.Util.is_String(variant):
1628 source = source + ' "%s"' % variant
1630 raise SCons.Errors.InternalError, "name must be a string or a list of strings"
1632 raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
1634 raise SCons.Errors.InternalError, "variant must be specified"
1636 for s in _DSPGenerator.srcargs:
1638 if SCons.Util.is_String(env[s]):
1639 source = source + ' "%s' % env[s]
1640 elif SCons.Util.is_List(env[s]):
1642 if SCons.Util.is_String(t):
1643 source = source + ' "%s"' % t
1645 raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
1647 raise SCons.Errors.InternalError, s + " must be a string or a list of strings"
1649 source = source + ' "%s"' % str(target[0])
1650 source = [SCons.Node.Python.Value(source)]
1652 targetlist = [target[0]]
1655 if env.get('auto_build_solution', 1):
1656 env['projects'] = targetlist
1657 t, s = solutionEmitter(target, target, env)
1658 targetlist = targetlist + t
1660 return (targetlist, sourcelist)
1662 def solutionEmitter(target, source, env):
1663 """Sets up the DSW dependencies."""
1665 # todo: Not sure what sets source to what user has passed as target,
1666 # but this is what happens. When that is fixed, we also won't have
1667 # to make the user always append env['MSVSSOLUTIONSUFFIX'] to target.
1668 if source[0] == target[0]:
1671 # make sure the suffix is correct for the version of MSVS we're running.
1672 (base, suff) = SCons.Util.splitext(str(target[0]))
1673 suff = env.subst('$MSVSSOLUTIONSUFFIX')
1674 target[0] = base + suff
1677 source = 'sln_inputs:'
1679 if env.has_key('name'):
1680 if SCons.Util.is_String(env['name']):
1681 source = source + ' "%s"' % env['name']
1683 raise SCons.Errors.InternalError, "name must be a string"
1685 if env.has_key('variant'):
1686 if SCons.Util.is_String(env['variant']):
1687 source = source + ' "%s"' % env['variant']
1688 elif SCons.Util.is_List(env['variant']):
1689 for variant in env['variant']:
1690 if SCons.Util.is_String(variant):
1691 source = source + ' "%s"' % variant
1693 raise SCons.Errors.InternalError, "name must be a string or a list of strings"
1695 raise SCons.Errors.InternalError, "variant must be a string or a list of strings"
1697 raise SCons.Errors.InternalError, "variant must be specified"
1699 if env.has_key('slnguid'):
1700 if SCons.Util.is_String(env['slnguid']):
1701 source = source + ' "%s"' % env['slnguid']
1703 raise SCons.Errors.InternalError, "slnguid must be a string"
1705 if env.has_key('projects'):
1706 if SCons.Util.is_String(env['projects']):
1707 source = source + ' "%s"' % env['projects']
1708 elif SCons.Util.is_List(env['projects']):
1709 for t in env['projects']:
1710 if SCons.Util.is_String(t):
1711 source = source + ' "%s"' % t
1713 source = source + ' "%s"' % str(target[0])
1714 source = [SCons.Node.Python.Value(source)]
1716 return ([target[0]], source)
1718 projectAction = SCons.Action.Action(GenerateProject, None)
1720 solutionAction = SCons.Action.Action(GenerateSolution, None)
1722 projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM',
1723 suffix = '$MSVSPROJECTSUFFIX',
1724 emitter = projectEmitter)
1726 solutionBuilder = SCons.Builder.Builder(action = '$MSVSSOLUTIONCOM',
1727 suffix = '$MSVSSOLUTIONSUFFIX',
1728 emitter = solutionEmitter)
1730 default_MSVS_SConscript = None
1733 """Add Builders and construction variables for Microsoft Visual
1734 Studio project files to an Environment."""
1736 env['BUILDERS']['MSVSProject']
1738 env['BUILDERS']['MSVSProject'] = projectBuilder
1741 env['BUILDERS']['MSVSSolution']
1743 env['BUILDERS']['MSVSSolution'] = solutionBuilder
1745 env['MSVSPROJECTCOM'] = projectAction
1746 env['MSVSSOLUTIONCOM'] = solutionAction
1748 if SCons.Script.call_stack:
1749 # XXX Need to find a way to abstract this; the build engine
1750 # shouldn't depend on anything in SCons.Script.
1751 env['MSVSSCONSCRIPT'] = SCons.Script.call_stack[0].sconscript
1753 global default_MSVS_SConscript
1754 if default_MSVS_SConscript is None:
1755 default_MSVS_SConscript = env.File('SConstruct')
1756 env['MSVSSCONSCRIPT'] = default_MSVS_SConscript
1758 env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(env))
1759 env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.abspath}" -f ${MSVSSCONSCRIPT.name}'
1760 env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS'
1761 env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
1762 env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"'
1763 env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"'
1764 env['MSVSENCODING'] = 'Windows-1252'
1767 version = get_default_visualstudio_version(env)
1768 # keep a record of some of the MSVS info so the user can use it.
1769 dirs = get_msvs_install_dirs(version)
1770 env['MSVS'].update(dirs)
1771 except (SCons.Util.RegError, SCons.Errors.InternalError):
1772 # we don't care if we can't do this -- if we can't, it's
1773 # because we don't have access to the registry, or because the
1774 # tools aren't installed. In either case, the user will have to
1775 # find them on their own.
1778 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1779 if (version_num < 7.0):
1780 env['MSVS']['PROJECTSUFFIX'] = '.dsp'
1781 env['MSVS']['SOLUTIONSUFFIX'] = '.dsw'
1783 env['MSVS']['PROJECTSUFFIX'] = '.vcproj'
1784 env['MSVS']['SOLUTIONSUFFIX'] = '.sln'
1786 env['GET_MSVSPROJECTSUFFIX'] = GetMSVSProjectSuffix
1787 env['GET_MSVSSOLUTIONSUFFIX'] = GetMSVSSolutionSuffix
1788 env['MSVSPROJECTSUFFIX'] = '${GET_MSVSPROJECTSUFFIX}'
1789 env['MSVSSOLUTIONSUFFIX'] = '${GET_MSVSSOLUTIONSUFFIX}'
1790 env['SCONS_HOME'] = os.environ.get('SCONS_HOME')
1793 if not env['PLATFORM'] in ('win32', 'cygwin'):
1797 v = SCons.Tool.msvs.get_visualstudio_versions()
1798 except (SCons.Util.RegError, SCons.Errors.InternalError):
1803 if env.has_key('MSVS_VERSION'):
1804 version_num, suite = msvs_parse_version(env['MSVS_VERSION'])
1805 if version_num >= 7.0:
1806 # The executable is 'devenv' in Visual Studio Pro,
1807 # Team System and others. Express Editions have different
1808 # executable names. Right now we're only going to worry
1809 # about Visual C++ 2005 Express Edition.
1810 return env.Detect('devenv') or env.Detect('vcexpress')
1812 return env.Detect('msdev')
1814 # there's at least one version of MSVS installed.