summaryrefslogtreecommitdiff
path: root/ninja/src/build.h
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /ninja/src/build.h
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'ninja/src/build.h')
-rw-r--r--ninja/src/build.h279
1 files changed, 279 insertions, 0 deletions
diff --git a/ninja/src/build.h b/ninja/src/build.h
new file mode 100644
index 00000000000..2715c0cf722
--- /dev/null
+++ b/ninja/src/build.h
@@ -0,0 +1,279 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef NINJA_BUILD_H_
+#define NINJA_BUILD_H_
+
+#include <cstdio>
+#include <map>
+#include <memory>
+#include <queue>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "graph.h" // XXX needed for DependencyScan; should rearrange.
+#include "exit_status.h"
+#include "line_printer.h"
+#include "metrics.h"
+#include "util.h" // int64_t
+
+struct BuildLog;
+struct BuildStatus;
+struct DiskInterface;
+struct Edge;
+struct Node;
+struct State;
+
+/// Plan stores the state of a build plan: what we intend to build,
+/// which steps we're ready to execute.
+struct Plan {
+ Plan();
+
+ /// Add a target to our plan (including all its dependencies).
+ /// Returns false if we don't need to build this target; may
+ /// fill in |err| with an error message if there's a problem.
+ bool AddTarget(Node* node, string* err);
+
+ // Pop a ready edge off the queue of edges to build.
+ // Returns NULL if there's no work to do.
+ Edge* FindWork();
+
+ /// Returns true if there's more work to be done.
+ bool more_to_do() const { return wanted_edges_; }
+
+ /// Dumps the current state of the plan.
+ void Dump();
+
+ /// Mark an edge as done building. Used internally and by
+ /// tests.
+ void EdgeFinished(Edge* edge);
+
+ /// Clean the given node during the build.
+ void CleanNode(DependencyScan* scan, Node* node);
+
+ /// Number of edges with commands to run.
+ int command_edge_count() const { return command_edges_; }
+
+private:
+ bool AddSubTarget(Node* node, vector<Node*>* stack, string* err);
+ bool CheckDependencyCycle(Node* node, vector<Node*>* stack, string* err);
+ void NodeFinished(Node* node);
+
+ /// Submits a ready edge as a candidate for execution.
+ /// The edge may be delayed from running, for example if it's a member of a
+ /// currently-full pool.
+ void ScheduleWork(Edge* edge);
+
+ /// Allows jobs blocking on |edge| to potentially resume.
+ /// For example, if |edge| is a member of a pool, calling this may schedule
+ /// previously pending jobs in that pool.
+ void ResumeDelayedJobs(Edge* edge);
+
+ /// Keep track of which edges we want to build in this plan. If this map does
+ /// not contain an entry for an edge, we do not want to build the entry or its
+ /// dependents. If an entry maps to false, we do not want to build it, but we
+ /// might want to build one of its dependents. If the entry maps to true, we
+ /// want to build it.
+ map<Edge*, bool> want_;
+
+ set<Edge*> ready_;
+
+ /// Total number of edges that have commands (not phony).
+ int command_edges_;
+
+ /// Total remaining number of wanted edges.
+ int wanted_edges_;
+};
+
+/// CommandRunner is an interface that wraps running the build
+/// subcommands. This allows tests to abstract out running commands.
+/// RealCommandRunner is an implementation that actually runs commands.
+struct CommandRunner {
+ virtual ~CommandRunner() {}
+ virtual bool CanRunMore() = 0;
+ virtual bool StartCommand(Edge* edge) = 0;
+
+ /// The result of waiting for a command.
+ struct Result {
+ Result() : edge(NULL) {}
+ Edge* edge;
+ ExitStatus status;
+ string output;
+ bool success() const { return status == ExitSuccess; }
+ };
+ /// Wait for a command to complete, or return false if interrupted.
+ virtual bool WaitForCommand(Result* result) = 0;
+
+ virtual vector<Edge*> GetActiveEdges() { return vector<Edge*>(); }
+ virtual void Abort() {}
+};
+
+/// Options (e.g. verbosity, parallelism) passed to a build.
+struct BuildConfig {
+ BuildConfig() : verbosity(NORMAL), dry_run(false), parallelism(1),
+ failures_allowed(1), max_load_average(-0.0f) {}
+
+ enum Verbosity {
+ NORMAL,
+ QUIET, // No output -- used when testing.
+ VERBOSE
+ };
+ Verbosity verbosity;
+ bool dry_run;
+ int parallelism;
+ int failures_allowed;
+ /// The maximum load average we must not exceed. A negative value
+ /// means that we do not have any limit.
+ double max_load_average;
+};
+
+/// Builder wraps the build process: starting commands, updating status.
+struct Builder {
+ Builder(State* state, const BuildConfig& config,
+ BuildLog* build_log, DepsLog* deps_log,
+ DiskInterface* disk_interface);
+ ~Builder();
+
+ /// Clean up after interrupted commands by deleting output files.
+ void Cleanup();
+
+ Node* AddTarget(const string& name, string* err);
+
+ /// Add a target to the build, scanning dependencies.
+ /// @return false on error.
+ bool AddTarget(Node* target, string* err);
+
+ /// Returns true if the build targets are already up to date.
+ bool AlreadyUpToDate() const;
+
+ /// Run the build. Returns false on error.
+ /// It is an error to call this function when AlreadyUpToDate() is true.
+ bool Build(string* err);
+
+ bool StartEdge(Edge* edge, string* err);
+ void FinishCommand(CommandRunner::Result* result);
+
+ /// Used for tests.
+ void SetBuildLog(BuildLog* log) {
+ scan_.set_build_log(log);
+ }
+
+ State* state_;
+ const BuildConfig& config_;
+ Plan plan_;
+ auto_ptr<CommandRunner> command_runner_;
+ BuildStatus* status_;
+
+ private:
+ bool ExtractDeps(CommandRunner::Result* result, const string& deps_type,
+ vector<Node*>* deps_nodes, string* err);
+
+ DiskInterface* disk_interface_;
+ DependencyScan scan_;
+
+ // Unimplemented copy ctor and operator= ensure we don't copy the auto_ptr.
+ Builder(const Builder &other); // DO NOT IMPLEMENT
+ void operator=(const Builder &other); // DO NOT IMPLEMENT
+};
+
+/// Tracks the status of a build: completion fraction, printing updates.
+struct BuildStatus {
+ explicit BuildStatus(const BuildConfig& config);
+ void PlanHasTotalEdges(int total);
+ void BuildEdgeStarted(Edge* edge);
+ void BuildEdgeFinished(Edge* edge, bool success, const string& output,
+ int* start_time, int* end_time);
+ void BuildFinished();
+
+ /// Format the progress status string by replacing the placeholders.
+ /// See the user manual for more information about the available
+ /// placeholders.
+ /// @param progress_status_format The format of the progress status.
+ string FormatProgressStatus(const char* progress_status_format) const;
+
+ private:
+ void PrintStatus(Edge* edge);
+
+ const BuildConfig& config_;
+
+ /// Time the build started.
+ int64_t start_time_millis_;
+
+ int started_edges_, finished_edges_, total_edges_;
+
+ /// Map of running edge to time the edge started running.
+ typedef map<Edge*, int> RunningEdgeMap;
+ RunningEdgeMap running_edges_;
+
+ /// Prints progress output.
+ LinePrinter printer_;
+
+ /// The custom progress status format to use.
+ const char* progress_status_format_;
+
+ template<size_t S>
+ void snprinfRate(double rate, char(&buf)[S], const char* format) const {
+ if (rate == -1) snprintf(buf, S, "?");
+ else snprintf(buf, S, format, rate);
+ }
+
+ struct RateInfo {
+ RateInfo() : rate_(-1) {}
+
+ void Restart() { stopwatch_.Restart(); }
+ double Elapsed() const { return stopwatch_.Elapsed(); }
+ double rate() { return rate_; }
+
+ void UpdateRate(int edges) {
+ if (edges && stopwatch_.Elapsed())
+ rate_ = edges / stopwatch_.Elapsed();
+ }
+
+ private:
+ double rate_;
+ Stopwatch stopwatch_;
+ };
+
+ struct SlidingRateInfo {
+ SlidingRateInfo(int n) : rate_(-1), N(n), last_update_(-1) {}
+
+ void Restart() { stopwatch_.Restart(); }
+ double rate() { return rate_; }
+
+ void UpdateRate(int update_hint) {
+ if (update_hint == last_update_)
+ return;
+ last_update_ = update_hint;
+
+ if (times_.size() == N)
+ times_.pop();
+ times_.push(stopwatch_.Elapsed());
+ if (times_.back() != times_.front())
+ rate_ = times_.size() / (times_.back() - times_.front());
+ }
+
+ private:
+ double rate_;
+ Stopwatch stopwatch_;
+ const size_t N;
+ queue<double> times_;
+ int last_update_;
+ };
+
+ mutable RateInfo overall_rate_;
+ mutable SlidingRateInfo current_rate_;
+};
+
+#endif // NINJA_BUILD_H_