OLD | NEW |
(Empty) | |
| 1 """SCons.Tool.msvs |
| 2 |
| 3 Tool-specific initialization for Microsoft Visual Studio project files. |
| 4 |
| 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() |
| 7 selection method. |
| 8 |
| 9 """ |
| 10 |
| 11 # |
| 12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S
Cons Foundation |
| 13 # |
| 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: |
| 21 # |
| 22 # The above copyright notice and this permission notice shall be included |
| 23 # in all copies or substantial portions of the Software. |
| 24 # |
| 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. |
| 32 |
| 33 __revision__ = "src/engine/SCons/Tool/msvs.py 5134 2010/08/16 23:02:40 bdeegan" |
| 34 |
| 35 import SCons.compat |
| 36 |
| 37 import base64 |
| 38 import hashlib |
| 39 import ntpath |
| 40 import os |
| 41 # compat layer imports "cPickle" for us if it's available. |
| 42 import pickle |
| 43 import re |
| 44 import sys |
| 45 |
| 46 import SCons.Builder |
| 47 import SCons.Node.FS |
| 48 import SCons.Platform.win32 |
| 49 import SCons.Script.SConscript |
| 50 import SCons.Util |
| 51 import SCons.Warnings |
| 52 |
| 53 from MSCommon import msvc_exists, msvc_setup_env_once |
| 54 from SCons.Defaults import processDefines |
| 55 |
| 56 ############################################################################## |
| 57 # Below here are the classes and functions for generation of |
| 58 # DSP/DSW/SLN/VCPROJ files. |
| 59 ############################################################################## |
| 60 |
| 61 def xmlify(s): |
| 62 s = s.replace("&", "&") # do this first |
| 63 s = s.replace("'", "'") |
| 64 s = s.replace('"', """) |
| 65 return s |
| 66 |
| 67 external_makefile_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}' |
| 68 |
| 69 def _generateGUID(slnfile, name): |
| 70 """This generates a dummy GUID for the sln file to use. It is |
| 71 based on the MD5 signatures of the sln filename plus the name of |
| 72 the project. It basically just needs to be unique, and not |
| 73 change with each invocation.""" |
| 74 m = hashlib.md5() |
| 75 # Normalize the slnfile path to a Windows path (\ separators) so |
| 76 # the generated file has a consistent GUID even if we generate |
| 77 # it on a non-Windows platform. |
| 78 m.update(ntpath.normpath(str(slnfile)) + str(name)) |
| 79 solution = m.hexdigest().upper() |
| 80 # convert most of the signature to GUID form (discard the rest) |
| 81 solution = "{" + solution[:8] + "-" + solution[8:12] + "-" + solution[12:16]
+ "-" + solution[16:20] + "-" + solution[20:32] + "}" |
| 82 return solution |
| 83 |
| 84 version_re = re.compile(r'(\d+\.\d+)(.*)') |
| 85 |
| 86 def msvs_parse_version(s): |
| 87 """ |
| 88 Split a Visual Studio version, which may in fact be something like |
| 89 '7.0Exp', into is version number (returned as a float) and trailing |
| 90 "suite" portion. |
| 91 """ |
| 92 num, suite = version_re.match(s).groups() |
| 93 return float(num), suite |
| 94 |
| 95 # This is how we re-invoke SCons from inside MSVS Project files. |
| 96 # The problem is that we might have been invoked as either scons.bat |
| 97 # or scons.py. If we were invoked directly as scons.py, then we could |
| 98 # use sys.argv[0] to find the SCons "executable," but that doesn't work |
| 99 # if we were invoked as scons.bat, which uses "python -c" to execute |
| 100 # things and ends up with "-c" as sys.argv[0]. Consequently, we have |
| 101 # the MSVS Project file invoke SCons the same way that scons.bat does, |
| 102 # which works regardless of how we were invoked. |
| 103 def getExecScriptMain(env, xml=None): |
| 104 scons_home = env.get('SCONS_HOME') |
| 105 if not scons_home and 'SCONS_LIB_DIR' in os.environ: |
| 106 scons_home = os.environ['SCONS_LIB_DIR'] |
| 107 if scons_home: |
| 108 exec_script_main = "from os.path import join; import sys; sys.path = [ r
'%s' ] + sys.path; import SCons.Script; SCons.Script.main()" % scons_home |
| 109 else: |
| 110 version = SCons.__version__ |
| 111 exec_script_main = "from os.path import join; import sys; sys.path = [ j
oin(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()" % loca
ls() |
| 112 if xml: |
| 113 exec_script_main = xmlify(exec_script_main) |
| 114 return exec_script_main |
| 115 |
| 116 # The string for the Python executable we tell the Project file to use |
| 117 # is either sys.executable or, if an external PYTHON_ROOT environment |
| 118 # variable exists, $(PYTHON)ROOT\\python.exe (generalized a little to |
| 119 # pluck the actual executable name from sys.executable). |
| 120 try: |
| 121 python_root = os.environ['PYTHON_ROOT'] |
| 122 except KeyError: |
| 123 python_executable = sys.executable |
| 124 else: |
| 125 python_executable = os.path.join('$$(PYTHON_ROOT)', |
| 126 os.path.split(sys.executable)[1]) |
| 127 |
| 128 class Config(object): |
| 129 pass |
| 130 |
| 131 def splitFully(path): |
| 132 dir, base = os.path.split(path) |
| 133 if dir and dir != '' and dir != path: |
| 134 return splitFully(dir)+[base] |
| 135 if base == '': |
| 136 return [] |
| 137 return [base] |
| 138 |
| 139 def makeHierarchy(sources): |
| 140 '''Break a list of files into a hierarchy; for each value, if it is a string
, |
| 141 then it is a file. If it is a dictionary, it is a folder. The string is |
| 142 the original path of the file.''' |
| 143 |
| 144 hierarchy = {} |
| 145 for file in sources: |
| 146 path = splitFully(file) |
| 147 if len(path): |
| 148 dict = hierarchy |
| 149 for part in path[:-1]: |
| 150 if part not in dict: |
| 151 dict[part] = {} |
| 152 dict = dict[part] |
| 153 dict[path[-1]] = file |
| 154 #else: |
| 155 # print 'Warning: failed to decompose path for '+str(file) |
| 156 return hierarchy |
| 157 |
| 158 class _DSPGenerator(object): |
| 159 """ Base class for DSP generators """ |
| 160 |
| 161 srcargs = [ |
| 162 'srcs', |
| 163 'incs', |
| 164 'localincs', |
| 165 'resources', |
| 166 'misc'] |
| 167 |
| 168 def __init__(self, dspfile, source, env): |
| 169 self.dspfile = str(dspfile) |
| 170 try: |
| 171 get_abspath = dspfile.get_abspath |
| 172 except AttributeError: |
| 173 self.dspabs = os.path.abspath(dspfile) |
| 174 else: |
| 175 self.dspabs = get_abspath() |
| 176 |
| 177 if 'variant' not in env: |
| 178 raise SCons.Errors.InternalError("You must specify a 'variant' argum
ent (i.e. 'Debug' or " +\ |
| 179 "'Release') to create an MSVSProject.") |
| 180 elif SCons.Util.is_String(env['variant']): |
| 181 variants = [env['variant']] |
| 182 elif SCons.Util.is_List(env['variant']): |
| 183 variants = env['variant'] |
| 184 |
| 185 if 'buildtarget' not in env or env['buildtarget'] == None: |
| 186 buildtarget = [''] |
| 187 elif SCons.Util.is_String(env['buildtarget']): |
| 188 buildtarget = [env['buildtarget']] |
| 189 elif SCons.Util.is_List(env['buildtarget']): |
| 190 if len(env['buildtarget']) != len(variants): |
| 191 raise SCons.Errors.InternalError("Sizes of 'buildtarget' and 'va
riant' lists must be the same.") |
| 192 buildtarget = [] |
| 193 for bt in env['buildtarget']: |
| 194 if SCons.Util.is_String(bt): |
| 195 buildtarget.append(bt) |
| 196 else: |
| 197 buildtarget.append(bt.get_abspath()) |
| 198 else: |
| 199 buildtarget = [env['buildtarget'].get_abspath()] |
| 200 if len(buildtarget) == 1: |
| 201 bt = buildtarget[0] |
| 202 buildtarget = [] |
| 203 for _ in variants: |
| 204 buildtarget.append(bt) |
| 205 |
| 206 if 'outdir' not in env or env['outdir'] == None: |
| 207 outdir = [''] |
| 208 elif SCons.Util.is_String(env['outdir']): |
| 209 outdir = [env['outdir']] |
| 210 elif SCons.Util.is_List(env['outdir']): |
| 211 if len(env['outdir']) != len(variants): |
| 212 raise SCons.Errors.InternalError("Sizes of 'outdir' and 'variant
' lists must be the same.") |
| 213 outdir = [] |
| 214 for s in env['outdir']: |
| 215 if SCons.Util.is_String(s): |
| 216 outdir.append(s) |
| 217 else: |
| 218 outdir.append(s.get_abspath()) |
| 219 else: |
| 220 outdir = [env['outdir'].get_abspath()] |
| 221 if len(outdir) == 1: |
| 222 s = outdir[0] |
| 223 outdir = [] |
| 224 for v in variants: |
| 225 outdir.append(s) |
| 226 |
| 227 if 'runfile' not in env or env['runfile'] == None: |
| 228 runfile = buildtarget[-1:] |
| 229 elif SCons.Util.is_String(env['runfile']): |
| 230 runfile = [env['runfile']] |
| 231 elif SCons.Util.is_List(env['runfile']): |
| 232 if len(env['runfile']) != len(variants): |
| 233 raise SCons.Errors.InternalError("Sizes of 'runfile' and 'varian
t' lists must be the same.") |
| 234 runfile = [] |
| 235 for s in env['runfile']: |
| 236 if SCons.Util.is_String(s): |
| 237 runfile.append(s) |
| 238 else: |
| 239 runfile.append(s.get_abspath()) |
| 240 else: |
| 241 runfile = [env['runfile'].get_abspath()] |
| 242 if len(runfile) == 1: |
| 243 s = runfile[0] |
| 244 runfile = [] |
| 245 for v in variants: |
| 246 runfile.append(s) |
| 247 |
| 248 self.sconscript = env['MSVSSCONSCRIPT'] |
| 249 |
| 250 cmdargs = env.get('cmdargs', '') |
| 251 |
| 252 self.env = env |
| 253 |
| 254 if 'name' in self.env: |
| 255 self.name = self.env['name'] |
| 256 else: |
| 257 self.name = os.path.basename(SCons.Util.splitext(self.dspfile)[0]) |
| 258 self.name = self.env.subst(self.name) |
| 259 |
| 260 sourcenames = [ |
| 261 'Source Files', |
| 262 'Header Files', |
| 263 'Local Headers', |
| 264 'Resource Files', |
| 265 'Other Files'] |
| 266 |
| 267 self.sources = {} |
| 268 for n in sourcenames: |
| 269 self.sources[n] = [] |
| 270 |
| 271 self.configs = {} |
| 272 |
| 273 self.nokeep = 0 |
| 274 if 'nokeep' in env and env['variant'] != 0: |
| 275 self.nokeep = 1 |
| 276 |
| 277 if self.nokeep == 0 and os.path.exists(self.dspabs): |
| 278 self.Parse() |
| 279 |
| 280 for t in zip(sourcenames,self.srcargs): |
| 281 if t[1] in self.env: |
| 282 if SCons.Util.is_List(self.env[t[1]]): |
| 283 for i in self.env[t[1]]: |
| 284 if not i in self.sources[t[0]]: |
| 285 self.sources[t[0]].append(i) |
| 286 else: |
| 287 if not self.env[t[1]] in self.sources[t[0]]: |
| 288 self.sources[t[0]].append(self.env[t[1]]) |
| 289 |
| 290 for n in sourcenames: |
| 291 #TODO 2.4: compat layer supports sorted(key=) but not sort(key=) |
| 292 #TODO 2.4: self.sources[n].sort(key=lambda a: a.lower()) |
| 293 self.sources[n] = sorted(self.sources[n], key=lambda a: a.lower()) |
| 294 |
| 295 def AddConfig(self, variant, buildtarget, outdir, runfile, cmdargs, dspf
ile=dspfile): |
| 296 config = Config() |
| 297 config.buildtarget = buildtarget |
| 298 config.outdir = outdir |
| 299 config.cmdargs = cmdargs |
| 300 config.runfile = runfile |
| 301 |
| 302 match = re.match('(.*)\|(.*)', variant) |
| 303 if match: |
| 304 config.variant = match.group(1) |
| 305 config.platform = match.group(2) |
| 306 else: |
| 307 config.variant = variant |
| 308 config.platform = 'Win32' |
| 309 |
| 310 self.configs[variant] = config |
| 311 print "Adding '" + self.name + ' - ' + config.variant + '|' + config
.platform + "' to '" + str(dspfile) + "'" |
| 312 |
| 313 for i in range(len(variants)): |
| 314 AddConfig(self, variants[i], buildtarget[i], outdir[i], runfile[i],
cmdargs) |
| 315 |
| 316 self.platforms = [] |
| 317 for key in self.configs.keys(): |
| 318 platform = self.configs[key].platform |
| 319 if not platform in self.platforms: |
| 320 self.platforms.append(platform) |
| 321 |
| 322 def Build(self): |
| 323 pass |
| 324 |
| 325 V6DSPHeader = """\ |
| 326 # Microsoft Developer Studio Project File - Name="%(name)s" - Package Owner=<4> |
| 327 # Microsoft Developer Studio Generated Build File, Format Version 6.00 |
| 328 # ** DO NOT EDIT ** |
| 329 |
| 330 # TARGTYPE "Win32 (x86) External Target" 0x0106 |
| 331 |
| 332 CFG=%(name)s - Win32 %(confkey)s |
| 333 !MESSAGE This is not a valid makefile. To build this project using NMAKE, |
| 334 !MESSAGE use the Export Makefile command and run |
| 335 !MESSAGE |
| 336 !MESSAGE NMAKE /f "%(name)s.mak". |
| 337 !MESSAGE |
| 338 !MESSAGE You can specify a configuration when running NMAKE |
| 339 !MESSAGE by defining the macro CFG on the command line. For example: |
| 340 !MESSAGE |
| 341 !MESSAGE NMAKE /f "%(name)s.mak" CFG="%(name)s - Win32 %(confkey)s" |
| 342 !MESSAGE |
| 343 !MESSAGE Possible choices for configuration are: |
| 344 !MESSAGE |
| 345 """ |
| 346 |
| 347 class _GenerateV6DSP(_DSPGenerator): |
| 348 """Generates a Project file for MSVS 6.0""" |
| 349 |
| 350 def PrintHeader(self): |
| 351 # pick a default config |
| 352 confkeys = sorted(self.configs.keys()) |
| 353 |
| 354 name = self.name |
| 355 confkey = confkeys[0] |
| 356 |
| 357 self.file.write(V6DSPHeader % locals()) |
| 358 |
| 359 for kind in confkeys: |
| 360 self.file.write('!MESSAGE "%s - Win32 %s" (based on "Win32 (x86) Ext
ernal Target")\n' % (name, kind)) |
| 361 |
| 362 self.file.write('!MESSAGE \n\n') |
| 363 |
| 364 def PrintProject(self): |
| 365 name = self.name |
| 366 self.file.write('# Begin Project\n' |
| 367 '# PROP AllowPerConfigDependencies 0\n' |
| 368 '# PROP Scc_ProjName ""\n' |
| 369 '# PROP Scc_LocalPath ""\n\n') |
| 370 |
| 371 first = 1 |
| 372 confkeys = sorted(self.configs.keys()) |
| 373 for kind in confkeys: |
| 374 outdir = self.configs[kind].outdir |
| 375 buildtarget = self.configs[kind].buildtarget |
| 376 if first == 1: |
| 377 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,
kind)) |
| 378 first = 0 |
| 379 else: |
| 380 self.file.write('\n!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (
name, kind)) |
| 381 |
| 382 env_has_buildtarget = 'MSVSBUILDTARGET' in self.env |
| 383 if not env_has_buildtarget: |
| 384 self.env['MSVSBUILDTARGET'] = buildtarget |
| 385 |
| 386 # have to write this twice, once with the BASE settings, and once wi
thout |
| 387 for base in ("BASE ",""): |
| 388 self.file.write('# PROP %sUse_MFC 0\n' |
| 389 '# PROP %sUse_Debug_Libraries ' % (base, base)) |
| 390 if kind.lower().find('debug') < 0: |
| 391 self.file.write('0\n') |
| 392 else: |
| 393 self.file.write('1\n') |
| 394 self.file.write('# PROP %sOutput_Dir "%s"\n' |
| 395 '# PROP %sIntermediate_Dir "%s"\n' % (base,outdi
r,base,outdir)) |
| 396 cmd = 'echo Starting SCons && ' + self.env.subst('$MSVSBUILDCOM'
, 1) |
| 397 self.file.write('# PROP %sCmd_Line "%s"\n' |
| 398 '# PROP %sRebuild_Opt "-c && %s"\n' |
| 399 '# PROP %sTarget_File "%s"\n' |
| 400 '# PROP %sBsc_Name ""\n' |
| 401 '# PROP %sTarget_Dir ""\n'\ |
| 402 %(base,cmd,base,cmd,base,buildtarget,base,base)) |
| 403 |
| 404 if not env_has_buildtarget: |
| 405 del self.env['MSVSBUILDTARGET'] |
| 406 |
| 407 self.file.write('\n!ENDIF\n\n' |
| 408 '# Begin Target\n\n') |
| 409 for kind in confkeys: |
| 410 self.file.write('# Name "%s - Win32 %s"\n' % (name,kind)) |
| 411 self.file.write('\n') |
| 412 first = 0 |
| 413 for kind in confkeys: |
| 414 if first == 0: |
| 415 self.file.write('!IF "$(CFG)" == "%s - Win32 %s"\n\n' % (name,k
ind)) |
| 416 first = 1 |
| 417 else: |
| 418 self.file.write('!ELSEIF "$(CFG)" == "%s - Win32 %s"\n\n' % (na
me,kind)) |
| 419 self.file.write('!ENDIF \n\n') |
| 420 self.PrintSourceFiles() |
| 421 self.file.write('# End Target\n' |
| 422 '# End Project\n') |
| 423 |
| 424 if self.nokeep == 0: |
| 425 # now we pickle some data and add it to the file -- MSDEV will ignor
e it. |
| 426 pdata = pickle.dumps(self.configs,1) |
| 427 pdata = base64.encodestring(pdata) |
| 428 self.file.write(pdata + '\n') |
| 429 pdata = pickle.dumps(self.sources,1) |
| 430 pdata = base64.encodestring(pdata) |
| 431 self.file.write(pdata + '\n') |
| 432 |
| 433 def PrintSourceFiles(self): |
| 434 categories = {'Source Files': 'cpp|c|cxx|l|y|def|odl|idl|hpj|bat', |
| 435 'Header Files': 'h|hpp|hxx|hm|inl', |
| 436 'Local Headers': 'h|hpp|hxx|hm|inl', |
| 437 'Resource Files': 'r|rc|ico|cur|bmp|dlg|rc2|rct|bin|cnt|rt
f|gif|jpg|jpeg|jpe', |
| 438 'Other Files': ''} |
| 439 |
| 440 for kind in sorted(categories.keys(), key=lambda a: a.lower()): |
| 441 if not self.sources[kind]: |
| 442 continue # skip empty groups |
| 443 |
| 444 self.file.write('# Begin Group "' + kind + '"\n\n') |
| 445 typelist = categories[kind].replace('|', ';') |
| 446 self.file.write('# PROP Default_Filter "' + typelist + '"\n') |
| 447 |
| 448 for file in self.sources[kind]: |
| 449 file = os.path.normpath(file) |
| 450 self.file.write('# Begin Source File\n\n' |
| 451 'SOURCE="' + file + '"\n' |
| 452 '# End Source File\n') |
| 453 self.file.write('# End Group\n') |
| 454 |
| 455 # add the SConscript file outside of the groups |
| 456 self.file.write('# Begin Source File\n\n' |
| 457 'SOURCE="' + str(self.sconscript) + '"\n' |
| 458 '# End Source File\n') |
| 459 |
| 460 def Parse(self): |
| 461 try: |
| 462 dspfile = open(self.dspabs,'r') |
| 463 except IOError: |
| 464 return # doesn't exist yet, so can't add anything to configs. |
| 465 |
| 466 line = dspfile.readline() |
| 467 while line: |
| 468 if line.find("# End Project") > -1: |
| 469 break |
| 470 line = dspfile.readline() |
| 471 |
| 472 line = dspfile.readline() |
| 473 datas = line |
| 474 while line and line != '\n': |
| 475 line = dspfile.readline() |
| 476 datas = datas + line |
| 477 |
| 478 # OK, we've found our little pickled cache of data. |
| 479 try: |
| 480 datas = base64.decodestring(datas) |
| 481 data = pickle.loads(datas) |
| 482 except KeyboardInterrupt: |
| 483 raise |
| 484 except: |
| 485 return # unable to unpickle any data for some reason |
| 486 |
| 487 self.configs.update(data) |
| 488 |
| 489 data = None |
| 490 line = dspfile.readline() |
| 491 datas = line |
| 492 while line and line != '\n': |
| 493 line = dspfile.readline() |
| 494 datas = datas + line |
| 495 |
| 496 # OK, we've found our little pickled cache of data. |
| 497 # it has a "# " in front of it, so we strip that. |
| 498 try: |
| 499 datas = base64.decodestring(datas) |
| 500 data = pickle.loads(datas) |
| 501 except KeyboardInterrupt: |
| 502 raise |
| 503 except: |
| 504 return # unable to unpickle any data for some reason |
| 505 |
| 506 self.sources.update(data) |
| 507 |
| 508 def Build(self): |
| 509 try: |
| 510 self.file = open(self.dspabs,'w') |
| 511 except IOError, detail: |
| 512 raise SCons.Errors.InternalError('Unable to open "' + self.dspabs +
'" for writing:' + str(detail)) |
| 513 else: |
| 514 self.PrintHeader() |
| 515 self.PrintProject() |
| 516 self.file.close() |
| 517 |
| 518 V7DSPHeader = """\ |
| 519 <?xml version="1.0" encoding = "%(encoding)s"?> |
| 520 <VisualStudioProject |
| 521 \tProjectType="Visual C++" |
| 522 \tVersion="%(versionstr)s" |
| 523 \tName="%(name)s" |
| 524 %(scc_attrs)s |
| 525 \tKeyword="MakeFileProj"> |
| 526 """ |
| 527 |
| 528 V7DSPConfiguration = """\ |
| 529 \t\t<Configuration |
| 530 \t\t\tName="%(variant)s|%(platform)s" |
| 531 \t\t\tOutputDirectory="%(outdir)s" |
| 532 \t\t\tIntermediateDirectory="%(outdir)s" |
| 533 \t\t\tConfigurationType="0" |
| 534 \t\t\tUseOfMFC="0" |
| 535 \t\t\tATLMinimizesCRunTimeLibraryUsage="FALSE"> |
| 536 \t\t\t<Tool |
| 537 \t\t\t\tName="VCNMakeTool" |
| 538 \t\t\t\tBuildCommandLine="%(buildcmd)s" |
| 539 \t\t\t\tCleanCommandLine="%(cleancmd)s" |
| 540 \t\t\t\tRebuildCommandLine="%(rebuildcmd)s" |
| 541 \t\t\t\tOutput="%(runfile)s"/> |
| 542 \t\t</Configuration> |
| 543 """ |
| 544 |
| 545 V8DSPHeader = """\ |
| 546 <?xml version="1.0" encoding="%(encoding)s"?> |
| 547 <VisualStudioProject |
| 548 \tProjectType="Visual C++" |
| 549 \tVersion="%(versionstr)s" |
| 550 \tName="%(name)s" |
| 551 %(scc_attrs)s |
| 552 \tRootNamespace="%(name)s" |
| 553 \tKeyword="MakeFileProj"> |
| 554 """ |
| 555 |
| 556 V8DSPConfiguration = """\ |
| 557 \t\t<Configuration |
| 558 \t\t\tName="%(variant)s|%(platform)s" |
| 559 \t\t\tConfigurationType="0" |
| 560 \t\t\tUseOfMFC="0" |
| 561 \t\t\tATLMinimizesCRunTimeLibraryUsage="false" |
| 562 \t\t\t> |
| 563 \t\t\t<Tool |
| 564 \t\t\t\tName="VCNMakeTool" |
| 565 \t\t\t\tBuildCommandLine="%(buildcmd)s" |
| 566 \t\t\t\tReBuildCommandLine="%(rebuildcmd)s" |
| 567 \t\t\t\tCleanCommandLine="%(cleancmd)s" |
| 568 \t\t\t\tOutput="%(runfile)s" |
| 569 \t\t\t\tPreprocessorDefinitions="%(preprocdefs)s" |
| 570 \t\t\t\tIncludeSearchPath="%(includepath)s" |
| 571 \t\t\t\tForcedIncludes="" |
| 572 \t\t\t\tAssemblySearchPath="" |
| 573 \t\t\t\tForcedUsingAssemblies="" |
| 574 \t\t\t\tCompileAsManaged="" |
| 575 \t\t\t/> |
| 576 \t\t</Configuration> |
| 577 """ |
| 578 class _GenerateV7DSP(_DSPGenerator): |
| 579 """Generates a Project file for MSVS .NET""" |
| 580 |
| 581 def __init__(self, dspfile, source, env): |
| 582 _DSPGenerator.__init__(self, dspfile, source, env) |
| 583 self.version = env['MSVS_VERSION'] |
| 584 self.version_num, self.suite = msvs_parse_version(self.version) |
| 585 if self.version_num >= 8.0: |
| 586 self.versionstr = '8.00' |
| 587 self.dspheader = V8DSPHeader |
| 588 self.dspconfiguration = V8DSPConfiguration |
| 589 else: |
| 590 if self.version_num >= 7.1: |
| 591 self.versionstr = '7.10' |
| 592 else: |
| 593 self.versionstr = '7.00' |
| 594 self.dspheader = V7DSPHeader |
| 595 self.dspconfiguration = V7DSPConfiguration |
| 596 self.file = None |
| 597 |
| 598 def PrintHeader(self): |
| 599 env = self.env |
| 600 versionstr = self.versionstr |
| 601 name = self.name |
| 602 encoding = self.env.subst('$MSVSENCODING') |
| 603 scc_provider = env.get('MSVS_SCC_PROVIDER', '') |
| 604 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '') |
| 605 scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '') |
| 606 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '') |
| 607 project_guid = env.get('MSVS_PROJECT_GUID', '') |
| 608 if self.version_num >= 8.0 and not project_guid: |
| 609 project_guid = _generateGUID(self.dspfile, '') |
| 610 if scc_provider != '': |
| 611 scc_attrs = ('\tProjectGUID="%s"\n' |
| 612 '\tSccProjectName="%s"\n' |
| 613 '\tSccAuxPath="%s"\n' |
| 614 '\tSccLocalPath="%s"\n' |
| 615 '\tSccProvider="%s"' % (project_guid, scc_project_name,
scc_aux_path, scc_local_path, scc_provider)) |
| 616 else: |
| 617 scc_attrs = ('\tProjectGUID="%s"\n' |
| 618 '\tSccProjectName="%s"\n' |
| 619 '\tSccLocalPath="%s"' % (project_guid, scc_project_name
, scc_local_path)) |
| 620 |
| 621 self.file.write(self.dspheader % locals()) |
| 622 |
| 623 self.file.write('\t<Platforms>\n') |
| 624 for platform in self.platforms: |
| 625 self.file.write( |
| 626 '\t\t<Platform\n' |
| 627 '\t\t\tName="%s"/>\n' % platform) |
| 628 self.file.write('\t</Platforms>\n') |
| 629 |
| 630 if self.version_num >= 8.0: |
| 631 self.file.write('\t<ToolFiles>\n' |
| 632 '\t</ToolFiles>\n') |
| 633 |
| 634 def PrintProject(self): |
| 635 self.file.write('\t<Configurations>\n') |
| 636 |
| 637 confkeys = sorted(self.configs.keys()) |
| 638 for kind in confkeys: |
| 639 variant = self.configs[kind].variant |
| 640 platform = self.configs[kind].platform |
| 641 outdir = self.configs[kind].outdir |
| 642 buildtarget = self.configs[kind].buildtarget |
| 643 runfile = self.configs[kind].runfile |
| 644 cmdargs = self.configs[kind].cmdargs |
| 645 |
| 646 env_has_buildtarget = 'MSVSBUILDTARGET' in self.env |
| 647 if not env_has_buildtarget: |
| 648 self.env['MSVSBUILDTARGET'] = buildtarget |
| 649 |
| 650 starting = 'echo Starting SCons && ' |
| 651 if cmdargs: |
| 652 cmdargs = ' ' + cmdargs |
| 653 else: |
| 654 cmdargs = '' |
| 655 buildcmd = xmlify(starting + self.env.subst('$MSVSBUILDCOM', 1) +
cmdargs) |
| 656 rebuildcmd = xmlify(starting + self.env.subst('$MSVSREBUILDCOM', 1)
+ cmdargs) |
| 657 cleancmd = xmlify(starting + self.env.subst('$MSVSCLEANCOM', 1) +
cmdargs) |
| 658 |
| 659 preprocdefs = xmlify(';'.join(processDefines(self.env.get('CPPDEFINE
S', [])))) |
| 660 includepath = xmlify(';'.join(self.env.get('CPPPATH', []))) |
| 661 |
| 662 if not env_has_buildtarget: |
| 663 del self.env['MSVSBUILDTARGET'] |
| 664 |
| 665 self.file.write(self.dspconfiguration % locals()) |
| 666 |
| 667 self.file.write('\t</Configurations>\n') |
| 668 |
| 669 if self.version_num >= 7.1: |
| 670 self.file.write('\t<References>\n' |
| 671 '\t</References>\n') |
| 672 |
| 673 self.PrintSourceFiles() |
| 674 |
| 675 self.file.write('</VisualStudioProject>\n') |
| 676 |
| 677 if self.nokeep == 0: |
| 678 # now we pickle some data and add it to the file -- MSDEV will ignor
e it. |
| 679 pdata = pickle.dumps(self.configs,1) |
| 680 pdata = base64.encodestring(pdata) |
| 681 self.file.write('<!-- SCons Data:\n' + pdata + '\n') |
| 682 pdata = pickle.dumps(self.sources,1) |
| 683 pdata = base64.encodestring(pdata) |
| 684 self.file.write(pdata + '-->\n') |
| 685 |
| 686 def printSources(self, hierarchy, commonprefix): |
| 687 sorteditems = sorted(hierarchy.items(), key=lambda a: a[0].lower()) |
| 688 |
| 689 # First folders, then files |
| 690 for key, value in sorteditems: |
| 691 if SCons.Util.is_Dict(value): |
| 692 self.file.write('\t\t\t<Filter\n' |
| 693 '\t\t\t\tName="%s"\n' |
| 694 '\t\t\t\tFilter="">\n' % (key)) |
| 695 self.printSources(value, commonprefix) |
| 696 self.file.write('\t\t\t</Filter>\n') |
| 697 |
| 698 for key, value in sorteditems: |
| 699 if SCons.Util.is_String(value): |
| 700 file = value |
| 701 if commonprefix: |
| 702 file = os.path.join(commonprefix, value) |
| 703 file = os.path.normpath(file) |
| 704 self.file.write('\t\t\t<File\n' |
| 705 '\t\t\t\tRelativePath="%s">\n' |
| 706 '\t\t\t</File>\n' % (file)) |
| 707 |
| 708 def PrintSourceFiles(self): |
| 709 categories = {'Source Files': 'cpp;c;cxx;l;y;def;odl;idl;hpj;bat', |
| 710 'Header Files': 'h;hpp;hxx;hm;inl', |
| 711 'Local Headers': 'h;hpp;hxx;hm;inl', |
| 712 'Resource Files': 'r;rc;ico;cur;bmp;dlg;rc2;rct;bin;cnt;rt
f;gif;jpg;jpeg;jpe', |
| 713 'Other Files': ''} |
| 714 |
| 715 self.file.write('\t<Files>\n') |
| 716 |
| 717 cats = sorted([k for k in categories.keys() if self.sources[k]], |
| 718 key=lambda a: a.lower()) |
| 719 for kind in cats: |
| 720 if len(cats) > 1: |
| 721 self.file.write('\t\t<Filter\n' |
| 722 '\t\t\tName="%s"\n' |
| 723 '\t\t\tFilter="%s">\n' % (kind, categories[kind]
)) |
| 724 |
| 725 sources = self.sources[kind] |
| 726 |
| 727 # First remove any common prefix |
| 728 commonprefix = None |
| 729 if len(sources) > 1: |
| 730 s = list(map(os.path.normpath, sources)) |
| 731 # take the dirname because the prefix may include parts |
| 732 # of the filenames (e.g. if you have 'dir\abcd' and |
| 733 # 'dir\acde' then the cp will be 'dir\a' ) |
| 734 cp = os.path.dirname( os.path.commonprefix(s) ) |
| 735 if cp and s[0][len(cp)] == os.sep: |
| 736 # +1 because the filename starts after the separator |
| 737 sources = [s[len(cp)+1:] for s in sources] |
| 738 commonprefix = cp |
| 739 elif len(sources) == 1: |
| 740 commonprefix = os.path.dirname( sources[0] ) |
| 741 sources[0] = os.path.basename( sources[0] ) |
| 742 |
| 743 hierarchy = makeHierarchy(sources) |
| 744 self.printSources(hierarchy, commonprefix=commonprefix) |
| 745 |
| 746 if len(cats)>1: |
| 747 self.file.write('\t\t</Filter>\n') |
| 748 |
| 749 # add the SConscript file outside of the groups |
| 750 self.file.write('\t\t<File\n' |
| 751 '\t\t\tRelativePath="%s">\n' |
| 752 '\t\t</File>\n' % str(self.sconscript)) |
| 753 |
| 754 self.file.write('\t</Files>\n' |
| 755 '\t<Globals>\n' |
| 756 '\t</Globals>\n') |
| 757 |
| 758 def Parse(self): |
| 759 try: |
| 760 dspfile = open(self.dspabs,'r') |
| 761 except IOError: |
| 762 return # doesn't exist yet, so can't add anything to configs. |
| 763 |
| 764 line = dspfile.readline() |
| 765 while line: |
| 766 if line.find('<!-- SCons Data:') > -1: |
| 767 break |
| 768 line = dspfile.readline() |
| 769 |
| 770 line = dspfile.readline() |
| 771 datas = line |
| 772 while line and line != '\n': |
| 773 line = dspfile.readline() |
| 774 datas = datas + line |
| 775 |
| 776 # OK, we've found our little pickled cache of data. |
| 777 try: |
| 778 datas = base64.decodestring(datas) |
| 779 data = pickle.loads(datas) |
| 780 except KeyboardInterrupt: |
| 781 raise |
| 782 except: |
| 783 return # unable to unpickle any data for some reason |
| 784 |
| 785 self.configs.update(data) |
| 786 |
| 787 data = None |
| 788 line = dspfile.readline() |
| 789 datas = line |
| 790 while line and line != '\n': |
| 791 line = dspfile.readline() |
| 792 datas = datas + line |
| 793 |
| 794 # OK, we've found our little pickled cache of data. |
| 795 try: |
| 796 datas = base64.decodestring(datas) |
| 797 data = pickle.loads(datas) |
| 798 except KeyboardInterrupt: |
| 799 raise |
| 800 except: |
| 801 return # unable to unpickle any data for some reason |
| 802 |
| 803 self.sources.update(data) |
| 804 |
| 805 def Build(self): |
| 806 try: |
| 807 self.file = open(self.dspabs,'w') |
| 808 except IOError, detail: |
| 809 raise SCons.Errors.InternalError('Unable to open "' + self.dspabs +
'" for writing:' + str(detail)) |
| 810 else: |
| 811 self.PrintHeader() |
| 812 self.PrintProject() |
| 813 self.file.close() |
| 814 |
| 815 class _DSWGenerator(object): |
| 816 """ Base class for DSW generators """ |
| 817 def __init__(self, dswfile, source, env): |
| 818 self.dswfile = os.path.normpath(str(dswfile)) |
| 819 self.env = env |
| 820 |
| 821 if 'projects' not in env: |
| 822 raise SCons.Errors.UserError("You must specify a 'projects' argument
to create an MSVSSolution.") |
| 823 projects = env['projects'] |
| 824 if not SCons.Util.is_List(projects): |
| 825 raise SCons.Errors.InternalError("The 'projects' argument must be a
list of nodes.") |
| 826 projects = SCons.Util.flatten(projects) |
| 827 if len(projects) < 1: |
| 828 raise SCons.Errors.UserError("You must specify at least one project
to create an MSVSSolution.") |
| 829 self.dspfiles = list(map(str, projects)) |
| 830 |
| 831 if 'name' in self.env: |
| 832 self.name = self.env['name'] |
| 833 else: |
| 834 self.name = os.path.basename(SCons.Util.splitext(self.dswfile)[0]) |
| 835 self.name = self.env.subst(self.name) |
| 836 |
| 837 def Build(self): |
| 838 pass |
| 839 |
| 840 class _GenerateV7DSW(_DSWGenerator): |
| 841 """Generates a Solution file for MSVS .NET""" |
| 842 def __init__(self, dswfile, source, env): |
| 843 _DSWGenerator.__init__(self, dswfile, source, env) |
| 844 |
| 845 self.file = None |
| 846 self.version = self.env['MSVS_VERSION'] |
| 847 self.version_num, self.suite = msvs_parse_version(self.version) |
| 848 self.versionstr = '7.00' |
| 849 if self.version_num >= 8.0: |
| 850 self.versionstr = '9.00' |
| 851 elif self.version_num >= 7.1: |
| 852 self.versionstr = '8.00' |
| 853 if self.version_num >= 8.0: |
| 854 self.versionstr = '9.00' |
| 855 |
| 856 if 'slnguid' in env and env['slnguid']: |
| 857 self.slnguid = env['slnguid'] |
| 858 else: |
| 859 self.slnguid = _generateGUID(dswfile, self.name) |
| 860 |
| 861 self.configs = {} |
| 862 |
| 863 self.nokeep = 0 |
| 864 if 'nokeep' in env and env['variant'] != 0: |
| 865 self.nokeep = 1 |
| 866 |
| 867 if self.nokeep == 0 and os.path.exists(self.dswfile): |
| 868 self.Parse() |
| 869 |
| 870 def AddConfig(self, variant, dswfile=dswfile): |
| 871 config = Config() |
| 872 |
| 873 match = re.match('(.*)\|(.*)', variant) |
| 874 if match: |
| 875 config.variant = match.group(1) |
| 876 config.platform = match.group(2) |
| 877 else: |
| 878 config.variant = variant |
| 879 config.platform = 'Win32' |
| 880 |
| 881 self.configs[variant] = config |
| 882 print "Adding '" + self.name + ' - ' + config.variant + '|' + config
.platform + "' to '" + str(dswfile) + "'" |
| 883 |
| 884 if 'variant' not in env: |
| 885 raise SCons.Errors.InternalError("You must specify a 'variant' argum
ent (i.e. 'Debug' or " +\ |
| 886 "'Release') to create an MSVS Solution File.") |
| 887 elif SCons.Util.is_String(env['variant']): |
| 888 AddConfig(self, env['variant']) |
| 889 elif SCons.Util.is_List(env['variant']): |
| 890 for variant in env['variant']: |
| 891 AddConfig(self, variant) |
| 892 |
| 893 self.platforms = [] |
| 894 for key in self.configs.keys(): |
| 895 platform = self.configs[key].platform |
| 896 if not platform in self.platforms: |
| 897 self.platforms.append(platform) |
| 898 |
| 899 def Parse(self): |
| 900 try: |
| 901 dswfile = open(self.dswfile,'r') |
| 902 except IOError: |
| 903 return # doesn't exist yet, so can't add anything to configs. |
| 904 |
| 905 line = dswfile.readline() |
| 906 while line: |
| 907 if line[:9] == "EndGlobal": |
| 908 break |
| 909 line = dswfile.readline() |
| 910 |
| 911 line = dswfile.readline() |
| 912 datas = line |
| 913 while line: |
| 914 line = dswfile.readline() |
| 915 datas = datas + line |
| 916 |
| 917 # OK, we've found our little pickled cache of data. |
| 918 try: |
| 919 datas = base64.decodestring(datas) |
| 920 data = pickle.loads(datas) |
| 921 except KeyboardInterrupt: |
| 922 raise |
| 923 except: |
| 924 return # unable to unpickle any data for some reason |
| 925 |
| 926 self.configs.update(data) |
| 927 |
| 928 def PrintSolution(self): |
| 929 """Writes a solution file""" |
| 930 self.file.write('Microsoft Visual Studio Solution File, Format Version %
s\n' % self.versionstr ) |
| 931 if self.version_num >= 8.0: |
| 932 self.file.write('# Visual Studio 2005\n') |
| 933 for p in self.dspfiles: |
| 934 name = os.path.basename(p) |
| 935 base, suffix = SCons.Util.splitext(name) |
| 936 if suffix == '.vcproj': |
| 937 name = base |
| 938 guid = _generateGUID(p, '') |
| 939 self.file.write('Project("%s") = "%s", "%s", "%s"\n' |
| 940 % ( external_makefile_guid, name, p, guid ) ) |
| 941 if self.version_num >= 7.1 and self.version_num < 8.0: |
| 942 self.file.write('\tProjectSection(ProjectDependencies) = postPro
ject\n' |
| 943 '\tEndProjectSection\n') |
| 944 self.file.write('EndProject\n') |
| 945 |
| 946 self.file.write('Global\n') |
| 947 |
| 948 env = self.env |
| 949 if 'MSVS_SCC_PROVIDER' in env: |
| 950 dspfile_base = os.path.basename(self.dspfile) |
| 951 slnguid = self.slnguid |
| 952 scc_provider = env.get('MSVS_SCC_PROVIDER', '') |
| 953 scc_provider = scc_provider.replace(' ', r'\u0020') |
| 954 scc_project_name = env.get('MSVS_SCC_PROJECT_NAME', '') |
| 955 # scc_aux_path = env.get('MSVS_SCC_AUX_PATH', '') |
| 956 scc_local_path = env.get('MSVS_SCC_LOCAL_PATH', '') |
| 957 scc_project_base_path = env.get('MSVS_SCC_PROJECT_BASE_PATH', '') |
| 958 # project_guid = env.get('MSVS_PROJECT_GUID', '') |
| 959 |
| 960 self.file.write('\tGlobalSection(SourceCodeControl) = preSolution\n' |
| 961 '\t\tSccNumberOfProjects = 2\n' |
| 962 '\t\tSccProjectUniqueName0 = %(dspfile_base)s\n' |
| 963 '\t\tSccLocalPath0 = %(scc_local_path)s\n' |
| 964 '\t\tCanCheckoutShared = true\n' |
| 965 '\t\tSccProjectFilePathRelativizedFromConnection0 =
%(scc_project_base_path)s\n' |
| 966 '\t\tSccProjectName1 = %(scc_project_name)s\n' |
| 967 '\t\tSccLocalPath1 = %(scc_local_path)s\n' |
| 968 '\t\tSccProvider1 = %(scc_provider)s\n' |
| 969 '\t\tCanCheckoutShared = true\n' |
| 970 '\t\tSccProjectFilePathRelativizedFromConnection1 =
%(scc_project_base_path)s\n' |
| 971 '\t\tSolutionUniqueID = %(slnguid)s\n' |
| 972 '\tEndGlobalSection\n' % locals()) |
| 973 |
| 974 if self.version_num >= 8.0: |
| 975 self.file.write('\tGlobalSection(SolutionConfigurationPlatforms) = p
reSolution\n') |
| 976 else: |
| 977 self.file.write('\tGlobalSection(SolutionConfiguration) = preSolutio
n\n') |
| 978 |
| 979 confkeys = sorted(self.configs.keys()) |
| 980 cnt = 0 |
| 981 for name in confkeys: |
| 982 variant = self.configs[name].variant |
| 983 platform = self.configs[name].platform |
| 984 if self.version_num >= 8.0: |
| 985 self.file.write('\t\t%s|%s = %s|%s\n' % (variant, platform, vari
ant, platform)) |
| 986 else: |
| 987 self.file.write('\t\tConfigName.%d = %s\n' % (cnt, variant)) |
| 988 cnt = cnt + 1 |
| 989 self.file.write('\tEndGlobalSection\n') |
| 990 if self.version_num < 7.1: |
| 991 self.file.write('\tGlobalSection(ProjectDependencies) = postSolution
\n' |
| 992 '\tEndGlobalSection\n') |
| 993 if self.version_num >= 8.0: |
| 994 self.file.write('\tGlobalSection(ProjectConfigurationPlatforms) = po
stSolution\n') |
| 995 else: |
| 996 self.file.write('\tGlobalSection(ProjectConfiguration) = postSolutio
n\n') |
| 997 |
| 998 for name in confkeys: |
| 999 variant = self.configs[name].variant |
| 1000 platform = self.configs[name].platform |
| 1001 if self.version_num >= 8.0: |
| 1002 for p in self.dspfiles: |
| 1003 guid = _generateGUID(p, '') |
| 1004 self.file.write('\t\t%s.%s|%s.ActiveCfg = %s|%s\n' |
| 1005 '\t\t%s.%s|%s.Build.0 = %s|%s\n' % (guid,va
riant,platform,variant,platform,guid,variant,platform,variant,platform)) |
| 1006 else: |
| 1007 for p in self.dspfiles: |
| 1008 guid = _generateGUID(p, '') |
| 1009 self.file.write('\t\t%s.%s.ActiveCfg = %s|%s\n' |
| 1010 '\t\t%s.%s.Build.0 = %s|%s\n' %(guid,varian
t,variant,platform,guid,variant,variant,platform)) |
| 1011 |
| 1012 self.file.write('\tEndGlobalSection\n') |
| 1013 |
| 1014 if self.version_num >= 8.0: |
| 1015 self.file.write('\tGlobalSection(SolutionProperties) = preSolution\n
' |
| 1016 '\t\tHideSolutionNode = FALSE\n' |
| 1017 '\tEndGlobalSection\n') |
| 1018 else: |
| 1019 self.file.write('\tGlobalSection(ExtensibilityGlobals) = postSolutio
n\n' |
| 1020 '\tEndGlobalSection\n' |
| 1021 '\tGlobalSection(ExtensibilityAddIns) = postSolution
\n' |
| 1022 '\tEndGlobalSection\n') |
| 1023 self.file.write('EndGlobal\n') |
| 1024 if self.nokeep == 0: |
| 1025 pdata = pickle.dumps(self.configs,1) |
| 1026 pdata = base64.encodestring(pdata) |
| 1027 self.file.write(pdata + '\n') |
| 1028 |
| 1029 def Build(self): |
| 1030 try: |
| 1031 self.file = open(self.dswfile,'w') |
| 1032 except IOError, detail: |
| 1033 raise SCons.Errors.InternalError('Unable to open "' + self.dswfile +
'" for writing:' + str(detail)) |
| 1034 else: |
| 1035 self.PrintSolution() |
| 1036 self.file.close() |
| 1037 |
| 1038 V6DSWHeader = """\ |
| 1039 Microsoft Developer Studio Workspace File, Format Version 6.00 |
| 1040 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! |
| 1041 |
| 1042 ############################################################################### |
| 1043 |
| 1044 Project: "%(name)s"="%(dspfile)s" - Package Owner=<4> |
| 1045 |
| 1046 Package=<5> |
| 1047 {{{ |
| 1048 }}} |
| 1049 |
| 1050 Package=<4> |
| 1051 {{{ |
| 1052 }}} |
| 1053 |
| 1054 ############################################################################### |
| 1055 |
| 1056 Global: |
| 1057 |
| 1058 Package=<5> |
| 1059 {{{ |
| 1060 }}} |
| 1061 |
| 1062 Package=<3> |
| 1063 {{{ |
| 1064 }}} |
| 1065 |
| 1066 ############################################################################### |
| 1067 """ |
| 1068 |
| 1069 class _GenerateV6DSW(_DSWGenerator): |
| 1070 """Generates a Workspace file for MSVS 6.0""" |
| 1071 |
| 1072 def PrintWorkspace(self): |
| 1073 """ writes a DSW file """ |
| 1074 name = self.name |
| 1075 dspfile = self.dspfiles[0] |
| 1076 self.file.write(V6DSWHeader % locals()) |
| 1077 |
| 1078 def Build(self): |
| 1079 try: |
| 1080 self.file = open(self.dswfile,'w') |
| 1081 except IOError, detail: |
| 1082 raise SCons.Errors.InternalError('Unable to open "' + self.dswfile +
'" for writing:' + str(detail)) |
| 1083 else: |
| 1084 self.PrintWorkspace() |
| 1085 self.file.close() |
| 1086 |
| 1087 |
| 1088 def GenerateDSP(dspfile, source, env): |
| 1089 """Generates a Project file based on the version of MSVS that is being used"
"" |
| 1090 |
| 1091 version_num = 6.0 |
| 1092 if 'MSVS_VERSION' in env: |
| 1093 version_num, suite = msvs_parse_version(env['MSVS_VERSION']) |
| 1094 if version_num >= 7.0: |
| 1095 g = _GenerateV7DSP(dspfile, source, env) |
| 1096 g.Build() |
| 1097 else: |
| 1098 g = _GenerateV6DSP(dspfile, source, env) |
| 1099 g.Build() |
| 1100 |
| 1101 def GenerateDSW(dswfile, source, env): |
| 1102 """Generates a Solution/Workspace file based on the version of MSVS that is
being used""" |
| 1103 |
| 1104 version_num = 6.0 |
| 1105 if 'MSVS_VERSION' in env: |
| 1106 version_num, suite = msvs_parse_version(env['MSVS_VERSION']) |
| 1107 if version_num >= 7.0: |
| 1108 g = _GenerateV7DSW(dswfile, source, env) |
| 1109 g.Build() |
| 1110 else: |
| 1111 g = _GenerateV6DSW(dswfile, source, env) |
| 1112 g.Build() |
| 1113 |
| 1114 |
| 1115 ############################################################################## |
| 1116 # Above here are the classes and functions for generation of |
| 1117 # DSP/DSW/SLN/VCPROJ files. |
| 1118 ############################################################################## |
| 1119 |
| 1120 def GetMSVSProjectSuffix(target, source, env, for_signature): |
| 1121 return env['MSVS']['PROJECTSUFFIX'] |
| 1122 |
| 1123 def GetMSVSSolutionSuffix(target, source, env, for_signature): |
| 1124 return env['MSVS']['SOLUTIONSUFFIX'] |
| 1125 |
| 1126 def GenerateProject(target, source, env): |
| 1127 # generate the dsp file, according to the version of MSVS. |
| 1128 builddspfile = target[0] |
| 1129 dspfile = builddspfile.srcnode() |
| 1130 |
| 1131 # this detects whether or not we're using a VariantDir |
| 1132 if not dspfile is builddspfile: |
| 1133 try: |
| 1134 bdsp = open(str(builddspfile), "w+") |
| 1135 except IOError, detail: |
| 1136 print 'Unable to open "' + str(dspfile) + '" for writing:',detail,'\
n' |
| 1137 raise |
| 1138 |
| 1139 bdsp.write("This is just a placeholder file.\nThe real project file is h
ere:\n%s\n" % dspfile.get_abspath()) |
| 1140 |
| 1141 GenerateDSP(dspfile, source, env) |
| 1142 |
| 1143 if env.get('auto_build_solution', 1): |
| 1144 builddswfile = target[1] |
| 1145 dswfile = builddswfile.srcnode() |
| 1146 |
| 1147 if not dswfile is builddswfile: |
| 1148 |
| 1149 try: |
| 1150 bdsw = open(str(builddswfile), "w+") |
| 1151 except IOError, detail: |
| 1152 print 'Unable to open "' + str(dspfile) + '" for writing:',detai
l,'\n' |
| 1153 raise |
| 1154 |
| 1155 bdsw.write("This is just a placeholder file.\nThe real workspace fil
e is here:\n%s\n" % dswfile.get_abspath()) |
| 1156 |
| 1157 GenerateDSW(dswfile, source, env) |
| 1158 |
| 1159 def GenerateSolution(target, source, env): |
| 1160 GenerateDSW(target[0], source, env) |
| 1161 |
| 1162 def projectEmitter(target, source, env): |
| 1163 """Sets up the DSP dependencies.""" |
| 1164 |
| 1165 # todo: Not sure what sets source to what user has passed as target, |
| 1166 # but this is what happens. When that is fixed, we also won't have |
| 1167 # to make the user always append env['MSVSPROJECTSUFFIX'] to target. |
| 1168 if source[0] == target[0]: |
| 1169 source = [] |
| 1170 |
| 1171 # make sure the suffix is correct for the version of MSVS we're running. |
| 1172 (base, suff) = SCons.Util.splitext(str(target[0])) |
| 1173 suff = env.subst('$MSVSPROJECTSUFFIX') |
| 1174 target[0] = base + suff |
| 1175 |
| 1176 if not source: |
| 1177 source = 'prj_inputs:' |
| 1178 source = source + env.subst('$MSVSSCONSCOM', 1) |
| 1179 source = source + env.subst('$MSVSENCODING', 1) |
| 1180 |
| 1181 if 'buildtarget' in env and env['buildtarget'] != None: |
| 1182 if SCons.Util.is_String(env['buildtarget']): |
| 1183 source = source + ' "%s"' % env['buildtarget'] |
| 1184 elif SCons.Util.is_List(env['buildtarget']): |
| 1185 for bt in env['buildtarget']: |
| 1186 if SCons.Util.is_String(bt): |
| 1187 source = source + ' "%s"' % bt |
| 1188 else: |
| 1189 try: source = source + ' "%s"' % bt.get_abspath() |
| 1190 except AttributeError: raise SCons.Errors.InternalError(
"buildtarget can be a string, a node, a list of strings or nodes, or None") |
| 1191 else: |
| 1192 try: source = source + ' "%s"' % env['buildtarget'].get_abspath(
) |
| 1193 except AttributeError: raise SCons.Errors.InternalError("buildta
rget can be a string, a node, a list of strings or nodes, or None") |
| 1194 |
| 1195 if 'outdir' in env and env['outdir'] != None: |
| 1196 if SCons.Util.is_String(env['outdir']): |
| 1197 source = source + ' "%s"' % env['outdir'] |
| 1198 elif SCons.Util.is_List(env['outdir']): |
| 1199 for s in env['outdir']: |
| 1200 if SCons.Util.is_String(s): |
| 1201 source = source + ' "%s"' % s |
| 1202 else: |
| 1203 try: source = source + ' "%s"' % s.get_abspath() |
| 1204 except AttributeError: raise SCons.Errors.InternalError(
"outdir can be a string, a node, a list of strings or nodes, or None") |
| 1205 else: |
| 1206 try: source = source + ' "%s"' % env['outdir'].get_abspath() |
| 1207 except AttributeError: raise SCons.Errors.InternalError("outdir
can be a string, a node, a list of strings or nodes, or None") |
| 1208 |
| 1209 if 'name' in env: |
| 1210 if SCons.Util.is_String(env['name']): |
| 1211 source = source + ' "%s"' % env['name'] |
| 1212 else: |
| 1213 raise SCons.Errors.InternalError("name must be a string") |
| 1214 |
| 1215 if 'variant' in env: |
| 1216 if SCons.Util.is_String(env['variant']): |
| 1217 source = source + ' "%s"' % env['variant'] |
| 1218 elif SCons.Util.is_List(env['variant']): |
| 1219 for variant in env['variant']: |
| 1220 if SCons.Util.is_String(variant): |
| 1221 source = source + ' "%s"' % variant |
| 1222 else: |
| 1223 raise SCons.Errors.InternalError("name must be a string
or a list of strings") |
| 1224 else: |
| 1225 raise SCons.Errors.InternalError("variant must be a string or a
list of strings") |
| 1226 else: |
| 1227 raise SCons.Errors.InternalError("variant must be specified") |
| 1228 |
| 1229 for s in _DSPGenerator.srcargs: |
| 1230 if s in env: |
| 1231 if SCons.Util.is_String(env[s]): |
| 1232 source = source + ' "%s' % env[s] |
| 1233 elif SCons.Util.is_List(env[s]): |
| 1234 for t in env[s]: |
| 1235 if SCons.Util.is_String(t): |
| 1236 source = source + ' "%s"' % t |
| 1237 else: |
| 1238 raise SCons.Errors.InternalError(s + " must be a str
ing or a list of strings") |
| 1239 else: |
| 1240 raise SCons.Errors.InternalError(s + " must be a string or a
list of strings") |
| 1241 |
| 1242 source = source + ' "%s"' % str(target[0]) |
| 1243 source = [SCons.Node.Python.Value(source)] |
| 1244 |
| 1245 targetlist = [target[0]] |
| 1246 sourcelist = source |
| 1247 |
| 1248 if env.get('auto_build_solution', 1): |
| 1249 env['projects'] = targetlist |
| 1250 t, s = solutionEmitter(target, target, env) |
| 1251 targetlist = targetlist + t |
| 1252 |
| 1253 return (targetlist, sourcelist) |
| 1254 |
| 1255 def solutionEmitter(target, source, env): |
| 1256 """Sets up the DSW dependencies.""" |
| 1257 |
| 1258 # todo: Not sure what sets source to what user has passed as target, |
| 1259 # but this is what happens. When that is fixed, we also won't have |
| 1260 # to make the user always append env['MSVSSOLUTIONSUFFIX'] to target. |
| 1261 if source[0] == target[0]: |
| 1262 source = [] |
| 1263 |
| 1264 # make sure the suffix is correct for the version of MSVS we're running. |
| 1265 (base, suff) = SCons.Util.splitext(str(target[0])) |
| 1266 suff = env.subst('$MSVSSOLUTIONSUFFIX') |
| 1267 target[0] = base + suff |
| 1268 |
| 1269 if not source: |
| 1270 source = 'sln_inputs:' |
| 1271 |
| 1272 if 'name' in env: |
| 1273 if SCons.Util.is_String(env['name']): |
| 1274 source = source + ' "%s"' % env['name'] |
| 1275 else: |
| 1276 raise SCons.Errors.InternalError("name must be a string") |
| 1277 |
| 1278 if 'variant' in env: |
| 1279 if SCons.Util.is_String(env['variant']): |
| 1280 source = source + ' "%s"' % env['variant'] |
| 1281 elif SCons.Util.is_List(env['variant']): |
| 1282 for variant in env['variant']: |
| 1283 if SCons.Util.is_String(variant): |
| 1284 source = source + ' "%s"' % variant |
| 1285 else: |
| 1286 raise SCons.Errors.InternalError("name must be a string
or a list of strings") |
| 1287 else: |
| 1288 raise SCons.Errors.InternalError("variant must be a string or a
list of strings") |
| 1289 else: |
| 1290 raise SCons.Errors.InternalError("variant must be specified") |
| 1291 |
| 1292 if 'slnguid' in env: |
| 1293 if SCons.Util.is_String(env['slnguid']): |
| 1294 source = source + ' "%s"' % env['slnguid'] |
| 1295 else: |
| 1296 raise SCons.Errors.InternalError("slnguid must be a string") |
| 1297 |
| 1298 if 'projects' in env: |
| 1299 if SCons.Util.is_String(env['projects']): |
| 1300 source = source + ' "%s"' % env['projects'] |
| 1301 elif SCons.Util.is_List(env['projects']): |
| 1302 for t in env['projects']: |
| 1303 if SCons.Util.is_String(t): |
| 1304 source = source + ' "%s"' % t |
| 1305 |
| 1306 source = source + ' "%s"' % str(target[0]) |
| 1307 source = [SCons.Node.Python.Value(source)] |
| 1308 |
| 1309 return ([target[0]], source) |
| 1310 |
| 1311 projectAction = SCons.Action.Action(GenerateProject, None) |
| 1312 |
| 1313 solutionAction = SCons.Action.Action(GenerateSolution, None) |
| 1314 |
| 1315 projectBuilder = SCons.Builder.Builder(action = '$MSVSPROJECTCOM', |
| 1316 suffix = '$MSVSPROJECTSUFFIX', |
| 1317 emitter = projectEmitter) |
| 1318 |
| 1319 solutionBuilder = SCons.Builder.Builder(action = '$MSVSSOLUTIONCOM', |
| 1320 suffix = '$MSVSSOLUTIONSUFFIX', |
| 1321 emitter = solutionEmitter) |
| 1322 |
| 1323 default_MSVS_SConscript = None |
| 1324 |
| 1325 def generate(env): |
| 1326 """Add Builders and construction variables for Microsoft Visual |
| 1327 Studio project files to an Environment.""" |
| 1328 try: |
| 1329 env['BUILDERS']['MSVSProject'] |
| 1330 except KeyError: |
| 1331 env['BUILDERS']['MSVSProject'] = projectBuilder |
| 1332 |
| 1333 try: |
| 1334 env['BUILDERS']['MSVSSolution'] |
| 1335 except KeyError: |
| 1336 env['BUILDERS']['MSVSSolution'] = solutionBuilder |
| 1337 |
| 1338 env['MSVSPROJECTCOM'] = projectAction |
| 1339 env['MSVSSOLUTIONCOM'] = solutionAction |
| 1340 |
| 1341 if SCons.Script.call_stack: |
| 1342 # XXX Need to find a way to abstract this; the build engine |
| 1343 # shouldn't depend on anything in SCons.Script. |
| 1344 env['MSVSSCONSCRIPT'] = SCons.Script.call_stack[0].sconscript |
| 1345 else: |
| 1346 global default_MSVS_SConscript |
| 1347 if default_MSVS_SConscript is None: |
| 1348 default_MSVS_SConscript = env.File('SConstruct') |
| 1349 env['MSVSSCONSCRIPT'] = default_MSVS_SConscript |
| 1350 |
| 1351 env['MSVSSCONS'] = '"%s" -c "%s"' % (python_executable, getExecScriptMain(en
v)) |
| 1352 env['MSVSSCONSFLAGS'] = '-C "${MSVSSCONSCRIPT.dir.abspath}" -f ${MSVSSCONSCR
IPT.name}' |
| 1353 env['MSVSSCONSCOM'] = '$MSVSSCONS $MSVSSCONSFLAGS' |
| 1354 env['MSVSBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' |
| 1355 env['MSVSREBUILDCOM'] = '$MSVSSCONSCOM "$MSVSBUILDTARGET"' |
| 1356 env['MSVSCLEANCOM'] = '$MSVSSCONSCOM -c "$MSVSBUILDTARGET"' |
| 1357 env['MSVSENCODING'] = 'Windows-1252' |
| 1358 |
| 1359 # Set-up ms tools paths for default version |
| 1360 msvc_setup_env_once(env) |
| 1361 |
| 1362 if 'MSVS_VERSION' in env: |
| 1363 version_num, suite = msvs_parse_version(env['MSVS_VERSION']) |
| 1364 else: |
| 1365 (version_num, suite) = (7.0, None) # guess at a default |
| 1366 if 'MSVS' not in env: |
| 1367 env['MSVS'] = {} |
| 1368 if (version_num < 7.0): |
| 1369 env['MSVS']['PROJECTSUFFIX'] = '.dsp' |
| 1370 env['MSVS']['SOLUTIONSUFFIX'] = '.dsw' |
| 1371 else: |
| 1372 env['MSVS']['PROJECTSUFFIX'] = '.vcproj' |
| 1373 env['MSVS']['SOLUTIONSUFFIX'] = '.sln' |
| 1374 |
| 1375 env['GET_MSVSPROJECTSUFFIX'] = GetMSVSProjectSuffix |
| 1376 env['GET_MSVSSOLUTIONSUFFIX'] = GetMSVSSolutionSuffix |
| 1377 env['MSVSPROJECTSUFFIX'] = '${GET_MSVSPROJECTSUFFIX}' |
| 1378 env['MSVSSOLUTIONSUFFIX'] = '${GET_MSVSSOLUTIONSUFFIX}' |
| 1379 env['SCONS_HOME'] = os.environ.get('SCONS_HOME') |
| 1380 |
| 1381 def exists(env): |
| 1382 return msvc_exists() |
| 1383 |
| 1384 # Local Variables: |
| 1385 # tab-width:4 |
| 1386 # indent-tabs-mode:nil |
| 1387 # End: |
| 1388 # vim: set expandtab tabstop=4 shiftwidth=4: |
OLD | NEW |