OLD | NEW |
1 # Copyright (c) 2014 Google Inc. All rights reserved. | 1 # Copyright (c) 2014 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """ | 5 """ |
6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of | 6 This script is intended for use as a GYP_GENERATOR. It takes as input (by way of |
7 the generator flag config_path) the path of a json file that dictates the files | 7 the generator flag config_path) the path of a json file that dictates the files |
8 and targets to search for. The following keys are supported: | 8 and targets to search for. The following keys are supported: |
9 files: list of paths (relative) of the files to search for. | 9 files: list of paths (relative) of the files to search for. |
10 targets: list of targets to search for. The target names are unqualified. | 10 targets: list of targets to search for. The target names are unqualified. |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 if _ToLocalPath(toplevel_dir, rel_include_file) in files: | 267 if _ToLocalPath(toplevel_dir, rel_include_file) in files: |
268 if debug: | 268 if debug: |
269 print 'included gyp file modified, gyp_file=', build_file, \ | 269 print 'included gyp file modified, gyp_file=', build_file, \ |
270 'included file=', rel_include_file | 270 'included file=', rel_include_file |
271 return True | 271 return True |
272 return False | 272 return False |
273 | 273 |
274 | 274 |
275 def _GetOrCreateTargetByName(targets, target_name): | 275 def _GetOrCreateTargetByName(targets, target_name): |
276 """Creates or returns the Target at targets[target_name]. If there is no | 276 """Creates or returns the Target at targets[target_name]. If there is no |
277 Target for |target_name| one is created.""" | 277 Target for |target_name| one is created. Returns a tuple of whether a new |
| 278 Target was created and the Target.""" |
278 if target_name in targets: | 279 if target_name in targets: |
279 return targets[target_name] | 280 return False, targets[target_name] |
280 target = Target(target_name) | 281 target = Target(target_name) |
281 targets[target_name] = target | 282 targets[target_name] = target |
282 return target | 283 return True, target |
283 | 284 |
284 | 285 |
285 def _DoesTargetTypeRequireBuild(target_dict): | 286 def _DoesTargetTypeRequireBuild(target_dict): |
286 """Returns true if the target type is such that it needs to be built.""" | 287 """Returns true if the target type is such that it needs to be built.""" |
287 # If a 'none' target has rules or actions we assume it requires a build. | 288 # If a 'none' target has rules or actions we assume it requires a build. |
288 return bool(target_dict['type'] != 'none' or | 289 return bool(target_dict['type'] != 'none' or |
289 target_dict.get('actions') or target_dict.get('rules')) | 290 target_dict.get('actions') or target_dict.get('rules')) |
290 | 291 |
291 | 292 |
292 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, | 293 def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, |
293 build_files): | 294 build_files): |
294 """Returns a tuple of the following: | 295 """Returns a tuple of the following: |
295 . A dictionary mapping from fully qualified name to Target. | 296 . A dictionary mapping from fully qualified name to Target. |
296 . A list of the targets that have a source file in |files|. | 297 . A list of the targets that have a source file in |files|. |
| 298 . Set of root Targets reachable from the the files |build_files|. This |
| 299 is the set of targets built by the 'all' target. |
297 This sets the |match_status| of the targets that contain any of the source | 300 This sets the |match_status| of the targets that contain any of the source |
298 files in |files| to MATCH_STATUS_MATCHES. | 301 files in |files| to MATCH_STATUS_MATCHES. |
299 |toplevel_dir| is the root of the source tree.""" | 302 |toplevel_dir| is the root of the source tree.""" |
300 # Maps from target name to Target. | 303 # Maps from target name to Target. |
301 targets = {} | 304 targets = {} |
302 | 305 |
303 # Targets that matched. | 306 # Targets that matched. |
304 matching_targets = [] | 307 matching_targets = [] |
305 | 308 |
306 # Queue of targets to visit. | 309 # Queue of targets to visit. |
307 targets_to_visit = target_list[:] | 310 targets_to_visit = target_list[:] |
308 | 311 |
309 # Maps from build file to a boolean indicating whether the build file is in | 312 # Maps from build file to a boolean indicating whether the build file is in |
310 # |files|. | 313 # |files|. |
311 build_file_in_files = {} | 314 build_file_in_files = {} |
312 | 315 |
| 316 # Root targets across all files. |
| 317 roots = set() |
| 318 |
| 319 # Set of Targets in |build_files|. |
| 320 build_file_targets = set() |
| 321 |
313 while len(targets_to_visit) > 0: | 322 while len(targets_to_visit) > 0: |
314 target_name = targets_to_visit.pop() | 323 target_name = targets_to_visit.pop() |
315 target = _GetOrCreateTargetByName(targets, target_name) | 324 created_target, target = _GetOrCreateTargetByName(targets, target_name) |
316 if target.visited: | 325 if created_target: |
| 326 roots.add(target) |
| 327 elif target.visited: |
317 continue | 328 continue |
318 | 329 |
319 target.visited = True | 330 target.visited = True |
320 target.requires_build = _DoesTargetTypeRequireBuild( | 331 target.requires_build = _DoesTargetTypeRequireBuild( |
321 target_dicts[target_name]) | 332 target_dicts[target_name]) |
322 target_type = target_dicts[target_name]['type'] | 333 target_type = target_dicts[target_name]['type'] |
323 target.is_executable = target_type == 'executable' | 334 target.is_executable = target_type == 'executable' |
324 target.is_static_library = target_type == 'static_library' | 335 target.is_static_library = target_type == 'static_library' |
325 target.is_or_has_linked_ancestor = (target_type == 'executable' or | 336 target.is_or_has_linked_ancestor = (target_type == 'executable' or |
326 target_type == 'shared_library') | 337 target_type == 'shared_library') |
327 | 338 |
328 build_file = gyp.common.ParseQualifiedTarget(target_name)[0] | 339 build_file = gyp.common.ParseQualifiedTarget(target_name)[0] |
329 if not build_file in build_file_in_files: | 340 if not build_file in build_file_in_files: |
330 build_file_in_files[build_file] = \ | 341 build_file_in_files[build_file] = \ |
331 _WasBuildFileModified(build_file, data, files, toplevel_dir) | 342 _WasBuildFileModified(build_file, data, files, toplevel_dir) |
332 | 343 |
| 344 if build_file in build_files: |
| 345 build_file_targets.add(target) |
| 346 |
333 # If a build file (or any of its included files) is modified we assume all | 347 # If a build file (or any of its included files) is modified we assume all |
334 # targets in the file are modified. | 348 # targets in the file are modified. |
335 if build_file_in_files[build_file]: | 349 if build_file_in_files[build_file]: |
336 print 'matching target from modified build file', target_name | 350 print 'matching target from modified build file', target_name |
337 target.match_status = MATCH_STATUS_MATCHES | 351 target.match_status = MATCH_STATUS_MATCHES |
338 matching_targets.append(target) | 352 matching_targets.append(target) |
339 else: | 353 else: |
340 sources = _ExtractSources(target_name, target_dicts[target_name], | 354 sources = _ExtractSources(target_name, target_dicts[target_name], |
341 toplevel_dir) | 355 toplevel_dir) |
342 for source in sources: | 356 for source in sources: |
343 if _ToGypPath(os.path.normpath(source)) in files: | 357 if _ToGypPath(os.path.normpath(source)) in files: |
344 print 'target', target_name, 'matches', source | 358 print 'target', target_name, 'matches', source |
345 target.match_status = MATCH_STATUS_MATCHES | 359 target.match_status = MATCH_STATUS_MATCHES |
346 matching_targets.append(target) | 360 matching_targets.append(target) |
347 break | 361 break |
348 | 362 |
349 # Add dependencies to visit as well as updating back pointers for deps. | 363 # Add dependencies to visit as well as updating back pointers for deps. |
350 for dep in target_dicts[target_name].get('dependencies', []): | 364 for dep in target_dicts[target_name].get('dependencies', []): |
351 targets_to_visit.append(dep) | 365 targets_to_visit.append(dep) |
352 | 366 |
353 dep_target = _GetOrCreateTargetByName(targets, dep) | 367 created_dep_target, dep_target = _GetOrCreateTargetByName(targets, dep) |
| 368 if not created_dep_target: |
| 369 roots.discard(dep_target) |
354 | 370 |
355 target.deps.add(dep_target) | 371 target.deps.add(dep_target) |
356 dep_target.back_deps.add(target) | 372 dep_target.back_deps.add(target) |
357 | 373 |
358 return targets, matching_targets | 374 return targets, matching_targets, roots & build_file_targets |
359 | 375 |
360 | 376 |
361 def _GetUnqualifiedToTargetMapping(all_targets, to_find): | 377 def _GetUnqualifiedToTargetMapping(all_targets, to_find): |
362 """Returns a mapping (dictionary) from unqualified name to Target for all the | 378 """Returns a mapping (dictionary) from unqualified name to Target for all the |
363 Targets in |to_find|.""" | 379 Targets in |to_find|.""" |
364 result = {} | 380 result = {} |
365 if not to_find: | 381 if not to_find: |
366 return result | 382 return result |
367 to_find = set(to_find) | 383 to_find = set(to_find) |
368 for target_name in all_targets.keys(): | 384 for target_name in all_targets.keys(): |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) | 532 toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir)) |
517 if debug: | 533 if debug: |
518 print 'toplevel_dir', toplevel_dir | 534 print 'toplevel_dir', toplevel_dir |
519 | 535 |
520 if _WasGypIncludeFileModified(params, config.files): | 536 if _WasGypIncludeFileModified(params, config.files): |
521 result_dict = { 'status': all_changed_string, | 537 result_dict = { 'status': all_changed_string, |
522 'targets': list(config.targets) } | 538 'targets': list(config.targets) } |
523 _WriteOutput(params, **result_dict) | 539 _WriteOutput(params, **result_dict) |
524 return | 540 return |
525 | 541 |
526 all_targets, matching_targets = _GenerateTargets( | 542 all_targets, matching_targets, _ = _GenerateTargets( |
527 data, target_list, target_dicts, toplevel_dir, frozenset(config.files), | 543 data, target_list, target_dicts, toplevel_dir, frozenset(config.files), |
528 params['build_files']) | 544 params['build_files']) |
529 | 545 |
530 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets, | 546 unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets, |
531 config.targets) | 547 config.targets) |
532 invalid_targets = None | 548 invalid_targets = None |
533 if len(unqualified_mapping) != len(config.targets): | 549 if len(unqualified_mapping) != len(config.targets): |
534 invalid_targets = _NamesNotIn(config.targets, unqualified_mapping) | 550 invalid_targets = _NamesNotIn(config.targets, unqualified_mapping) |
535 | 551 |
536 if matching_targets: | 552 if matching_targets: |
(...skipping 18 matching lines...) Expand all Loading... |
555 result_dict = { 'targets': build_targets, | 571 result_dict = { 'targets': build_targets, |
556 'status': found_dependency_string if matching_targets else | 572 'status': found_dependency_string if matching_targets else |
557 no_dependency_string, | 573 no_dependency_string, |
558 'build_targets': build_targets} | 574 'build_targets': build_targets} |
559 if invalid_targets: | 575 if invalid_targets: |
560 result_dict['invalid_targets'] = invalid_targets | 576 result_dict['invalid_targets'] = invalid_targets |
561 _WriteOutput(params, **result_dict) | 577 _WriteOutput(params, **result_dict) |
562 | 578 |
563 except Exception as e: | 579 except Exception as e: |
564 _WriteOutput(params, error=str(e)) | 580 _WriteOutput(params, error=str(e)) |
OLD | NEW |