Index: pylib/gyp/generator/analyzer.py |
diff --git a/pylib/gyp/generator/analyzer.py b/pylib/gyp/generator/analyzer.py |
index f403d4e266b048e59b81512ad43c2a95e37dcc74..298c6635e035e74f57a00bf26791d370c0709ac8 100644 |
--- a/pylib/gyp/generator/analyzer.py |
+++ b/pylib/gyp/generator/analyzer.py |
@@ -15,13 +15,32 @@ targets: the set of targets passed in via targets that either directly or |
indirectly depend upon the set of paths supplied in files. |
build_targets: minimal set of targets that directly depend on the changed |
files and need to be built. The expectation is this set of targets is passed |
- into a build step. |
+ into a build step. The returned values are either values in the supplied |
+ targets, or have a dependency on one of the supplied targets. |
status: outputs one of three values: none of the supplied files were found, |
one of the include files changed so that it should be assumed everything |
changed (in this case targets and build_targets are not output) or at |
least one file was found. |
invalid_targets: list of supplied targets thare were not found. |
+|targets| and |build_targets| are very closely related but subtly different. |
+Consider a graph like the following: |
+ A D |
+ / \ |
+B C |
+A depends upon both B and C, A is of type none and B and C are executables. |
+D is an executable, has no dependencies and nothing depends on it. |
+If |targets| = ["A"] and files = ["b.cc", "d.cc"] (B depends upon b.cc and D |
+depends upon d.cc), then the following is output: |
+|targets| = ["A"] A is output because A depends upon B and B has the changed |
+file b.cc. |
+|build_targets| = ["B"] B must built as it depends upon the changed file b.cc |
+and the supplied target A depends upon it. A is not output as a build_target |
+as it is of type none with no rules and actions. |
Dirk Pranke
2015/10/12 19:01:28
I thought we agreed that we were going to get rid
sky
2015/10/12 19:05:18
I'm fine with that, but wasn't sure about the stag
|
+ |
+Even though the file d.cc, which D depends upon, has changed D is not output |
+as none of the supplied targets (A) depend upon D. |
+ |
If the generator flag analyzer_output_path is specified, output is written |
there. Otherwise output is written to stdout. |
""" |
@@ -259,13 +278,12 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir): |
def _GetOrCreateTargetByName(targets, target_name): |
"""Creates or returns the Target at targets[target_name]. If there is no |
- Target for |target_name| one is created. Returns a tuple of whether a new |
- Target was created and the Target.""" |
+ Target for |target_name| one is created.""" |
if target_name in targets: |
- return False, targets[target_name] |
+ return targets[target_name] |
target = Target(target_name) |
targets[target_name] = target |
- return True, target |
+ return target |
def _DoesTargetTypeRequireBuild(target_dict): |
@@ -280,7 +298,6 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, |
"""Returns a tuple of the following: |
. A dictionary mapping from fully qualified name to Target. |
. A list of the targets that have a source file in |files|. |
- . Set of root Targets reachable from the the files |build_files|. |
This sets the |match_status| of the targets that contain any of the source |
files in |files| to MATCH_STATUS_MATCHES. |
|toplevel_dir| is the root of the source tree.""" |
@@ -297,18 +314,10 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, |
# |files|. |
build_file_in_files = {} |
- # Root targets across all files. |
- roots = set() |
- |
- # Set of Targets in |build_files|. |
- build_file_targets = set() |
- |
while len(targets_to_visit) > 0: |
target_name = targets_to_visit.pop() |
- created_target, target = _GetOrCreateTargetByName(targets, target_name) |
- if created_target: |
- roots.add(target) |
- elif target.visited: |
+ target = _GetOrCreateTargetByName(targets, target_name) |
+ if target.visited: |
continue |
target.visited = True |
@@ -325,9 +334,6 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, |
build_file_in_files[build_file] = \ |
_WasBuildFileModified(build_file, data, files, toplevel_dir) |
- if build_file in build_files: |
- build_file_targets.add(target) |
- |
# If a build file (or any of its included files) is modified we assume all |
# targets in the file are modified. |
if build_file_in_files[build_file]: |
@@ -348,14 +354,12 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files, |
for dep in target_dicts[target_name].get('dependencies', []): |
targets_to_visit.append(dep) |
- created_dep_target, dep_target = _GetOrCreateTargetByName(targets, dep) |
- if not created_dep_target: |
- roots.discard(dep_target) |
+ dep_target = _GetOrCreateTargetByName(targets, dep) |
target.deps.add(dep_target) |
dep_target.back_deps.add(target) |
- return targets, matching_targets, roots & build_file_targets |
+ return targets, matching_targets |
def _GetUnqualifiedToTargetMapping(all_targets, to_find): |
@@ -405,21 +409,19 @@ def _GetTargetsDependingOn(possible_targets): |
return found |
-def _AddBuildTargets(target, roots, add_if_no_ancestor, result): |
+def _AddBuildTargets(target, roots, result): |
"""Recurses through all targets that depend on |target|, adding all targets |
that need to be built (and are in |roots|) to |result|. |
roots: set of root targets. |
- add_if_no_ancestor: If true and there are no ancestors of |target| then add |
- |target| to |result|. |target| must still be in |roots|. |
result: targets that need to be built are added here.""" |
if target.visited: |
return |
target.visited = True |
- target.in_roots = not target.back_deps and target in roots |
+ target.in_roots = target in roots |
for back_dep_target in target.back_deps: |
- _AddBuildTargets(back_dep_target, roots, False, result) |
+ _AddBuildTargets(back_dep_target, roots, result) |
target.added_to_compile_targets |= back_dep_target.added_to_compile_targets |
target.in_roots |= back_dep_target.in_roots |
target.is_or_has_linked_ancestor |= ( |
@@ -433,16 +435,14 @@ def _AddBuildTargets(target, roots, add_if_no_ancestor, result): |
# static libraries themselves, which are not compile time dependencies. |
if target.in_roots and \ |
(target.is_executable or |
- (not target.added_to_compile_targets and |
- (add_if_no_ancestor or target.requires_build)) or |
- (target.is_static_library and add_if_no_ancestor and |
- not target.is_or_has_linked_ancestor)): |
+ (not target.added_to_compile_targets and target.requires_build) or |
+ (target.is_static_library and not target.is_or_has_linked_ancestor)): |
print '\t\tadding to build targets', target.name, 'executable', \ |
target.is_executable, 'added_to_compile_targets', \ |
- target.added_to_compile_targets, 'add_if_no_ancestor', \ |
- add_if_no_ancestor, 'requires_build', target.requires_build, \ |
- 'is_static_library', target.is_static_library, \ |
- 'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor |
+ target.added_to_compile_targets, 'requires_build', \ |
+ target.requires_build, 'is_static_library', \ |
+ target.is_static_library, 'is_or_has_linked_ancestor', \ |
+ target.is_or_has_linked_ancestor |
result.add(target) |
target.added_to_compile_targets = True |
@@ -454,7 +454,7 @@ def _GetBuildTargets(matching_targets, roots): |
result = set() |
for target in matching_targets: |
print '\tfinding build targets for match', target.name |
- _AddBuildTargets(target, roots, True, result) |
+ _AddBuildTargets(target, roots, result) |
return result |
@@ -557,14 +557,10 @@ def GenerateOutput(target_list, target_dicts, data, params): |
_WriteOutput(params, **result_dict) |
return |
- all_targets, matching_targets, roots = _GenerateTargets( |
+ all_targets, matching_targets = _GenerateTargets( |
data, target_list, target_dicts, toplevel_dir, frozenset(config.files), |
params['build_files']) |
- print 'roots:' |
- for root in roots: |
- print '\t', root.name |
- |
unqualified_mapping = _GetUnqualifiedToTargetMapping(all_targets, |
config.targets) |
invalid_targets = None |
@@ -587,7 +583,7 @@ def GenerateOutput(target_list, target_dicts, data, params): |
for target in all_targets.itervalues(): |
target.visited = False |
print 'Finding build targets' |
- build_targets = _GetBuildTargets(matching_targets, roots) |
+ build_targets = _GetBuildTargets(matching_targets, search_targets) |
matched_search_targets = [gyp.common.ParseQualifiedTarget(target.name)[1] |
for target in matched_search_targets] |
build_targets = [gyp.common.ParseQualifiedTarget(target.name)[1] |