| OLD | NEW |
| 1 # | 1 # |
| 2 # __COPYRIGHT__ | 2 # __COPYRIGHT__ |
| 3 # | 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining | 4 # Permission is hereby granted, free of charge, to any person obtaining |
| 5 # a copy of this software and associated documentation files (the | 5 # a copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including | 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, | 7 # without limitation the rights to use, copy, modify, merge, publish, |
| 8 # distribute, sublicense, and/or sell copies of the Software, and to | 8 # distribute, sublicense, and/or sell copies of the Software, and to |
| 9 # permit persons to whom the Software is furnished to do so, subject to | 9 # permit persons to whom the Software is furnished to do so, subject to |
| 10 # the following conditions: | 10 # the following conditions: |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 import os | 32 import os |
| 33 import random | 33 import random |
| 34 import re | 34 import re |
| 35 import UserList | 35 import UserList |
| 36 import xml.dom | 36 import xml.dom |
| 37 import xml.dom.minidom | 37 import xml.dom.minidom |
| 38 | 38 |
| 39 import SCons.Node.FS | 39 import SCons.Node.FS |
| 40 import SCons.Script | 40 import SCons.Script |
| 41 | 41 |
| 42 from SCons.Debug import Trace | |
| 43 TODO = 0 | |
| 44 | 42 |
| 45 # Initialize random number generator | 43 # Initialize random number generator |
| 46 random.seed() | 44 random.seed() |
| 47 | 45 |
| 48 | 46 |
| 49 #------------------------------------------------------------------------------ | 47 #------------------------------------------------------------------------------ |
| 50 # Entry point for supplying a fixed map of GUIDs for testing. | 48 # Entry point for supplying a fixed map of GUIDs for testing. |
| 51 | 49 |
| 52 GUIDMap = {} | 50 GUIDMap = {} |
| 53 | 51 |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 def get_msvs_path(self, sln): | 257 def get_msvs_path(self, sln): |
| 260 return self.msvs_name | 258 return self.msvs_name |
| 261 | 259 |
| 262 def MSVSFolder(env, item, *args, **kw): | 260 def MSVSFolder(env, item, *args, **kw): |
| 263 return LookupCreate(_MSVSFolder, item, *args, **kw) | 261 return LookupCreate(_MSVSFolder, item, *args, **kw) |
| 264 | 262 |
| 265 #------------------------------------------------------------------------------ | 263 #------------------------------------------------------------------------------ |
| 266 | 264 |
| 267 class MSVSConfig(object): | 265 class MSVSConfig(object): |
| 268 """Visual Studio configuration.""" | 266 """Visual Studio configuration.""" |
| 269 def __init__(self, Name, config_type, tools=None, **attrs): | 267 def __init__(self, Name, config_type, tools=[], **attrs): |
| 270 """Initializes the configuration. | 268 """Initializes the configuration. |
| 271 | 269 |
| 272 Args: | 270 Args: |
| 273 **attrs: Configuration attributes. | 271 **attrs: Configuration attributes. |
| 274 """ | 272 """ |
| 275 # Special handling for attributes that we want to make more | 273 # Special handling for attributes that we want to make more |
| 276 # convenient for the user. | 274 # convenient for the user. |
| 277 ips = attrs.get('InheritedPropertySheets') | 275 ips = attrs.get('InheritedPropertySheets') |
| 278 if ips: | 276 if ips: |
| 279 if isinstance(ips, list): | 277 if isinstance(ips, list): |
| 280 ips = ';'.join(ips) | 278 ips = ';'.join(ips) |
| 281 attrs['InheritedPropertySheets'] = ips.replace('/', '\\') | 279 attrs['InheritedPropertySheets'] = ips.replace('/', '\\') |
| 282 | 280 |
| 281 tools = tools or [] |
| 282 if not SCons.Util.is_List(tools): |
| 283 tools = [tools] |
| 284 tool_objects = [] |
| 285 for t in tools: |
| 286 if not isinstance(t, MSVSTool): |
| 287 t = MSVSTool(t) |
| 288 tool_objects.append(t) |
| 289 |
| 283 self.Name = Name | 290 self.Name = Name |
| 284 self.config_type = config_type | 291 self.config_type = config_type |
| 285 self.tools = tools | 292 self.tools = tool_objects |
| 286 self.attrs = attrs | 293 self.attrs = attrs |
| 287 | 294 |
| 288 def CreateElement(self, doc, project): | 295 def CreateElement(self, doc): |
| 289 """Creates an element for the configuration. | 296 """Creates an element for the configuration. |
| 290 | 297 |
| 291 Args: | 298 Args: |
| 292 doc: xml.dom.Document object to use for node creation. | 299 doc: xml.dom.Document object to use for node creation. |
| 293 | 300 |
| 294 Returns: | 301 Returns: |
| 295 A new xml.dom.Element for the configuration. | 302 A new xml.dom.Element for the configuration. |
| 296 """ | 303 """ |
| 297 node = doc.createElement(self.config_type) | 304 node = doc.createElement(self.config_type) |
| 298 node.setAttribute('Name', self.Name) | 305 node.setAttribute('Name', self.Name) |
| 299 for k, v in self.attrs.items(): | 306 for k, v in self.attrs.items(): |
| 300 node.setAttribute(k, v) | 307 node.setAttribute(k, v) |
| 301 | 308 for t in self.tools: |
| 302 tools = self.tools | |
| 303 if tools is None: | |
| 304 tools = project.tools or [] | |
| 305 if not SCons.Util.is_List(tools): | |
| 306 tools = [tools] | |
| 307 tool_objects = [] | |
| 308 for t in tools: | |
| 309 if not isinstance(t, MSVSTool): | |
| 310 t = MSVSTool(t) | |
| 311 tool_objects.append(t) | |
| 312 for t in tool_objects: | |
| 313 node.appendChild(t.CreateElement(doc)) | 309 node.appendChild(t.CreateElement(doc)) |
| 314 | |
| 315 return node | 310 return node |
| 316 | 311 |
| 317 | 312 |
| 318 class MSVSFileListBase(FileList): | 313 class MSVSFileListBase(FileList): |
| 319 """Base class for a file list in a Visual Studio project file.""" | 314 """Base class for a file list in a Visual Studio project file.""" |
| 320 | 315 |
| 321 def CreateElement(self, doc, node_func=lambda x: x): | 316 def CreateElement(self, doc, node_func=lambda x: x): |
| 322 """Creates an element for an MSVSFileListBase subclass. | 317 """Creates an element for an MSVSFileListBase subclass. |
| 323 | 318 |
| 324 Args: | 319 Args: |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 | 391 |
| 397 Returns: | 392 Returns: |
| 398 A new xml.dom.Element for the tool. | 393 A new xml.dom.Element for the tool. |
| 399 """ | 394 """ |
| 400 node = doc.createElement('Tool') | 395 node = doc.createElement('Tool') |
| 401 node.setAttribute('Name', self.Name) | 396 node.setAttribute('Name', self.Name) |
| 402 for k, v in self.attrs.items(): | 397 for k, v in self.attrs.items(): |
| 403 node.setAttribute(k, v) | 398 node.setAttribute(k, v) |
| 404 return node | 399 return node |
| 405 | 400 |
| 406 def _format(self): | |
| 407 """Formats a tool specification for debug printing""" | |
| 408 xml_impl = xml.dom.getDOMImplementation() | |
| 409 doc = xml_impl.createDocument(None, 'VisualStudioProject', None) | |
| 410 return self.CreateElement(doc).toprettyxml() | |
| 411 | |
| 412 def diff(self, other): | |
| 413 for key, value in self.attrs.items(): | |
| 414 if other.attrs[key] == value: | |
| 415 del self.attrs[key] | |
| 416 | |
| 417 | 401 |
| 418 class MSVSToolFile(object): | 402 class MSVSToolFile(object): |
| 419 """Visual Studio tool file specification.""" | 403 """Visual Studio tool file specification.""" |
| 420 | 404 |
| 421 def __init__(self, node, **attrs): | 405 def __init__(self, node, **attrs): |
| 422 """Initializes the tool. | 406 """Initializes the tool. |
| 423 | 407 |
| 424 Args: | 408 Args: |
| 425 node: Node for the Tool File | 409 node: Node for the Tool File |
| 426 **attrs: Tool File attributes. | 410 **attrs: Tool File attributes. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 438 def MSVSAction(target, source, env): | 422 def MSVSAction(target, source, env): |
| 439 target[0].Write(env) | 423 target[0].Write(env) |
| 440 | 424 |
| 441 MSVSProjectAction = SCons.Script.Action(MSVSAction, | 425 MSVSProjectAction = SCons.Script.Action(MSVSAction, |
| 442 "Generating Visual Studio project `$TARG
ET' ...") | 426 "Generating Visual Studio project `$TARG
ET' ...") |
| 443 | 427 |
| 444 class _MSVSProject(SCons.Node.FS.File): | 428 class _MSVSProject(SCons.Node.FS.File): |
| 445 """Visual Studio project.""" | 429 """Visual Studio project.""" |
| 446 | 430 |
| 447 entry_type_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}' | 431 entry_type_guid = '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}' |
| 448 initialized = False | |
| 449 | 432 |
| 450 def initialize(self, env, path, name = None, | 433 def initialize(self, env, path, name = None, |
| 451 dependencies = None, | 434 dependencies = None, |
| 452 guid = None, | 435 guid = None, |
| 453 buildtargets = [], | 436 buildtargets = [], |
| 454 files = [], | 437 files = [], |
| 455 root_namespace = None, | 438 root_namespace = None, |
| 456 relative_path_prefix = '', | 439 relative_path_prefix = '', |
| 457 tools = None, | 440 tools = None, |
| 458 configurations = None, | 441 configurations = None): |
| 459 **attrs): | |
| 460 """Initializes the project. | 442 """Initializes the project. |
| 461 | 443 |
| 462 Args: | 444 Args: |
| 463 path: Relative path to project file. | 445 path: Relative path to project file. |
| 464 name: Name of project. If None, the name will be the same as the base | 446 name: Name of project. If None, the name will be the same as the base |
| 465 name of the project file. | 447 name of the project file. |
| 466 dependencies: List of other Project objects this project is dependent | 448 dependencies: List of other Project objects this project is dependent |
| 467 upon, if not None. | 449 upon, if not None. |
| 468 guid: GUID to use for project, if not None. | 450 guid: GUID to use for project, if not None. |
| 469 buildtargets: List of target(s) being built by this project. | 451 buildtargets: List of target(s) being built by this project. |
| 470 files: List of source files for the project. This will be | 452 files: List of source files for the project. This will be |
| 471 supplemented by any source files of buildtargets. | 453 supplemented by any source files of buildtargets. |
| 472 root_namespace: The value of the RootNamespace attribute of the | 454 root_namespace: The value of the RootNamespace attribute of the |
| 473 project, if not None. The default is to use the same | 455 project, if not None. The default is to use the same |
| 474 string as the name. | 456 string as the name. |
| 475 relative_path_prefix: A prefix to be appended to the beginning of | 457 relative_path_prefix: A prefix to be appended to the beginning of |
| 476 every file name in the list. The canonical use is to specify | 458 every file name in the list. The canonical use is to specify |
| 477 './' to make files explicitly relative to the local directory. | 459 './' to make files explicitly relative to the local directory. |
| 478 tools: A list of MSVSTool objects or strings representing | 460 tools: A list of MSVSTool objects or strings representing |
| 479 tools to be used to build this project. This will be used | 461 tools to be used to build this project. This will be used |
| 480 for any configurations that don't provide their own | 462 for any configurations that don't provide their own |
| 481 per-configuration tool list. | 463 per-configuration tool list. |
| 482 configurations: A list of MSVSConfig objects representing | 464 configurations: A list of MSVSConfig objects representing |
| 483 configurations built by this project. | 465 configurations built by this project. |
| 484 """ | 466 """ |
| 467 self.msvs_path = path |
| 468 self.msvs_node = env.File(path) |
| 485 if name is None: | 469 if name is None: |
| 486 if buildtargets: | 470 if buildtargets: |
| 487 name = os.path.splitext(buildtargets[0].name)[0] | 471 name = os.path.splitext(buildtargets[0].name)[0] |
| 488 else: | 472 else: |
| 489 name = os.path.splitext(os.path.basename(path))[0] | 473 name = os.path.splitext(os.path.basename(path))[0] |
| 490 if not root_namespace: | 474 self.msvs_name = name |
| 491 root_namespace or name | 475 self.root_namespace = root_namespace or self.msvs_name |
| 476 self.buildtargets = buildtargets |
| 477 self.relative_path_prefix = relative_path_prefix |
| 478 self.tools = tools |
| 492 | 479 |
| 493 if self.initialized: | |
| 494 # TODO(sgk): fill in | |
| 495 if self.msvs_name != name: | |
| 496 pass | |
| 497 if self.root_namespace != root_namespace: | |
| 498 pass | |
| 499 if self.relative_path_prefix != relative_path_prefix: | |
| 500 pass | |
| 501 if self.guid != guid: | |
| 502 pass | |
| 503 #if self.env != env: | |
| 504 # pass | |
| 505 else: | |
| 506 self.buildtargets = [] | |
| 507 self.configurations = [] | |
| 508 self.dependencies = [] | |
| 509 self.file_configurations = {} | |
| 510 self.files = MSVSFiles([]) | |
| 511 self.tool_files = [] | |
| 512 self.file_lists = [] | |
| 513 self.initialized = True | |
| 514 | |
| 515 self.attrs = attrs | |
| 516 self.env = env | 480 self.env = env |
| 517 self.guid = guid | 481 self.guid = guid |
| 518 self.msvs_name = name | |
| 519 self.msvs_path = path | |
| 520 self.relative_path_prefix = relative_path_prefix | |
| 521 self.root_namespace = root_namespace or self.msvs_name | |
| 522 self.tools = tools | |
| 523 | 482 |
| 524 self.buildtargets.extend(buildtargets) | 483 self.dependencies = list(dependencies or []) |
| 525 self.configurations.extend(configurations or []) | 484 self.configurations = list(configurations or []) |
| 526 self.dependencies.extend(list(dependencies or [])) | 485 self.file_configurations = {} |
| 527 self.AddFiles(files) | 486 self.tool_files = [] |
| 528 | 487 |
| 529 env.Command(self, [], MSVSProjectAction) | 488 if not isinstance(files, MSVSFiles): |
| 489 files = MSVSFiles(self.args2nodes(files)) |
| 490 self.files = files |
| 491 |
| 492 env.Command(self, [], MSVSSolutionAction) |
| 530 | 493 |
| 531 def args2nodes(self, entries): | 494 def args2nodes(self, entries): |
| 532 result = [] | 495 result = [] |
| 533 for entry in entries: | 496 for entry in entries: |
| 534 if SCons.Util.is_String(entry): | 497 if SCons.Util.is_String(entry): |
| 535 entry = self.env.File(entry) | 498 entry = self.env.File(entry) |
| 536 result.append(entry) | 499 result.append(entry) |
| 537 elif hasattr(entry, 'entries'): | 500 elif hasattr(entry, 'entries'): |
| 538 entry.entries = self.args2nodes(entry.entries) | 501 entry.entries = self.args2nodes(entry.entries) |
| 539 result.append(entry) | 502 result.append(entry) |
| 540 elif isinstance(entry, (list, UserList.UserList)): | 503 elif isinstance(entry, (list, UserList.UserList)): |
| 541 result.extend(self.args2nodes(entry)) | 504 result.extend(self.args2nodes(entry)) |
| 542 elif hasattr(entry, 'sources') and entry.sources: | 505 elif hasattr(entry, 'sources') and entry.sources: |
| 543 result.extend(entry.sources) | 506 result.extend(entry.sources) |
| 544 else: | 507 else: |
| 545 result.append(entry.srcnode()) | 508 result.append(entry) |
| 546 return result | 509 return result |
| 547 | 510 |
| 548 def FindFile(self, node): | 511 def FindFile(self, node): |
| 549 try: | 512 try: |
| 550 flat_file_dict = self.flat_file_dict | 513 flat_file_dict = self.flat_file_dict |
| 551 except AttributeError: | 514 except AttributeError: |
| 552 flat_file_dict = {} | 515 flat_file_dict = {} |
| 553 file_list = self.files[:] | 516 file_list = self.files[:] |
| 554 while file_list: | 517 while file_list: |
| 555 entry = file_list.pop(0) | 518 entry = file_list.pop(0) |
| 556 if not isinstance(entry, (list, UserList.UserList)): | 519 if not isinstance(entry, (list, UserList.UserList)): |
| 557 entry = [entry] | 520 entry = [entry] |
| 558 for f in entry: | 521 for f in entry: |
| 559 if hasattr(f, 'entries'): | 522 if hasattr(f, 'entries'): |
| 560 file_list.extend(f.entries) | 523 file_list.extend(f.entries) |
| 561 else: | 524 else: |
| 562 flat_file_dict[f] = True | 525 flat_file_dict[f] = True |
| 563 flat_file_dict[f.srcnode()] = True | |
| 564 if hasattr(f, 'sources'): | 526 if hasattr(f, 'sources'): |
| 565 for s in f.sources: | 527 for s in f.sources: |
| 566 flat_file_dict[s] = True | 528 flat_file_dict[s] = True |
| 567 flat_file_dict[s.srcnode()] = True | |
| 568 self.flat_file_dict = flat_file_dict | 529 self.flat_file_dict = flat_file_dict |
| 569 | 530 |
| 570 return flat_file_dict.get(node) | 531 return flat_file_dict.get(node) |
| 571 | 532 |
| 572 def get_guid(self): | 533 def get_guid(self): |
| 573 if self.guid is None: | 534 if self.guid is None: |
| 574 guid = GUIDMap.get(self.msvs_path) | 535 guid = GUIDMap.get(self.msvs_path) |
| 575 if not guid: | 536 if not guid: |
| 576 # Set GUID from path | 537 # Set GUID from path |
| 577 # TODO(rspangler): This is fragile. | 538 # TODO(rspangler): This is fragile. |
| 578 # 1. We can't just use the project filename sans path, since there | 539 # 1. We can't just use the project filename sans path, since there |
| 579 # could be multiple projects with the same base name (for example, | 540 # could be multiple projects with the same base name (for example, |
| 580 # foo/unittest.vcproj and bar/unittest.vcproj). | 541 # foo/unittest.vcproj and bar/unittest.vcproj). |
| 581 # 2. The path needs to be relative to $SOURCE_ROOT, so that the project | 542 # 2. The path needs to be relative to $SOURCE_ROOT, so that the project |
| 582 # GUID is the same whether it's included from base/base.sln or | 543 # GUID is the same whether it's included from base/base.sln or |
| 583 # foo/bar/baz/baz.sln. | 544 # foo/bar/baz/baz.sln. |
| 584 # 3. The GUID needs to be the same each time this builder is invoked, | 545 # 3. The GUID needs to be the same each time this builder is invoked, |
| 585 # so that we don't need to rebuild the solution when the | 546 # so that we don't need to rebuild the solution when the |
| 586 # project changes. | 547 # project changes. |
| 587 # 4. We should be able to handle pre-built project files by reading the | 548 # 4. We should be able to handle pre-built project files by reading the |
| 588 # GUID from the files. | 549 # GUID from the files. |
| 589 guid = MakeGuid(self.msvs_path) | 550 guid = MakeGuid(self.msvs_path) |
| 590 self.guid = guid | 551 self.guid = guid |
| 591 return self.guid | 552 return self.guid |
| 592 | 553 |
| 593 def get_msvs_path(self, sln): | 554 def get_msvs_path(self, sln): |
| 594 return sln.rel_path(self).replace('/', '\\') | 555 return sln.rel_path(self).replace('/', '\\') |
| 595 | 556 |
| 596 def get_rel_path(self, node): | 557 def get_rel_path(self, node): |
| 597 result = self.relative_path_prefix + self.rel_path(node) | 558 result = self.relative_path_prefix + self.msvs_node.rel_path(node) |
| 598 return result.replace('/', '\\') | 559 return result.replace('/', '\\') |
| 599 | 560 |
| 600 def AddConfig(self, Name, tools=None, **attrs): | 561 def AddConfig(self, Name, tools=None, **attrs): |
| 601 """Adds a configuration to the parent node. | 562 """Adds a configuration to the parent node. |
| 602 | 563 |
| 603 Args: | 564 Args: |
| 604 Name: The name of the configuration. | 565 Name: The name of the configuration. |
| 605 tools: List of tools (strings or Tool objects); may be None. | 566 tools: List of tools (strings or Tool objects); may be None. |
| 606 **attrs: Configuration attributes. | 567 **attrs: Configuration attributes. |
| 607 """ | 568 """ |
| 608 if tools is None: | 569 if tools is None: |
| 609 # No tool list specifically for this configuration, | 570 # No tool list specifically for this configuration, |
| 610 # use the Project's as a default. | 571 # use the Project's as a default. |
| 611 tools = self.tools | 572 tools = self.tools |
| 612 if not attrs.has_key('ConfigurationType'): | |
| 613 # No ConfigurationType specifically for this configuration, | |
| 614 # use the Project's as a default. | |
| 615 try: | |
| 616 attrs['ConfigurationType'] = self.attrs['ConfigurationType'] | |
| 617 except KeyError: | |
| 618 pass | |
| 619 if attrs.has_key('InheritedPropertySheets'): | |
| 620 ips = attrs['InheritedPropertySheets'] | |
| 621 attrs['InheritedPropertySheets'] = self.env.subst(ips) | |
| 622 c = MSVSConfig(Name, 'Configuration', tools=tools, **attrs) | 573 c = MSVSConfig(Name, 'Configuration', tools=tools, **attrs) |
| 623 self.configurations.append(c) | 574 self.configurations.append(c) |
| 624 | 575 |
| 625 def AddFiles(self, files): | 576 def AddFiles(self, files): |
| 626 """Adds files to the project. | 577 """Adds files to the project. |
| 627 | 578 |
| 628 Args: | 579 Args: |
| 629 files: A list of Filter objects and/or relative paths to files. | 580 files: A list of Filter objects and/or relative paths to files. |
| 630 | 581 |
| 631 This makes a copy of the file/filter tree at the time of this call. If you | 582 This makes a copy of the file/filter tree at the time of this call. If you |
| 632 later add files to a Filter object which was passed into a previous call | 583 later add files to a Filter object which was passed into a previous call |
| 633 to AddFiles(), it will not be reflected in this project. | 584 to AddFiles(), it will not be reflected in this project. |
| 634 """ | 585 """ |
| 635 self.file_lists.append(self.args2nodes(files)) | 586 # TODO(rspangler) This also doesn't handle adding files to an existing |
| 636 | 587 # filter. That is, it doesn't merge the trees. |
| 637 def _FilesToSourceFiles(self, files): | 588 self.files.extend(self.args2nodes(files)) |
| 638 file_list = files[:] | |
| 639 result = [] | |
| 640 while file_list: | |
| 641 entry = file_list.pop(0) | |
| 642 if not isinstance(entry, (list, UserList.UserList)): | |
| 643 entry = [entry] | |
| 644 for f in entry: | |
| 645 if hasattr(f, 'entries'): | |
| 646 self._FilesToSourceFiles(f.entries) | |
| 647 result.append(f) | |
| 648 else: | |
| 649 if f.sources: | |
| 650 flist = f.sources | |
| 651 else: | |
| 652 flist = [f] | |
| 653 for x in flist: | |
| 654 result.append(x.srcnode()) | |
| 655 files[:] = result | |
| 656 | |
| 657 def _MergeFiles(self, dest_list, src_list): | |
| 658 for f in src_list: | |
| 659 if f not in dest_list: | |
| 660 dest_list.append(f) | |
| 661 continue | |
| 662 #if hasattr(f, 'entries'): | |
| 663 # self._FilesToSourceFiles(f.entries) | |
| 664 | 589 |
| 665 def AddFileConfig(self, path, Name, tools=None, **attrs): | 590 def AddFileConfig(self, path, Name, tools=None, **attrs): |
| 666 """Adds a configuration to a file. | 591 """Adds a configuration to a file. |
| 667 | 592 |
| 668 Args: | 593 Args: |
| 669 path: Relative path to the file. | 594 path: Relative path to the file. |
| 670 Name: Name of configuration to add. | 595 Name: Name of configuration to add. |
| 671 tools: List of tools (strings or MSVSTool objects); may be None. | 596 tools: List of tools (strings or MSVSTool objects); may be None. |
| 672 **attrs: Configuration attributes. | 597 **attrs: Configuration attributes. |
| 673 | 598 |
| 674 Raises: | 599 Raises: |
| 675 ValueError: Relative path does not match any file added via AddFiles(). | 600 ValueError: Relative path does not match any file added via AddFiles(). |
| 676 """ | 601 """ |
| 677 # Store as the VariantDir node, not as the source node. | |
| 678 node = self.env.File(path) | 602 node = self.env.File(path) |
| 603 if not self.FindFile(node): |
| 604 raise ValueError('AddFileConfig: file "%s" not in project' % path) |
| 679 c = MSVSConfig(Name, 'FileConfiguration', tools=tools, **attrs) | 605 c = MSVSConfig(Name, 'FileConfiguration', tools=tools, **attrs) |
| 680 config_list = self.file_configurations.get(node) | 606 config_list = self.file_configurations.get(node) |
| 681 if config_list is None: | 607 if config_list is None: |
| 682 config_list = [] | 608 config_list = [] |
| 683 self.file_configurations[node] = config_list | 609 self.file_configurations[node] = config_list |
| 684 config_list.append(c) | 610 config_list.append(c) |
| 685 | 611 |
| 686 def AddToolFile(self, path): | 612 def AddToolFile(self, path): |
| 687 """Adds a tool file to the project. | 613 """Adds a tool file to the project. |
| 688 | 614 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 # Add tool files section | 648 # Add tool files section |
| 723 tool_files = self.doc.createElement('ToolFiles') | 649 tool_files = self.doc.createElement('ToolFiles') |
| 724 root.appendChild(tool_files) | 650 root.appendChild(tool_files) |
| 725 for tf in self.tool_files: | 651 for tf in self.tool_files: |
| 726 tool_files.appendChild(tf.CreateElement(self.doc, self)) | 652 tool_files.appendChild(tf.CreateElement(self.doc, self)) |
| 727 | 653 |
| 728 # Add configurations section | 654 # Add configurations section |
| 729 configs = self.doc.createElement('Configurations') | 655 configs = self.doc.createElement('Configurations') |
| 730 root.appendChild(configs) | 656 root.appendChild(configs) |
| 731 for c in self.configurations: | 657 for c in self.configurations: |
| 732 configs.appendChild(c.CreateElement(self.doc, self)) | 658 configs.appendChild(c.CreateElement(self.doc)) |
| 733 | 659 |
| 734 # Add empty References section | 660 # Add empty References section |
| 735 root.appendChild(self.doc.createElement('References')) | 661 root.appendChild(self.doc.createElement('References')) |
| 736 | 662 |
| 737 # Add files section | 663 # Add files section |
| 738 root.appendChild(self.files.CreateElement(self.doc, self.CreateFileElement)) | 664 root.appendChild(self.files.CreateElement(self.doc, self.CreateFileElement)) |
| 739 | 665 |
| 740 # Add empty Globals section | 666 # Add empty Globals section |
| 741 root.appendChild(self.doc.createElement('Globals')) | 667 root.appendChild(self.doc.createElement('Globals')) |
| 742 | 668 |
| 743 def CreateFileElement(self, file): | 669 def CreateFileElement(self, file): |
| 744 """Create a DOM node for the specified file. | 670 """Create a DOM node for the specified file. |
| 745 | 671 |
| 746 Args: | 672 Args: |
| 747 file: The file Node being considered. | 673 file: The file Node being considered. |
| 748 | 674 |
| 749 Returns: | 675 Returns: |
| 750 A DOM Node for the File, with a relative path to the current | 676 A DOM Node for the File, with a relative path to the current |
| 751 project object, and any file configurations attached to the | 677 project object, and any file configurations attached to the |
| 752 project. | 678 project. |
| 753 """ | 679 """ |
| 754 | 680 |
| 755 node = self.doc.createElement('File') | 681 node = self.doc.createElement('File') |
| 756 node.setAttribute('RelativePath', self.get_rel_path(file)) | 682 node.setAttribute('RelativePath', self.get_rel_path(file)) |
| 757 for c in self.file_configurations.get(file, []): | 683 for c in self.file_configurations.get(file, []): |
| 758 node.appendChild(c.CreateElement(self.doc, self)) | 684 node.appendChild(c.CreateElement(self.doc)) |
| 759 return node | 685 return node |
| 760 | 686 |
| 761 def VCCLCompilerTool(self, args): | 687 def _AddFileConfigurationDifferences(self, target, source, base_env, file_env)
: |
| 762 default_attrs = { | |
| 763 'BufferSecurityCheck' : "false", | |
| 764 'CompileAs' : 0, # default | |
| 765 'DebugInformationFormat' : 0, # TODO(???) | |
| 766 'DisableSpecificWarnings' : [], | |
| 767 'EnableFiberSafeOptimizations' : "false", | |
| 768 'EnableFunctionLevelLinking' : "false", | |
| 769 'EnableIntrinsicFunctions' : "false", | |
| 770 'FavorSizeOrSpeed' : 0, # favorNone | |
| 771 'InlineFunctionExpansion' : 1, # expandDisable | |
| 772 'MinimalRebuild' : "false", | |
| 773 'OmitFramePointers' : "false", | |
| 774 'Optimization' : 1, # optimizeDisabled TODO(???) | |
| 775 'PreprocessorDefinitions' : [], | |
| 776 'RuntimeLibrary' : TODO, | |
| 777 'RuntimeTypeInfo' : "false", | |
| 778 'StringPooling' : "false", | |
| 779 'SuppressStartupBanner' : "false", | |
| 780 'WarningAsError' : "false", | |
| 781 'WarningLevel' : 1, # warningLevel_1 | |
| 782 'WholeProgramOptimization' : "false", | |
| 783 } | |
| 784 | |
| 785 tool = MSVSTool('VCCLCompilerTool', **default_attrs) | |
| 786 attrs = tool.attrs | |
| 787 | |
| 788 for arg in args: | |
| 789 if arg in ('/c',): | |
| 790 continue | |
| 791 if arg.startswith('/Fo'): | |
| 792 continue | |
| 793 if arg.startswith('/D'): | |
| 794 attrs['PreprocessorDefinitions'].append(arg[2:]) | |
| 795 elif arg == '/EH': | |
| 796 attrs['ExceptionHandling'] = 0 | |
| 797 elif arg == '/GF': | |
| 798 attrs['StringPooling'] = "true" | |
| 799 elif arg == '/GL': | |
| 800 attrs['WholeProgramOptimization'] = "true" | |
| 801 elif arg == '/GM': | |
| 802 attrs['MinimalRebuild'] = "true" | |
| 803 elif arg == '/GR-': | |
| 804 attrs['RuntimeTypeInfo'] = "true" | |
| 805 elif arg == '/Gs': | |
| 806 attrs['BufferSecurityCheck'] = "true" | |
| 807 elif arg == '/Gs-': | |
| 808 attrs['BufferSecurityCheck'] = "false" | |
| 809 elif arg == '/GT': | |
| 810 attrs['EnableFiberSafeOptimizations'] = "true" | |
| 811 elif arg == '/Gy': | |
| 812 attrs['EnableFunctionLevelLinking'] = "true" | |
| 813 elif arg == '/MD': | |
| 814 attrs['RuntimeLibrary'] = 1 # rtMultiThreadedDebug | |
| 815 elif arg == '/MDd': | |
| 816 attrs['RuntimeLibrary'] = 2 # rtMultiThreadedDebugDLL | |
| 817 elif arg == '/MT': | |
| 818 attrs['RuntimeLibrary'] = 0 # rtMultiThreaded | |
| 819 elif arg == '/MTd': | |
| 820 attrs['RuntimeLibrary'] = 3 # rtMultiThreadedDLL | |
| 821 elif arg == '/nologo': | |
| 822 attrs['SuppressStartupBanner'] = "true" | |
| 823 elif arg == '/O1': | |
| 824 attrs['InlineFunctionExpansion'] = 4 # optimizeMinSpace | |
| 825 elif arg == '/O2': | |
| 826 attrs['InlineFunctionExpansion'] = 3 # optimizeMaxSpeed | |
| 827 elif arg == '/Ob1': | |
| 828 attrs['InlineFunctionExpansion'] = 2 # expandOnlyInline | |
| 829 elif arg == '/Ob2': | |
| 830 attrs['InlineFunctionExpansion'] = 0 # expandAnySuitable | |
| 831 elif arg == '/Od': | |
| 832 attrs['Optimization'] = 0 | |
| 833 elif arg == '/Oi': | |
| 834 attrs['EnableIntrinsicFunctions'] = "true" | |
| 835 elif arg == '/Os': | |
| 836 attrs['FavorSizeOrSpeed'] = 1 # favorSize | |
| 837 elif arg == '/Ot': | |
| 838 attrs['FavorSizeOrSpeed'] = 2 # favorSpeed | |
| 839 elif arg == '/Ox': | |
| 840 attrs['Optimization'] = 2 # optimizeFull | |
| 841 elif arg == '/Oy': | |
| 842 attrs['OmitFramePointers'] = "true" | |
| 843 elif arg == '/Oy-': | |
| 844 attrs['TODO'] = "true" | |
| 845 elif arg in ('/Tc', '/TC'): | |
| 846 attrs['CompileAs'] = 1 # compileAsC | |
| 847 elif arg in ('/Tp', '/TP'): | |
| 848 attrs['CompileAs'] = 2 # compileAsCPlusPlus | |
| 849 elif arg == '/WX': | |
| 850 attrs['WarnAsError'] = "true" | |
| 851 elif arg.startswith('/W'): | |
| 852 attrs['WarningLevel'] = int(arg[2:]) # 0 through 4 | |
| 853 elif arg.startswith('/wd'): | |
| 854 attrs['DisableSpecificWarnings'].append(str(arg[3:])) | |
| 855 elif arg == '/Z7': | |
| 856 attrs['DebugInformationFormat'] = 3 # debugOldSytleInfo TODO(???) | |
| 857 elif arg == '/Zd': | |
| 858 attrs['DebugInformationFormat'] = 0 # debugDisabled | |
| 859 elif arg == '/Zi': | |
| 860 attrs['DebugInformationFormat'] = 2 # debugEnabled TODO(???) | |
| 861 elif arg == '/ZI': | |
| 862 attrs['DebugInformationFormat'] = 1 # debugEditAndContinue TODO(???) | |
| 863 | |
| 864 cppdefines = attrs['PreprocessorDefinitions'] | |
| 865 if cppdefines: | |
| 866 attrs['PreprocessorDefinitions'] = ';'.join(cppdefines) | |
| 867 warnings = attrs['DisableSpecificWarnings'] | |
| 868 if warnings: | |
| 869 warnings = SCons.Util.uniquer(warnings) | |
| 870 attrs['DisableSpecificWarnings'] = ';'.join(warnings) | |
| 871 | |
| 872 return tool | |
| 873 | |
| 874 def VCLibrarianTool(self, args): | |
| 875 default_attrs = { | |
| 876 'LinkTimeCodeGeneration' : "false", | |
| 877 'SuppressStartupBanner' : "false", | |
| 878 } | |
| 879 | |
| 880 tool = MSVSTool('VCLibrarianTool', **default_attrs) | |
| 881 attrs = tool.attrs | |
| 882 | |
| 883 for arg in args: | |
| 884 if arg.startswith('/OUT'): | |
| 885 continue | |
| 886 if arg == '/ltcg': | |
| 887 attrs['LinkTimeCodeGeneration'] = "true" | |
| 888 elif arg == '/nologo': | |
| 889 attrs['SuppressStartupBanner'] = "true" | |
| 890 | |
| 891 return tool | |
| 892 | |
| 893 def VCLinkerTool(self, args): | |
| 894 default_attrs = { | |
| 895 'LinkIncremental' : "false", | |
| 896 'LinkTimeCodeGeneration' : "false", | |
| 897 'EnableCOMDATFolding' : TODO, | |
| 898 'OptimizeForWindows98' : TODO, | |
| 899 'OptimizeReferences' : TODO, | |
| 900 'Profile' : "false", | |
| 901 'SuppressStartupBanner' : "false", | |
| 902 } | |
| 903 | |
| 904 tool = MSVSTool('VCLinkerTool', **default_attrs) | |
| 905 attrs = tool.attrs | |
| 906 | |
| 907 for arg in args: | |
| 908 if arg == '': | |
| 909 continue | |
| 910 if arg == '/INCREMENTAL': | |
| 911 attrs['LinkIncremental'] = "true" | |
| 912 elif arg == '/INCREMENTAL:NO': | |
| 913 attrs['LinkIncremental'] = "false" | |
| 914 elif arg == '/LTCG': | |
| 915 attrs['LinkTimeCodeGeneration'] = "true" | |
| 916 elif arg == '/nologo': | |
| 917 attrs['SuppressStartupBanner'] = "true" | |
| 918 elif arg == '/OPT:NOICF': | |
| 919 attrs['EnableCOMDATFolding'] = 2 # | |
| 920 elif arg == '/OPT:NOWIN98': | |
| 921 attrs['OptimizeForWindows98'] = 1 # | |
| 922 elif arg == '/OPT:REF': | |
| 923 attrs['OptimizeReferences'] = 2 # | |
| 924 elif arg == '/PROFILE': | |
| 925 attrs['Profile'] = "true" | |
| 926 | |
| 927 return tool | |
| 928 | |
| 929 command_to_tool_map = { | |
| 930 'cl' : 'VCCLCompilerTool', | |
| 931 'cl.exe' : 'VCCLCompilerTool', | |
| 932 'lib' : 'VCLibrarianTool', | |
| 933 'lib.exe' : 'VCLibrarianTool', | |
| 934 'link' : 'VCLinkerTool', | |
| 935 'link.exe' : 'VCLinkerTool', | |
| 936 } | |
| 937 | |
| 938 def cl_to_tool(self, args): | |
| 939 command = os.path.basename(args[0]) | |
| 940 method_name = self.command_to_tool_map.get(command) | |
| 941 if not method_name: | |
| 942 return None | |
| 943 return getattr(self, method_name)(args[1:]) | |
| 944 | |
| 945 def _AddFileConfigurationDifferences(self, target, source, base_env, file_env,
name): | |
| 946 """Adds a per-file configuration. | 688 """Adds a per-file configuration. |
| 947 | 689 |
| 948 Args: | 690 Args: |
| 949 target: The target being built from the source. | 691 target: The target being built from the source. |
| 950 source: The source to which the file configuration is being added. | 692 source: The source to which the file configuration is being added. |
| 951 base_env: The base construction environment for the project. | 693 base_env: The base construction environment for the project. |
| 952 Differences from this will go into the FileConfiguration | 694 Differences from this will go into the FileConfiguration |
| 953 in the project file. | 695 in the project file. |
| 954 file_env: The construction environment for the target, containing | 696 file_env: The construction environment for the target, containing |
| 955 the per-target settings. | 697 the per-target settings. |
| 956 """ | 698 """ |
| 957 executor = target.get_executor() | 699 pass |
| 958 base_cl = map(str, base_env.subst_list(executor)[0]) | |
| 959 file_cl = map(str, file_env.subst_list(executor)[0]) | |
| 960 if base_cl == file_cl: | |
| 961 return | |
| 962 | |
| 963 base_tool = self.cl_to_tool(base_cl) | |
| 964 file_tool = self.cl_to_tool(file_cl) | |
| 965 | |
| 966 file_tool.diff(base_tool) | |
| 967 | |
| 968 self.AddFileConfig(source, name, tools=[file_tool]) | |
| 969 | 700 |
| 970 def _AddFileConfigurations(self, env): | 701 def _AddFileConfigurations(self, env): |
| 971 """Adds per-file configurations for the buildtarget's sources. | 702 """Adds per-file configurations for the buildtarget's sources. |
| 972 | 703 |
| 973 Args: | 704 Args: |
| 974 env: The base construction environment for the project. | 705 env: The base construction environment for the project. |
| 975 """ | 706 """ |
| 976 if not self.buildtargets: | 707 if not self.buildtargets: |
| 977 return | 708 return |
| 978 | 709 |
| 979 for bt in self.buildtargets: | 710 bt = self.buildtargets[0] |
| 980 executor = bt.get_executor() | 711 additional_files = [] |
| 981 build_env = bt.get_build_env() | 712 for t in bt.sources: |
| 982 bt_cl = map(str, build_env.subst_list(executor)[0]) | |
| 983 tool = self.cl_to_tool(bt_cl) | |
| 984 default_tool = self.cl_to_tool([bt_cl[0]]) | |
| 985 if default_tool: | |
| 986 tool.diff(default_tool) | |
| 987 else: | |
| 988 print "no tool for %r" % bt_cl[0] | |
| 989 for t in bt.sources: | |
| 990 e = t.get_build_env() | 713 e = t.get_build_env() |
| 991 additional_files = SCons.Util.UniqueList() | |
| 992 for s in t.sources: | 714 for s in t.sources: |
| 993 s = env.arg2nodes([s])[0].srcnode() | 715 s = env.arg2nodes([s])[0] |
| 994 if not self.FindFile(s): | 716 if not self.FindFile(s): |
| 995 additional_files.append(s) | 717 additional_files.append(s) |
| 996 if not build_env is e: | 718 if not env is e: |
| 997 # TODO(sgk): This test may be bogus, but it works for now. | 719 self._AddFileConfigurationDifferences(t, s, env, e) |
| 998 # We're trying to figure out if the file configuration | 720 self.AddFiles(additional_files) |
| 999 # differences need to be added one per build target, or one | |
| 1000 # per configuration for the entire project. The assumption | |
| 1001 # is that if the number of buildtargets configured matches | |
| 1002 # the number of project configurations, that we use those | |
| 1003 # in preference to the project configurations. | |
| 1004 if len(self.buildtargets) == len(self.configurations): | |
| 1005 self._AddFileConfigurationDifferences(t, s, build_env, e, e.subst(
'$MSVSCONFIGURATIONNAME')) | |
| 1006 else: | |
| 1007 for config in self.configurations: | |
| 1008 self._AddFileConfigurationDifferences(t, s, build_env, e, config
.Name) | |
| 1009 self._MergeFiles(self.files, additional_files) | |
| 1010 | 721 |
| 1011 def Write(self, env): | 722 def Write(self, env): |
| 1012 """Writes the project file.""" | 723 """Writes the project file.""" |
| 1013 for flist in self.file_lists: | |
| 1014 self._FilesToSourceFiles(flist) | |
| 1015 self._MergeFiles(self.files, flist) | |
| 1016 for k, v in self.file_configurations.items(): | |
| 1017 self.file_configurations[str(k)] = v | |
| 1018 k = self.env.File(k).srcnode() | |
| 1019 self.file_configurations[k] = v | |
| 1020 self.file_configurations[str(k)] = v | |
| 1021 self._AddFileConfigurations(env) | 724 self._AddFileConfigurations(env) |
| 1022 | 725 |
| 1023 self.Create() | 726 self.Create() |
| 1024 | 727 |
| 1025 f = open(str(self), 'wt') | 728 f = open(str(self.msvs_node), 'wt') |
| 1026 f.write(self.formatMSVSProjectXML(self.doc)) | 729 f.write(self.formatMSVSProjectXML(self.doc)) |
| 1027 f.close() | 730 f.close() |
| 1028 | 731 |
| 1029 # Methods for formatting XML as nearly identically to Microsoft's | 732 # Methods for formatting XML as nearly identically to Microsoft's |
| 1030 # .vcproj output as we can practically make it. | 733 # .vcproj output as we can practically make it. |
| 1031 # | 734 # |
| 1032 # The general design here is copied from: | 735 # The general design here is copied from: |
| 1033 # | 736 # |
| 1034 # Bruce Eckels' MindView, Inc: 12-09-04 XML Oddyssey | 737 # Bruce Eckels' MindView, Inc: 12-09-04 XML Oddyssey |
| 1035 # http://www.mindview.net/WebLog/log-0068 | 738 # http://www.mindview.net/WebLog/log-0068 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 'ConfigurationType', | 782 'ConfigurationType', |
| 1080 'InheritedPropertySheets', | 783 'InheritedPropertySheets', |
| 1081 ], | 784 ], |
| 1082 'FileConfiguration' : [ | 785 'FileConfiguration' : [ |
| 1083 'Name', | 786 'Name', |
| 1084 'ExcludedFromBuild', | 787 'ExcludedFromBuild', |
| 1085 ], | 788 ], |
| 1086 'Tool' : [ | 789 'Tool' : [ |
| 1087 'Name', | 790 'Name', |
| 1088 'DisableSpecificWarnings', | 791 'DisableSpecificWarnings', |
| 1089 | |
| 1090 'PreprocessorDefinitions', | |
| 1091 'UsePrecompiledHeader', | |
| 1092 'PrecompiledHeaderThrough', | |
| 1093 'ForcedIncludeFiles', | |
| 1094 ], | 792 ], |
| 1095 'VisualStudioProject' : [ | 793 'VisualStudioProject' : [ |
| 1096 'ProjectType', | 794 'ProjectType', |
| 1097 'Version', | 795 'Version', |
| 1098 'Name', | 796 'Name', |
| 1099 'ProjectGUID', | 797 'ProjectGUID', |
| 1100 'RootNamespace', | 798 'RootNamespace', |
| 1101 'Keyword', | 799 'Keyword', |
| 1102 ], | 800 ], |
| 1103 } | 801 } |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1357 if not SCons.Util.is_String(item): | 1055 if not SCons.Util.is_String(item): |
| 1358 return item | 1056 return item |
| 1359 item = env.subst(item) | 1057 item = env.subst(item) |
| 1360 result = env.fs._lookup(item, None, _MSVSSolution, create=1) | 1058 result = env.fs._lookup(item, None, _MSVSSolution, create=1) |
| 1361 result.initialize(env, item, *args, **kw) | 1059 result.initialize(env, item, *args, **kw) |
| 1362 LookupAdd(item, result) | 1060 LookupAdd(item, result) |
| 1363 return result | 1061 return result |
| 1364 | 1062 |
| 1365 import __builtin__ | 1063 import __builtin__ |
| 1366 | 1064 |
| 1367 __builtin__.MSVSConfig = MSVSConfig | |
| 1368 __builtin__.MSVSFilter = MSVSFilter | 1065 __builtin__.MSVSFilter = MSVSFilter |
| 1369 __builtin__.MSVSProject = MSVSProject | 1066 __builtin__.MSVSProject = MSVSProject |
| 1370 __builtin__.MSVSSolution = MSVSSolution | 1067 __builtin__.MSVSSolution = MSVSSolution |
| 1371 __builtin__.MSVSTool = MSVSTool | 1068 __builtin__.MSVSTool = MSVSTool |
| OLD | NEW |