summaryrefslogtreecommitdiffstats
path: root/src/build.cc
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2020-06-10 01:41:27 (GMT)
committerColin Cross <ccross@android.com>2021-10-12 00:34:46 (GMT)
commit04c410b15b70fb321928ffba19d697db15cb0121 (patch)
tree39e12abe514f4794fa3d87ccec2a0c31c9ed3922 /src/build.cc
parentd2dae79908e890222d4fd4fa81c669c40f102c47 (diff)
downloadNinja-04c410b15b70fb321928ffba19d697db15cb0121.zip
Ninja-04c410b15b70fb321928ffba19d697db15cb0121.tar.gz
Ninja-04c410b15b70fb321928ffba19d697db15cb0121.tar.bz2
Add validation nodes to ninja
A common problem in the Android build is inserting rules that perform some sort of error checking that doesn't produce any artifacts needed by the build, for example static analysis tools. There are a few patterns currently used, both of which have downsides. The first is to have a rule that depends on all of the static analysis results. This ensures they run, but requires running static analysis over everything, and not just the active parts of the build graph. The second is to insert the static analysis rule into the build graph between the artifact producing rule and anything that depends on it, often copying the artifact as the output of the static analysis rule. This increases the critical path of the build, often reducing parallelism. In the case of copying the artifact, it also wastes disk space. This patch adds "validation nodes" to edges in Ninja. A build statement can specify validation nodes using "|@" in the edge inputs. The validation nodes are not used as an input to the edge (the edge can run before the validation node is ready), but are added to the initial nodes of the build graph whenever the edge is part of the build graph. The edge that outputs the validation node can depend on the output of the edge that is being validated if desired. Test: ninja_test Change-Id: Ife27086c50c1b257a26509373199664680b2b247
Diffstat (limited to 'src/build.cc')
-rw-r--r--src/build.cc29
1 files changed, 27 insertions, 2 deletions
diff --git a/src/build.cc b/src/build.cc
index 735922b..6f11ed7 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -384,8 +384,21 @@ bool Plan::RefreshDyndepDependents(DependencyScan* scan, const Node* node,
Node* n = *i;
// Check if this dependent node is now dirty. Also checks for new cycles.
- if (!scan->RecomputeDirty(n, err))
+ std::vector<Node*> validation_nodes;
+ if (!scan->RecomputeDirty(n, &validation_nodes, err))
return false;
+
+ // Add any validation nodes found during RecomputeDirty as new top level
+ // targets.
+ for (std::vector<Node*>::iterator v = validation_nodes.begin();
+ v != validation_nodes.end(); ++v) {
+ if (Edge* in_edge = (*v)->in_edge()) {
+ if (!in_edge->outputs_ready() &&
+ !AddTarget(*v, err)) {
+ return false;
+ }
+ }
+ }
if (!n->dirty())
continue;
@@ -553,7 +566,8 @@ Node* Builder::AddTarget(const string& name, string* err) {
}
bool Builder::AddTarget(Node* target, string* err) {
- if (!scan_.RecomputeDirty(target, err))
+ std::vector<Node*> validation_nodes;
+ if (!scan_.RecomputeDirty(target, &validation_nodes, err))
return false;
Edge* in_edge = target->in_edge();
@@ -563,6 +577,17 @@ bool Builder::AddTarget(Node* target, string* err) {
}
}
+ // Also add any validation nodes found during RecomputeDirty as top level
+ // targets.
+ for (std::vector<Node*>::iterator n = validation_nodes.begin();
+ n != validation_nodes.end(); ++n) {
+ if (Edge* validation_in_edge = (*n)->in_edge()) {
+ if (!validation_in_edge->outputs_ready() &&
+ !plan_.AddTarget(*n, err)) {
+ return false;
+ }
+ }
+ }
return true;
}