| OLD | NEW |
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright 2008, Google Inc. | 2 # Copyright 2008, Google Inc. |
| 3 # All rights reserved. | 3 # All rights reserved. |
| 4 # | 4 # |
| 5 # Redistribution and use in source and binary forms, with or without | 5 # Redistribution and use in source and binary forms, with or without |
| 6 # modification, are permitted provided that the following conditions are | 6 # modification, are permitted provided that the following conditions are |
| 7 # met: | 7 # met: |
| 8 # | 8 # |
| 9 # * Redistributions of source code must retain the above copyright | 9 # * Redistributions of source code must retain the above copyright |
| 10 # notice, this list of conditions and the following disclaimer. | 10 # notice, this list of conditions and the following disclaimer. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | 30 |
| 31 """Visual Studio solution output of component targets for SCons.""" | 31 """Visual Studio solution output of component targets for SCons.""" |
| 32 | 32 |
| 33 import copy |
| 33 import md5 | 34 import md5 |
| 35 import os |
| 34 import sys | 36 import sys |
| 35 import xml.dom | 37 import xml.dom |
| 36 import xml.dom.minidom | 38 import xml.dom.minidom |
| 37 import SCons | 39 import SCons |
| 38 | 40 |
| 39 | 41 |
| 40 #------------------------------------------------------------------------------ | 42 #------------------------------------------------------------------------------ |
| 41 | 43 |
| 42 | 44 |
| 43 def MakeGuid(name, seed='component_targets_msvs'): | 45 def MakeGuid(name, seed='component_targets_msvs'): |
| (...skipping 14 matching lines...) Expand all Loading... |
| 58 # Calculate a MD5 signature for the seed and name. | 60 # Calculate a MD5 signature for the seed and name. |
| 59 d = md5.new(str(seed) + str(name)).hexdigest().upper() | 61 d = md5.new(str(seed) + str(name)).hexdigest().upper() |
| 60 # Convert most of the signature to GUID form (discard the rest) | 62 # Convert most of the signature to GUID form (discard the rest) |
| 61 guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20] | 63 guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20] |
| 62 + '-' + d[20:32] + '}') | 64 + '-' + d[20:32] + '}') |
| 63 return guid | 65 return guid |
| 64 | 66 |
| 65 #------------------------------------------------------------------------------ | 67 #------------------------------------------------------------------------------ |
| 66 | 68 |
| 67 | 69 |
| 68 def GetGuidFromVSProject(project_path): | 70 def GetGuidAndNameFromVSProject(project_path): |
| 69 """Reads the GUID from a Visual Studio project file. | 71 """Reads the GUID from a Visual Studio project file. |
| 70 | 72 |
| 71 Args: | 73 Args: |
| 72 project_path: Path to the Visual Studio project file. | 74 project_path: Path to the Visual Studio project file. |
| 73 | 75 |
| 74 Returns: | 76 Returns: |
| 75 The GUID string from the file. | 77 The GUID string from the file. |
| 78 The project name from the file. |
| 76 """ | 79 """ |
| 77 doc = xml.dom.minidom.parse(project_path) | 80 doc = xml.dom.minidom.parse(project_path) |
| 78 try: | 81 try: |
| 79 n_root = doc.documentElement | 82 n_root = doc.documentElement |
| 80 if n_root.nodeName != 'VisualStudioProject': | 83 if n_root.nodeName != 'VisualStudioProject': |
| 81 raise SCons.Errors.UserError('%s is not a Visual Studio project.' % | 84 raise SCons.Errors.UserError('%s is not a Visual Studio project.' % |
| 82 project_path) | 85 project_path) |
| 83 return str(n_root.attributes['ProjectGUID'].nodeValue) | 86 return ( |
| 87 str(n_root.attributes['ProjectGUID'].nodeValue), |
| 88 str(n_root.attributes['Name'].nodeValue), |
| 89 ) |
| 84 finally: | 90 finally: |
| 85 # Clean up doc | 91 # Clean up doc |
| 86 doc.unlink() | 92 doc.unlink() |
| 87 | 93 |
| 88 #------------------------------------------------------------------------------ | 94 #------------------------------------------------------------------------------ |
| 89 | 95 |
| 90 | 96 |
| 97 class VSProjectWriter(object): |
| 98 """Visual Studio XML project writer.""" |
| 99 |
| 100 def __init__(self, project_path): |
| 101 """Initializes the project. |
| 102 |
| 103 Args: |
| 104 project_path: Path to the project file. |
| 105 """ |
| 106 self.project_path = project_path |
| 107 self.doc = None |
| 108 |
| 109 def Create(self, name): |
| 110 """Creates the project document. |
| 111 |
| 112 Args: |
| 113 name: Name of the project. |
| 114 """ |
| 115 self.name = name |
| 116 self.guid = MakeGuid(name) |
| 117 |
| 118 # Create XML doc |
| 119 xml_impl = xml.dom.getDOMImplementation() |
| 120 self.doc = xml_impl.createDocument(None, 'VisualStudioProject', None) |
| 121 |
| 122 # Add attributes to root element |
| 123 self.n_root = self.doc.documentElement |
| 124 self.n_root.setAttribute('ProjectType', 'Visual C++') |
| 125 self.n_root.setAttribute('Version', '8.00') |
| 126 self.n_root.setAttribute('Name', self.name) |
| 127 self.n_root.setAttribute('ProjectGUID', self.guid) |
| 128 self.n_root.setAttribute('RootNamespace', self.name) |
| 129 self.n_root.setAttribute('Keyword', 'MakeFileProj') |
| 130 |
| 131 # Add platform list |
| 132 n_platform = self.doc.createElement('Platforms') |
| 133 self.n_root.appendChild(n_platform) |
| 134 n = self.doc.createElement('Platform') |
| 135 n.setAttribute('Name', 'Win32') |
| 136 n_platform.appendChild(n) |
| 137 |
| 138 # Add empty ToolFiles section |
| 139 self.n_root.appendChild(self.doc.createElement('ToolFiles')) |
| 140 |
| 141 # Add configurations section |
| 142 self.n_configs = self.doc.createElement('Configurations') |
| 143 self.n_root.appendChild(self.n_configs) |
| 144 |
| 145 # Add files section |
| 146 self.n_files = self.doc.createElement('Files') |
| 147 self.n_root.appendChild(self.n_files) |
| 148 |
| 149 # Add empty Globals section |
| 150 self.n_root.appendChild(self.doc.createElement('Globals')) |
| 151 |
| 152 def AddConfig(self, name, attrs, tool_attrs): |
| 153 """Adds a configuration to the project. |
| 154 |
| 155 Args: |
| 156 name: Configuration name. |
| 157 attrs: Dict of configuration attributes. |
| 158 tool_attrs: Dict of tool attributes. |
| 159 """ |
| 160 # Add configuration node |
| 161 n_config = self.doc.createElement('Configuration') |
| 162 n_config.setAttribute('Name', '%s|Win32' % name) |
| 163 n_config.setAttribute('ConfigurationType', '0') |
| 164 for k, v in attrs.items(): |
| 165 n_config.setAttribute(k, v) |
| 166 self.n_configs.appendChild(n_config) |
| 167 |
| 168 # Add tool node |
| 169 n_tool = self.doc.createElement('Tool') |
| 170 n_tool.setAttribute('Name', 'VCNMakeTool') |
| 171 n_tool.setAttribute('IncludeSearchPath', '') |
| 172 n_tool.setAttribute('ForcedIncludes', '') |
| 173 n_tool.setAttribute('AssemblySearchPath', '') |
| 174 n_tool.setAttribute('ForcedUsingAssemblies', '') |
| 175 n_tool.setAttribute('CompileAsManaged', '') |
| 176 n_tool.setAttribute('PreprocessorDefinitions', '') |
| 177 for k, v in tool_attrs.items(): |
| 178 n_tool.setAttribute(k, v) |
| 179 n_config.appendChild(n_tool) |
| 180 |
| 181 def _WalkFolders(self, folder_dict, parent): |
| 182 """Recursively walks the folder tree. |
| 183 |
| 184 Args: |
| 185 folder_dict: Dict of folder entries. Entry is |
| 186 either subdir_name:subdir_dict or relative_path_to_file:None. |
| 187 parent: Parent node (folder node for that dict) |
| 188 """ |
| 189 entries = folder_dict.keys() |
| 190 entries.sort() |
| 191 for e in entries: |
| 192 if folder_dict[e]: |
| 193 # Folder |
| 194 n_subfolder = self.doc.createElement('Filter') |
| 195 n_subfolder.setAttribute('Name', e) |
| 196 parent.appendChild(n_subfolder) |
| 197 self._WalkFolders(folder_dict[e], n_subfolder) |
| 198 else: |
| 199 # File |
| 200 n_file = self.doc.createElement('File') |
| 201 n_file.setAttribute('RelativePath', e) |
| 202 parent.appendChild(n_file) |
| 203 |
| 204 def AddFiles(self, name, files_dict): |
| 205 """Adds files to the project. |
| 206 |
| 207 Args: |
| 208 name: Name of the folder. If None, files/folders will be added directly |
| 209 to the files list. |
| 210 files_dict: A dict of files / folders. |
| 211 |
| 212 Within the files_dict: |
| 213 * A file entry is relative_path:None |
| 214 * A folder entry is folder_name:files_dict, where files_dict is another |
| 215 dict of this form. |
| 216 """ |
| 217 # Create subfolder if necessary |
| 218 if name: |
| 219 n_folder = self.doc.createElement('Filter') |
| 220 n_folder.setAttribute('Name', name) |
| 221 self.n_files.appendChild(n_folder) |
| 222 else: |
| 223 n_folder = self.n_files |
| 224 |
| 225 # Recursively add files to the folder |
| 226 self._WalkFolders(files_dict, n_folder) |
| 227 |
| 228 def Write(self): |
| 229 """Writes the project file.""" |
| 230 f = open(self.project_path, 'wt') |
| 231 self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\n') |
| 232 f.close() |
| 233 |
| 234 #------------------------------------------------------------------------------ |
| 235 |
| 236 |
| 91 def ComponentVSProjectBuilder(target, source, env): | 237 def ComponentVSProjectBuilder(target, source, env): |
| 92 """Visual Studio project builder. | 238 """Visual Studio project builder. |
| 93 | 239 |
| 94 Args: | 240 Args: |
| 95 target: Destination file. | 241 target: Destination file. |
| 96 source: List of sources to be added to the target. | 242 source: List of sources to be added to the target. |
| 97 env: Environment context. | 243 env: Environment context. |
| 98 | 244 |
| 99 Returns: | 245 Returns: |
| 100 Zero if successful. | 246 Zero if successful. |
| 101 """ | 247 """ |
| 102 source = source # Silence gpylint | 248 source = source # Silence gpylint |
| 103 | 249 |
| 104 target_name = env['TARGET_NAME'] | 250 target_name = env['TARGET_NAME'] |
| 105 project_file = target[0].path | 251 project_file = target[0].path |
| 106 project_to_main = env.RelativePath(target[0].dir, env.Dir('$MAIN_DIR'), | 252 project_to_main = env.RelativePath(target[0].dir, env.Dir('$MAIN_DIR'), |
| 107 sep='/') | 253 sep='/') |
| 108 | 254 |
| 109 env_hammer_bat = env.Clone(VS_PROJECT_TO_MAIN_DIR=project_to_main) | 255 env_hammer_bat = env.Clone(VS_PROJECT_TO_MAIN_DIR=project_to_main) |
| 110 hammer_bat = env_hammer_bat.subst('$COMPONENT_VS_PROJECT_SCRIPT_PATH', raw=1) | 256 hammer_bat = env_hammer_bat.subst('$COMPONENT_VS_PROJECT_SCRIPT_PATH', raw=1) |
| 111 | 257 |
| 112 # Project header | 258 vsp = VSProjectWriter(project_file) |
| 113 xml_impl = xml.dom.getDOMImplementation() | 259 vsp.Create(target_name) |
| 114 doc = xml_impl.createDocument(None, 'VisualStudioProject', None) | |
| 115 | 260 |
| 116 n_root = doc.documentElement | 261 # Add configuration per build mode supported by this target |
| 117 n_root.setAttribute('ProjectType', 'Visual C++') | |
| 118 n_root.setAttribute('Version', '8.00') | |
| 119 n_root.setAttribute('Name', target_name) | |
| 120 n_root.setAttribute('ProjectGUID', MakeGuid(target_name)) | |
| 121 n_root.setAttribute('RootNamespace', target_name) | |
| 122 n_root.setAttribute('Keyword', 'MakeFileProj') | |
| 123 | |
| 124 n_platform = doc.createElement('Platforms') | |
| 125 n_root.appendChild(n_platform) | |
| 126 n = doc.createElement('Platform') | |
| 127 n.setAttribute('Name', 'Win32') | |
| 128 n_platform.appendChild(n) | |
| 129 | |
| 130 n_root.appendChild(doc.createElement('ToolFiles')) | |
| 131 | |
| 132 # One configuration per build mode supported by this target | |
| 133 n_configs = doc.createElement('Configurations') | |
| 134 n_root.appendChild(n_configs) | |
| 135 | |
| 136 target_path = env['TARGET_PATH'] | 262 target_path = env['TARGET_PATH'] |
| 137 for mode, path in target_path.items(): | 263 for mode, path in target_path.items(): |
| 138 n_config = doc.createElement('Configuration') | 264 attrs = {} |
| 139 n_config.setAttribute('Name', '%s|Win32' % mode) | 265 attrs['OutputDirectory'] = '$(ProjectDir)/%s/%s/out' % (mode, target_name) |
| 140 n_config.setAttribute('OutputDirectory', | 266 attrs['IntermediateDirectory'] = ('$(ProjectDir)/%s/%s/tmp' % |
| 141 '$(ProjectDir)/%s/%s/out' % (mode, target_name)) | 267 (mode, target_name)) |
| 142 n_config.setAttribute('IntermediateDirectory', | |
| 143 '$(ProjectDir)/%s/%s/tmp' % (mode, target_name)) | |
| 144 n_config.setAttribute('ConfigurationType', '0') | |
| 145 n_configs.appendChild(n_config) | |
| 146 | 268 |
| 147 n_tool = doc.createElement('Tool') | 269 tool_attrs = {} |
| 148 n_tool.setAttribute('Name', 'VCNMakeTool') | |
| 149 n_tool.setAttribute('IncludeSearchPath', '') | |
| 150 n_tool.setAttribute('ForcedIncludes', '') | |
| 151 n_tool.setAttribute('AssemblySearchPath', '') | |
| 152 n_tool.setAttribute('ForcedUsingAssemblies', '') | |
| 153 n_tool.setAttribute('CompileAsManaged', '') | |
| 154 n_tool.setAttribute('PreprocessorDefinitions', '') | |
| 155 if path: | 270 if path: |
| 156 n_tool.setAttribute( | 271 tool_attrs['Output'] = env.RelativePath(target[0].dir, |
| 157 'Output', env.RelativePath(target[0].dir, env.Entry(path), sep='/')) | 272 env.Entry(path), sep='/') |
| 158 build_cmd = '%s --mode=%s %s' % (hammer_bat, mode, target_name) | 273 build_cmd = '%s --mode=%s %s' % (hammer_bat, mode, target_name) |
| 159 clean_cmd = '%s --mode=%s -c %s' % (hammer_bat, mode, target_name) | 274 clean_cmd = '%s --mode=%s -c %s' % (hammer_bat, mode, target_name) |
| 160 n_tool.setAttribute('BuildCommandLine', build_cmd) | 275 tool_attrs['BuildCommandLine'] = build_cmd |
| 161 n_tool.setAttribute('CleanCommandLine', clean_cmd) | 276 tool_attrs['CleanCommandLine'] = clean_cmd |
| 162 n_tool.setAttribute('ReBuildCommandLine', clean_cmd + ' && ' + build_cmd) | 277 tool_attrs['ReBuildCommandLine'] = clean_cmd + ' && ' + build_cmd |
| 163 n_config.appendChild(n_tool) | |
| 164 | 278 |
| 165 n_files = doc.createElement('Files') | 279 vsp.AddConfig(mode, attrs, tool_attrs) |
| 166 n_root.appendChild(n_files) | 280 |
| 167 # TODO(rspangler): Fill in files - at least, the .scons file invoking the | 281 # TODO(rspangler): Fill in files - at least, the .scons file invoking the |
| 168 # target. | 282 # target. |
| 169 | 283 |
| 170 n_root.appendChild(doc.createElement('Globals')) | 284 # Write project |
| 171 | 285 vsp.Write() |
| 172 f = open(project_file, 'wt') | |
| 173 doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\n') | |
| 174 f.close() | |
| 175 | |
| 176 return 0 | 286 return 0 |
| 177 | 287 |
| 178 | 288 |
| 179 def ComponentVSProject(self, target_name, **kwargs): | 289 def ComponentVSProject(self, target_name, **kwargs): |
| 180 """Visual Studio project pseudo-builder for the specified target. | 290 """Visual Studio project pseudo-builder for the specified target. |
| 181 | 291 |
| 182 Args: | 292 Args: |
| 183 self: Environment context. | 293 self: Environment context. |
| 184 target_name: Name of the target. | 294 target_name: Name of the target. |
| 185 kwargs: Optional keyword arguments override environment variables in the | 295 kwargs: Optional keyword arguments override environment variables in the |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 for mode in GetTargetModes(): | 328 for mode in GetTargetModes(): |
| 219 env.Append(TARGET_PATH={mode: None}) | 329 env.Append(TARGET_PATH={mode: None}) |
| 220 | 330 |
| 221 # Call the real builder | 331 # Call the real builder |
| 222 return env.ComponentVSProjectBuilder( | 332 return env.ComponentVSProjectBuilder( |
| 223 '$COMPONENT_VS_PROJECT_DIR/${TARGET_NAME}', []) | 333 '$COMPONENT_VS_PROJECT_DIR/${TARGET_NAME}', []) |
| 224 | 334 |
| 225 #------------------------------------------------------------------------------ | 335 #------------------------------------------------------------------------------ |
| 226 | 336 |
| 227 | 337 |
| 338 class SourceWalker(object): |
| 339 """Iterator for walking a node tree and collecting sources. |
| 340 |
| 341 This is depth-first, children are visited before the parent. The object |
| 342 can be initialized with any node, and returns the next node on the descent |
| 343 with each Next() call. |
| 344 |
| 345 This class does not get caught in node cycles caused, for example, by C |
| 346 header file include loops. |
| 347 |
| 348 Based on SCons.Node.Walker. |
| 349 """ |
| 350 |
| 351 def __init__(self, node, seen, print_interval = 1000): |
| 352 """Initializes the source walker. |
| 353 |
| 354 Args: |
| 355 node: Node to start walk from. |
| 356 seen: Set to add seen nodes to, if not None. |
| 357 print_interval: Interval in nodes examined at which to print a progress |
| 358 indicator. |
| 359 """ |
| 360 self.interval = print_interval |
| 361 # Put node on stack |
| 362 self.stack = [node] |
| 363 # Scan for node's children, then copy them to node.wkids |
| 364 node.wkids = copy.copy(node.children(scan=1)) |
| 365 # Keep track of nodes we've seen (returned) |
| 366 if seen is None: |
| 367 seen = set() |
| 368 self.seen = seen |
| 369 # Add node to history for cycle detection |
| 370 self.history = set() |
| 371 self.history.add(node) |
| 372 # We've seen one node now |
| 373 self.nodes_examined = 1 |
| 374 self.unique_nodes = 1 |
| 375 |
| 376 |
| 377 def Next(self): |
| 378 """Get the next node for this walk of the tree. |
| 379 |
| 380 Returns: |
| 381 The next node, or None if no more nodes. |
| 382 |
| 383 This function is intentionally iterative, not recursive, to sidestep any |
| 384 issues of stack size limitations. |
| 385 """ |
| 386 while self.stack: |
| 387 if self.stack[-1].wkids: |
| 388 # Node has children we haven't examined, so iterate into the first |
| 389 # child |
| 390 node = self.stack[-1].wkids.pop(0) |
| 391 if not self.stack[-1].wkids: |
| 392 # No more children of this node |
| 393 self.stack[-1].wkids = None |
| 394 self.nodes_examined += 1 |
| 395 if self.interval and not self.nodes_examined % self.interval: |
| 396 self.PrintProgress() |
| 397 if (node not in self.history) and (node not in self.seen): |
| 398 # Haven't hit a cycle or a node we've already seen |
| 399 node.wkids = copy.copy(node.children(scan=1)) |
| 400 self.stack.append(node) |
| 401 self.history.add(node) |
| 402 else: |
| 403 # Coming back from iterating, so return the next node on the stack. |
| 404 node = self.stack.pop() |
| 405 self.history.remove(node) |
| 406 self.seen.add(node) |
| 407 self.unique_nodes += 1 |
| 408 return node |
| 409 return None |
| 410 |
| 411 def PrintProgress(self): |
| 412 """Prints a progress indicator.""" |
| 413 print ' Examined %d nodes, found %d unique...' % ( |
| 414 self.nodes_examined, self.unique_nodes) |
| 415 |
| 416 def WalkAll(self): |
| 417 """Walks all nodes in the the tree.""" |
| 418 while self.Next(): |
| 419 pass |
| 420 if self.interval: |
| 421 self.PrintProgress() |
| 422 |
| 423 |
| 424 def ComponentVSSourceProjectBuilder(target, source, env): |
| 425 """Visual Studio source project builder. |
| 426 |
| 427 Args: |
| 428 target: Destination file. |
| 429 source: List of sources to be added to the target. |
| 430 env: Environment context. |
| 431 |
| 432 Returns: |
| 433 Zero if successful. |
| 434 """ |
| 435 source = source # Silence gpylint |
| 436 |
| 437 target_name = env['PROJECT_NAME'] |
| 438 project_file = target[0].path |
| 439 project_dir = target[0].dir |
| 440 |
| 441 # Get list of suffixes to include |
| 442 suffixes = env.SubstList2('$COMPONENT_VS_SOURCE_SUFFIXES') |
| 443 |
| 444 # Convert source folders to absolute paths |
| 445 folders = [] |
| 446 for f in env['COMPONENT_VS_SOURCE_FOLDERS']: |
| 447 # (folder name, folder abspath, dict of contents) |
| 448 folders.append((f[0], env.Dir(f[1]).abspath, {})) |
| 449 |
| 450 # TODO(rspangler): Additional enhancements: |
| 451 # * Should be able to specify paths in folder name (i.e., foo/bar) and |
| 452 # create the nested folder nodes ('foo' and 'bar') |
| 453 # * Should be tolerant of a folder being specified more than once with |
| 454 # the same name (probably necessary to support nested folder nodes anyway) |
| 455 # Can probably accomplish both of those by creating a parent fodler dict and |
| 456 # calling WalkFolders() only once. |
| 457 # Create a temporary solution alias to point to all the targets, so we can |
| 458 # make a single call to SourceWalker() |
| 459 tmp_alias = env.Alias('vs_source_project_' + target_name, |
| 460 map(env.Alias, env['COMPONENT_VS_SOURCE_TARGETS'])) |
| 461 |
| 462 # Scan all targets and add unique nodes to set of sources |
| 463 print ' Scanning dependency tree ...' |
| 464 all_srcs = set() |
| 465 walker = SourceWalker(tmp_alias[0], all_srcs) |
| 466 walker.WalkAll() |
| 467 |
| 468 # Walk all sources and build directory trees |
| 469 print ' Building source tree...' |
| 470 for n in all_srcs: |
| 471 if not hasattr(n, 'isfile') or not n.isfile(): |
| 472 continue # Not a file |
| 473 if n.has_builder(): |
| 474 continue # Not a leaf node |
| 475 if n.suffix not in suffixes: |
| 476 continue # Not a file type we include |
| 477 |
| 478 path = n.rfile().abspath |
| 479 for f in folders: |
| 480 if path.startswith(f[1]): |
| 481 if f[0] is None: |
| 482 # Folder name of None is a filter |
| 483 break |
| 484 relpath = path[len(f[1]) + 1:].split(os.sep) |
| 485 folder_dict = f[2] |
| 486 # Recursively add subdirs |
| 487 for pathseg in relpath[:-1]: |
| 488 if pathseg not in folder_dict: |
| 489 folder_dict[pathseg] = {} |
| 490 folder_dict = folder_dict[pathseg] |
| 491 # Add file to last subdir. No dict, since this isn't a subdir |
| 492 folder_dict[env.RelativePath(project_dir, path)] = None |
| 493 break |
| 494 |
| 495 print ' Writing project file...' |
| 496 |
| 497 vsp = VSProjectWriter(project_file) |
| 498 vsp.Create(target_name) |
| 499 |
| 500 # One configuration for all build modes |
| 501 vsp.AddConfig('all', {}, {}) |
| 502 |
| 503 # Add files |
| 504 for f in folders: |
| 505 if f[0] is None: |
| 506 continue # Skip filters |
| 507 vsp.AddFiles(f[0], f[2]) |
| 508 |
| 509 vsp.Write() |
| 510 return 0 |
| 511 |
| 512 |
| 513 def ComponentVSSourceProject(self, project_name, target_names, **kwargs): |
| 514 """Visual Studio source project pseudo-builder. |
| 515 |
| 516 Args: |
| 517 self: Environment context. |
| 518 project_name: Name of the project. |
| 519 target_names: List of target names to include source for. |
| 520 kwargs: Optional keyword arguments override environment variables in the |
| 521 derived environment used to create the project. |
| 522 |
| 523 Returns: |
| 524 A list of output nodes. |
| 525 """ |
| 526 # Builder only works on Windows |
| 527 if sys.platform not in ('win32', 'cygwin'): |
| 528 return [] |
| 529 |
| 530 # Clone environment and add keyword args |
| 531 env = self.Clone() |
| 532 for k, v in kwargs.items(): |
| 533 env[k] = v |
| 534 |
| 535 # Save the project name and targets |
| 536 env['PROJECT_NAME'] = project_name |
| 537 env['COMPONENT_VS_SOURCE_TARGETS'] = target_names |
| 538 |
| 539 # Call the real builder |
| 540 return env.ComponentVSSourceProjectBuilder( |
| 541 '$COMPONENT_VS_PROJECT_DIR/${PROJECT_NAME}', []) |
| 542 |
| 543 #------------------------------------------------------------------------------ |
| 544 |
| 545 |
| 546 def FindSources(env, dest, source, suffixes=None): |
| 547 """Recursively finds sources and adds them to the destination set. |
| 548 |
| 549 Args: |
| 550 env: Environment context. |
| 551 dest: Set to add source nodes to. |
| 552 source: Source file(s) to find. May be a string, Node, or a list of |
| 553 mixed strings or Nodes. Strings will be passed through env.Glob() to |
| 554 evaluate wildcards. If a source evaluates to a directory, the entire |
| 555 directory will be recursively added. |
| 556 suffixes: List of suffixes to include. If not None, only files with these |
| 557 suffixes will be added to dest. |
| 558 """ |
| 559 for source_entry in env.Flatten(source): |
| 560 if type(source_entry) == str: |
| 561 # Search for matches for each source entry |
| 562 source_nodes = env.Glob(source_entry) |
| 563 else: |
| 564 # Source entry is already a file or directory node; no need to glob it |
| 565 source_nodes = [source_entry] |
| 566 for s in source_nodes: |
| 567 if str(s.__class__) == 'SCons.Node.FS.Dir': |
| 568 # Recursively search subdir. Since glob('*') doesn't match dot files, |
| 569 # also glob('.*'). |
| 570 FindSources(env, dest, [s.abspath + '/*', s.abspath + '/.*'], suffixes) |
| 571 elif suffixes and s.suffix in suffixes: |
| 572 dest.add(s) |
| 573 |
| 574 |
| 575 def ComponentVSDirProjectBuilder(target, source, env): |
| 576 """Visual Studio directory project builder. |
| 577 |
| 578 Args: |
| 579 target: Destination file. |
| 580 source: List of sources to be added to the target. |
| 581 env: Environment context. |
| 582 |
| 583 Returns: |
| 584 Zero if successful. |
| 585 """ |
| 586 source = source # Silence gpylint |
| 587 |
| 588 target_name = env['PROJECT_NAME'] |
| 589 project_file = target[0].path |
| 590 project_dir = target[0].dir |
| 591 |
| 592 # Convert source folders to absolute paths |
| 593 folders = [] |
| 594 for f in env['COMPONENT_VS_SOURCE_FOLDERS']: |
| 595 # (folder name, folder abspath, dict of contents) |
| 596 folders.append((f[0], env.Dir(f[1]).abspath, {})) |
| 597 |
| 598 # Recursively scan source directories |
| 599 print ' Scanning directories for source...' |
| 600 all_srcs = set() |
| 601 FindSources(env, all_srcs, env['PROJECT_SOURCES'], |
| 602 suffixes=env.SubstList2('$COMPONENT_VS_SOURCE_SUFFIXES')) |
| 603 |
| 604 # Walk all sources and build directory trees |
| 605 print ' Building source tree...' |
| 606 for n in all_srcs: |
| 607 # Map addRepository'd source to its real location. |
| 608 path = n.rfile().abspath |
| 609 for f in folders: |
| 610 if path.startswith(f[1]): |
| 611 if f[0] is None: |
| 612 # Folder name of None is a filter |
| 613 break |
| 614 relpath = path[len(f[1]) + 1:].split(os.sep) |
| 615 folder_dict = f[2] |
| 616 # Recursively add subdirs |
| 617 for pathseg in relpath[:-1]: |
| 618 if pathseg not in folder_dict: |
| 619 folder_dict[pathseg] = {} |
| 620 folder_dict = folder_dict[pathseg] |
| 621 # Add file to last subdir. No dict, since this isn't a subdir |
| 622 folder_dict[env.RelativePath(project_dir, path)] = None |
| 623 break |
| 624 |
| 625 print ' Writing project file...' |
| 626 |
| 627 vsp = VSProjectWriter(project_file) |
| 628 vsp.Create(target_name) |
| 629 |
| 630 # One configuration for all build modes |
| 631 vsp.AddConfig('all', {}, {}) |
| 632 |
| 633 # Add files |
| 634 for f in folders: |
| 635 if f[0] is None: |
| 636 continue # Skip filters |
| 637 vsp.AddFiles(f[0], f[2]) |
| 638 |
| 639 vsp.Write() |
| 640 return 0 |
| 641 |
| 642 |
| 643 def ComponentVSDirProject(self, project_name, source, **kwargs): |
| 644 """Visual Studio directory project pseudo-builder. |
| 645 |
| 646 Args: |
| 647 self: Environment context. |
| 648 project_name: Name of the project. |
| 649 source: List of source files and/or directories. |
| 650 kwargs: Optional keyword arguments override environment variables in the |
| 651 derived environment used to create the project. |
| 652 |
| 653 Returns: |
| 654 A list of output nodes. |
| 655 """ |
| 656 # Builder only works on Windows |
| 657 if sys.platform not in ('win32', 'cygwin'): |
| 658 return [] |
| 659 |
| 660 # Clone environment and add keyword args |
| 661 env = self.Clone() |
| 662 for k, v in kwargs.items(): |
| 663 env[k] = v |
| 664 |
| 665 # Save the project name and sources |
| 666 env['PROJECT_NAME'] = project_name |
| 667 env['PROJECT_SOURCES'] = source |
| 668 |
| 669 # Call the real builder |
| 670 return env.ComponentVSDirProjectBuilder( |
| 671 '$COMPONENT_VS_PROJECT_DIR/${PROJECT_NAME}', []) |
| 672 |
| 673 #------------------------------------------------------------------------------ |
| 674 |
| 675 |
| 228 def ComponentVSSolutionBuilder(target, source, env): | 676 def ComponentVSSolutionBuilder(target, source, env): |
| 229 """Visual Studio solution builder. | 677 """Visual Studio solution builder. |
| 230 | 678 |
| 231 Args: | 679 Args: |
| 232 target: Destination file. | 680 target: Destination file. |
| 233 source: List of sources to be added to the target. | 681 source: List of sources to be added to the target. |
| 234 env: Environment context. | 682 env: Environment context. |
| 235 | 683 |
| 236 Returns: | 684 Returns: |
| 237 Zero if successful. | 685 Zero if successful. |
| 238 """ | 686 """ |
| 239 source = source # Silence gpylint | 687 source = source # Silence gpylint |
| 240 | 688 |
| 241 solution_file = target[0].path | 689 solution_file = target[0].path |
| 242 projects = env['SOLUTION_PROJECTS'] | 690 projects = env['SOLUTION_PROJECTS'] |
| 243 folders = env['SOLUTION_FOLDERS'] | 691 folders = env['SOLUTION_FOLDERS'] |
| 244 | 692 |
| 693 # Scan externally-generated projects |
| 694 external_projects = [] |
| 695 for p in source: |
| 696 guid, name = GetGuidAndNameFromVSProject(p.abspath) |
| 697 external_projects.append((p, name, guid)) |
| 698 |
| 245 f = open(solution_file, 'wt') | 699 f = open(solution_file, 'wt') |
| 246 | |
| 247 f.write('Microsoft Visual Studio Solution File, Format Version 9.00\n') | 700 f.write('Microsoft Visual Studio Solution File, Format Version 9.00\n') |
| 248 f.write('# Visual Studio 2005\n') | 701 f.write('# Visual Studio 2005\n') |
| 249 | 702 |
| 250 # Projects generated by ComponentVSSolution() | 703 # Projects generated by ComponentVSSolution() |
| 251 for p in projects: | 704 for p in projects: |
| 252 project_file = env.File( | 705 project_file = env.File( |
| 253 '$COMPONENT_VS_PROJECT_DIR/%s$COMPONENT_VS_PROJECT_SUFFIX' % p) | 706 '$COMPONENT_VS_PROJECT_DIR/%s$COMPONENT_VS_PROJECT_SUFFIX' % p) |
| 254 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( | 707 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( |
| 255 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID | 708 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID |
| 256 p, # Project name | 709 p, # Project name |
| 257 env.RelativePath(target[0].dir, project_file), # Path to project file | 710 env.RelativePath(target[0].dir, project_file), # Path to project file |
| 258 MakeGuid(p), # Project GUID | 711 MakeGuid(p), # Project GUID |
| 259 )) | 712 )) |
| 260 | 713 |
| 261 # Projects generated elsewhere | 714 # Projects generated elsewhere |
| 262 for p in source: | 715 for p, name, guid in external_projects: |
| 263 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( | 716 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( |
| 264 # TODO(rspangler): What if this project isn't type external makefile? | 717 # TODO(rspangler): What if this project isn't type external makefile? |
| 265 # How to tell what type it is? | 718 # How to tell what type it is? |
| 266 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID | 719 '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}', # External makefile GUID |
| 267 p, # Project name | 720 name, # Project name |
| 268 env.RelativePath(target[0].dir, p), # Path to project file | 721 env.RelativePath(target[0].dir, p), # Path to project file |
| 269 GetGuidFromVSProject(p.abspath), # Project GUID | 722 guid, # Project GUID |
| 270 )) | 723 )) |
| 271 | 724 |
| 272 # Folders from build groups | 725 # Folders from build groups |
| 726 # TODO(rspangler): Currently no way to add external project (specified in |
| 727 # sources) to a solution folder. |
| 273 for folder in folders: | 728 for folder in folders: |
| 274 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( | 729 f.write('Project("%s") = "%s", "%s", "%s"\nEndProject\n' % ( |
| 275 '{2150E333-8FDC-42A3-9474-1A3956D46DE8}', # Solution folder GUID | 730 '{2150E333-8FDC-42A3-9474-1A3956D46DE8}', # Solution folder GUID |
| 276 folder, # Folder name | 731 folder, # Folder name |
| 277 folder, # Folder name (again) | 732 folder, # Folder name (again) |
| 278 # Use a different seed so the folder won't get the same GUID as a | 733 # Use a different seed so the folder won't get the same GUID as a |
| 279 # project. | 734 # project. |
| 280 MakeGuid(folder, seed='folder'), # Project GUID | 735 MakeGuid(folder, seed='folder'), # Project GUID |
| 281 )) | 736 )) |
| 282 | 737 |
| 283 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n') | 738 f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n') |
| 284 for mode in GetTargetModes(): | 739 for mode in GetTargetModes(): |
| 285 f.write('\t\t%s|Win32 = %s|Win32\n' % (mode, mode)) | 740 f.write('\t\t%s|Win32 = %s|Win32\n' % (mode, mode)) |
| 286 f.write('\tEndGlobalSection\n') | 741 f.write('\tEndGlobalSection\n') |
| 287 | 742 |
| 743 # Determine which projects should be enabled |
| 744 # TODO(rspangler): This is somewhat clunky. DEFAULT_TARGETS is global, and |
| 745 # what we really need is something mode-specific. In theory we could make |
| 746 # this a mode-specific dict rather than a list, but that'd also be a pain to |
| 747 # populate. |
| 748 # These variable names are also getting REALLY long. Perhaps we should |
| 749 # define shorter ones (with the default value redirecting to the longer |
| 750 # ones for legacy compatibility). |
| 751 enable_projects = env.SubstList2('$COMPONENT_VS_ENABLED_PROJECTS') |
| 752 |
| 288 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n') | 753 f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n') |
| 754 |
| 755 # Projects generated by ComponentVSSolution() |
| 289 for p in projects: | 756 for p in projects: |
| 290 for mode in GetTargetModes(): | 757 for mode in GetTargetModes(): |
| 291 f.write('\t\t%s.%s|Win32.ActiveCfg = %s|Win32\n' % ( | 758 f.write('\t\t%s.%s|Win32.ActiveCfg = %s|Win32\n' % ( |
| 292 MakeGuid(p), # Project GUID | 759 MakeGuid(p), # Project GUID |
| 293 mode, # Solution build configuration | 760 mode, # Solution build configuration |
| 294 mode, # Project build config for that solution config | 761 mode, # Project build config for that solution config |
| 295 )) | 762 )) |
| 763 |
| 296 t = GetTargets().get(p) | 764 t = GetTargets().get(p) |
| 297 if t and mode in t.mode_properties: | 765 |
| 766 # Determine if project should be enabled in this mode |
| 767 enabled = t and mode in t.mode_properties |
| 768 if enable_projects and p not in enable_projects: |
| 769 # Enable list specified, but target isn't in it |
| 770 # TODO(rspangler): Since we env.Default(scons-out) elsewhere, this |
| 771 # likely causes all projects to be disabled by default. But that's |
| 772 # realistically better than enabling them all... |
| 773 enabled = False |
| 774 |
| 775 if enabled: |
| 298 # Target can be built in this mode | 776 # Target can be built in this mode |
| 299 f.write('\t\t%s.%s|Win32.Build.0 = %s|Win32\n' % ( | 777 f.write('\t\t%s.%s|Win32.Build.0 = %s|Win32\n' % ( |
| 300 MakeGuid(p), # Project GUID | 778 MakeGuid(p), # Project GUID |
| 301 mode, # Solution build configuration | 779 mode, # Solution build configuration |
| 302 mode, # Project build config for that solution config | 780 mode, # Project build config for that solution config |
| 303 )) | 781 )) |
| 782 |
| 783 # Projects generated elsewhere |
| 784 for p, name, guid in external_projects: |
| 785 for mode in GetTargetModes(): |
| 786 f.write('\t\t%s.%s|Win32.ActiveCfg = %s|Win32\n' % ( |
| 787 guid, # Project GUID |
| 788 mode, # Solution build configuration |
| 789 mode, # Project build config for that solution config |
| 790 )) |
| 791 |
| 792 if name in enable_projects or not enable_projects: |
| 793 # Build target in this mode |
| 794 f.write('\t\t%s.%s|Win32.Build.0 = %s|Win32\n' % ( |
| 795 guid, # Project GUID |
| 796 mode, # Solution build configuration |
| 797 mode, # Project build config for that solution config |
| 798 )) |
| 799 |
| 304 f.write('\tEndGlobalSection\n') | 800 f.write('\tEndGlobalSection\n') |
| 305 | 801 |
| 306 f.write('\tGlobalSection(SolutionProperties) = preSolution\n') | 802 f.write('\tGlobalSection(SolutionProperties) = preSolution\n') |
| 307 f.write('\t\tHideSolutionNode = FALSE\n') | 803 f.write('\t\tHideSolutionNode = FALSE\n') |
| 308 f.write('\tEndGlobalSection\n') | 804 f.write('\tEndGlobalSection\n') |
| 309 | 805 |
| 310 if folders: | 806 if folders: |
| 311 f.write('\tGlobalSection(NestedProjects) = preSolution\n') | 807 f.write('\tGlobalSection(NestedProjects) = preSolution\n') |
| 312 for p, folder in projects.items(): | 808 for p, folder in projects.items(): |
| 313 f.write('\t\t%s = %s\n' % (MakeGuid(p), MakeGuid(folder, seed='folder'))) | 809 f.write('\t\t%s = %s\n' % (MakeGuid(p), MakeGuid(folder, seed='folder'))) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 env[k] = v | 850 env[k] = v |
| 355 | 851 |
| 356 # Save the target name | 852 # Save the target name |
| 357 env['SOLUTION_NAME'] = solution_name | 853 env['SOLUTION_NAME'] = solution_name |
| 358 | 854 |
| 359 # Get list of targets to make projects for. At this point we haven't | 855 # Get list of targets to make projects for. At this point we haven't |
| 360 # determined whether they're groups or targets. | 856 # determined whether they're groups or targets. |
| 361 target_names = env.SubstList2(target_names) | 857 target_names = env.SubstList2(target_names) |
| 362 env['SOLUTION_TARGETS'] = target_names | 858 env['SOLUTION_TARGETS'] = target_names |
| 363 | 859 |
| 860 # Save the default targets list as an environment variable |
| 861 env['COMPONENT_VS_SCONS_DEFAULT_TARGETS'] = SCons.Script.DEFAULT_TARGETS |
| 862 |
| 863 # Expand target_names into project names, and create project-to-folder |
| 864 # mappings |
| 364 project_names = {} | 865 project_names = {} |
| 365 folders = [] | 866 folders = [] |
| 366 # Expand target_names into project names, and create project-to-folder | |
| 367 # mappings | |
| 368 if target_names: | 867 if target_names: |
| 369 # Expand target_names into project names | 868 # Expand target_names into project names |
| 370 for target in target_names: | 869 for target in target_names: |
| 371 if target in GetTargetGroups(): | 870 if target in GetTargetGroups(): |
| 372 # Add target to folders | 871 # Add target to folders |
| 373 folders.append(target) | 872 folders.append(target) |
| 374 # Add all project_names in the group | 873 # Add all project_names in the group |
| 375 for t in GetTargetGroups()[target].GetTargetNames(): | 874 for t in GetTargetGroups()[target].GetTargetNames(): |
| 376 project_names[t] = target | 875 project_names[t] = target |
| 377 elif target in GetTargets(): | 876 elif target in GetTargets(): |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 #------------------------------------------------------------------------------ | 912 #------------------------------------------------------------------------------ |
| 414 | 913 |
| 415 | 914 |
| 416 def generate(env): | 915 def generate(env): |
| 417 # NOTE: SCons requires the use of this name, which fails gpylint. | 916 # NOTE: SCons requires the use of this name, which fails gpylint. |
| 418 """SCons entry point for this tool.""" | 917 """SCons entry point for this tool.""" |
| 419 | 918 |
| 420 # Add pseudo-builders to set up the project and solution builders. These | 919 # Add pseudo-builders to set up the project and solution builders. These |
| 421 # need to be available on all platforms so that SConscripts which reference | 920 # need to be available on all platforms so that SConscripts which reference |
| 422 # them will work. | 921 # them will work. |
| 922 env.AddMethod(ComponentVSDirProject) |
| 423 env.AddMethod(ComponentVSProject) | 923 env.AddMethod(ComponentVSProject) |
| 424 env.AddMethod(ComponentVSSolution) | 924 env.AddMethod(ComponentVSSolution) |
| 925 env.AddMethod(ComponentVSSourceProject) |
| 425 | 926 |
| 426 # If not on Windows, don't do anything else | 927 # If not on Windows, don't do anything else |
| 427 if sys.platform not in ('win32', 'cygwin'): | 928 if sys.platform not in ('win32', 'cygwin'): |
| 428 return | 929 return |
| 429 | 930 |
| 430 # Include tools we need | 931 # Include tools we need |
| 431 env.Tool('gather_inputs') | 932 env.Tool('gather_inputs') |
| 432 | 933 |
| 433 env.SetDefault( | 934 env.SetDefault( |
| 434 COMPONENT_VS_SOLUTION_DIR='$DESTINATION_ROOT/solution', | |
| 435 COMPONENT_VS_PROJECT_DIR='$COMPONENT_VS_SOLUTION_DIR/projects', | 935 COMPONENT_VS_PROJECT_DIR='$COMPONENT_VS_SOLUTION_DIR/projects', |
| 436 COMPONENT_VS_SOLUTION_SUFFIX='.sln', | |
| 437 COMPONENT_VS_PROJECT_SUFFIX='.vcproj', | |
| 438 COMPONENT_VS_PROJECT_SCRIPT_NAME = 'hammer.bat', | 936 COMPONENT_VS_PROJECT_SCRIPT_NAME = 'hammer.bat', |
| 439 COMPONENT_VS_PROJECT_SCRIPT_PATH = ( | 937 COMPONENT_VS_PROJECT_SCRIPT_PATH = ( |
| 440 '$$(ProjectDir)/$VS_PROJECT_TO_MAIN_DIR/' | 938 '$$(ProjectDir)/$VS_PROJECT_TO_MAIN_DIR/' |
| 441 '$COMPONENT_VS_PROJECT_SCRIPT_NAME'), | 939 '$COMPONENT_VS_PROJECT_SCRIPT_NAME'), |
| 940 COMPONENT_VS_PROJECT_SUFFIX='.vcproj', |
| 941 |
| 942 COMPONENT_VS_SOLUTION_DIR='$DESTINATION_ROOT/solution', |
| 943 COMPONENT_VS_SOLUTION_SUFFIX='.sln', |
| 944 COMPONENT_VS_ENABLED_PROJECTS=['$COMPONENT_VS_SCONS_DEFAULT_TARGETS'], |
| 945 |
| 946 COMPONENT_VS_SOURCE_SUFFIXES=['$CPPSUFFIXES', '.rc', '.scons'], |
| 947 COMPONENT_VS_SOURCE_FOLDERS=[('source', '$MAIN_DIR')], |
| 442 ) | 948 ) |
| 443 | 949 |
| 444 AddTargetGroup('all_solutions', 'solutions can be built') | 950 AddTargetGroup('all_solutions', 'solutions can be built') |
| 445 | 951 |
| 446 # Add builders | 952 # Add builders |
| 447 vcprojaction = SCons.Script.Action(ComponentVSProjectBuilder, varlist=[ | 953 vcprojaction = SCons.Script.Action(ComponentVSProjectBuilder, varlist=[ |
| 954 'COMPONENT_VS_PROJECT_SCRIPT_PATH', |
| 448 'TARGET_NAME', | 955 'TARGET_NAME', |
| 449 'TARGET_PATH', | 956 'TARGET_PATH', |
| 450 'COMPONENT_VS_PROJECT_SCRIPT_PATH', | |
| 451 ]) | 957 ]) |
| 452 vcprojbuilder = SCons.Script.Builder( | 958 vcprojbuilder = SCons.Script.Builder( |
| 453 action=vcprojaction, | 959 action=vcprojaction, |
| 454 suffix='$COMPONENT_VS_PROJECT_SUFFIX') | 960 suffix='$COMPONENT_VS_PROJECT_SUFFIX') |
| 455 | 961 |
| 962 source_vcproj_action = SCons.Script.Action( |
| 963 ComponentVSSourceProjectBuilder, varlist=[ |
| 964 'COMPONENT_VS_SOURCE_FOLDERS', |
| 965 'COMPONENT_VS_SOURCE_SUFFIXES', |
| 966 'COMPONENT_VS_SOURCE_TARGETS', |
| 967 ]) |
| 968 source_vcproj_builder = SCons.Script.Builder( |
| 969 action=source_vcproj_action, |
| 970 suffix='$COMPONENT_VS_PROJECT_SUFFIX') |
| 971 |
| 972 dir_vcproj_action = SCons.Script.Action( |
| 973 ComponentVSDirProjectBuilder, varlist=[ |
| 974 'COMPONENT_VS_SOURCE_FOLDERS', |
| 975 'COMPONENT_VS_SOURCE_SUFFIXES', |
| 976 'PROJECT_SOURCES', |
| 977 ]) |
| 978 dir_vcproj_builder = SCons.Script.Builder( |
| 979 action=dir_vcproj_action, |
| 980 suffix='$COMPONENT_VS_PROJECT_SUFFIX') |
| 981 |
| 456 slnaction = SCons.Script.Action(ComponentVSSolutionBuilder, varlist=[ | 982 slnaction = SCons.Script.Action(ComponentVSSolutionBuilder, varlist=[ |
| 457 'SOLUTION_TARGETS', | 983 'COMPONENT_VS_ENABLED_PROJECTS', |
| 458 'SOLUTION_FOLDERS', | 984 'SOLUTION_FOLDERS', |
| 459 'SOLUTION_PROJECTS', | 985 'SOLUTION_PROJECTS', |
| 986 'SOLUTION_TARGETS', |
| 460 ]) | 987 ]) |
| 461 slnbuilder = SCons.Script.Builder( | 988 slnbuilder = SCons.Script.Builder( |
| 462 action=slnaction, | 989 action=slnaction, |
| 463 suffix='$COMPONENT_VS_SOLUTION_SUFFIX') | 990 suffix='$COMPONENT_VS_SOLUTION_SUFFIX') |
| 464 | 991 |
| 465 env.Append(BUILDERS={ | 992 env.Append(BUILDERS={ |
| 993 'ComponentVSDirProjectBuilder': dir_vcproj_builder, |
| 466 'ComponentVSProjectBuilder': vcprojbuilder, | 994 'ComponentVSProjectBuilder': vcprojbuilder, |
| 467 'ComponentVSSolutionBuilder': slnbuilder, | 995 'ComponentVSSolutionBuilder': slnbuilder, |
| 996 'ComponentVSSourceProjectBuilder': source_vcproj_builder, |
| 468 }) | 997 }) |
| OLD | NEW |