blob: 32a859d18a4c18e8a4df2dbb7a13ee14b67856a5 [file] [log] [blame]
// 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_GRAPH_H_
#define NINJA_GRAPH_H_
#include <string>
#include <vector>
using namespace std;
#include "eval_env.h"
#include "timestamp.h"
struct DiskInterface;
struct Edge;
/// Information about a node in the dependency graph: the file, whether
/// it's dirty, mtime, etc.
struct Node {
explicit Node(const string& path)
: path_(path),
mtime_(-1),
dirty_(false),
in_edge_(NULL) {}
/// Return true if the file exists (mtime_ got a value).
bool Stat(DiskInterface* disk_interface);
/// Return true if we needed to stat.
bool StatIfNecessary(DiskInterface* disk_interface) {
if (status_known())
return false;
Stat(disk_interface);
return true;
}
/// Mark as not-yet-stat()ed and not dirty.
void ResetState() {
mtime_ = -1;
dirty_ = false;
}
/// Mark the Node as already-stat()ed and missing.
void MarkMissing() {
mtime_ = 0;
}
bool exists() const {
return mtime_ != 0;
}
bool status_known() const {
return mtime_ != -1;
}
const string& path() const { return path_; }
TimeStamp mtime() const { return mtime_; }
bool dirty() const { return dirty_; }
void set_dirty(bool dirty) { dirty_ = dirty; }
void MarkDirty() { dirty_ = true; }
Edge* in_edge() const { return in_edge_; }
void set_in_edge(Edge* edge) { in_edge_ = edge; }
const vector<Edge*>& out_edges() const { return out_edges_; }
void AddOutEdge(Edge* edge) { out_edges_.push_back(edge); }
private:
string path_;
/// Possible values of mtime_:
/// -1: file hasn't been examined
/// 0: we looked, and file doesn't exist
/// >0: actual file's mtime
TimeStamp mtime_;
/// Dirty is true when the underlying file is out-of-date.
/// But note that Edge::outputs_ready_ is also used in judging which
/// edges to build.
bool dirty_;
/// The Edge that produces this Node, or NULL when there is no
/// known edge to produce it.
Edge* in_edge_;
/// All Edges that use this Node as an input.
vector<Edge*> out_edges_;
};
/// An invokable build command and associated metadata (description, etc.).
struct Rule {
explicit Rule(const string& name)
: name_(name), generator_(false), restat_(false) {}
const string& name() const { return name_; }
bool generator() const { return generator_; }
bool restat() const { return restat_; }
const EvalString& command() const { return command_; }
EvalString& command() { return command_; }
const EvalString& description() const { return description_; }
const EvalString& depfile() const { return depfile_; }
const EvalString& rspfile() const { return rspfile_; }
const EvalString& rspfile_content() const { return rspfile_content_; }
private:
// Allow the parsers to reach into this object and fill out its fields.
friend struct ManifestParser;
string name_;
bool generator_;
bool restat_;
EvalString command_;
EvalString description_;
EvalString depfile_;
EvalString rspfile_;
EvalString rspfile_content_;
};
struct BuildLog;
struct Node;
struct State;
/// An edge in the dependency graph; links between Nodes using Rules.
struct Edge {
Edge() : rule_(NULL), env_(NULL), outputs_ready_(false), implicit_deps_(0),
order_only_deps_(0) {}
/// Examine inputs, outputs, and command lines to judge whether this edge
/// needs to be re-run, and update outputs_ready_ and each outputs' |dirty_|
/// state accordingly.
/// Returns false on failure.
bool RecomputeDirty(State* state, DiskInterface* disk_interface, string* err);
/// Recompute whether a given single output should be marked dirty.
/// Returns true if so.
bool RecomputeOutputDirty(BuildLog* build_log, TimeStamp most_recent_input,
Node* most_recent_node, const string& command,
Node* output);
/// Return true if all inputs' in-edges are ready.
bool AllInputsReady() const;
/// Expand all variables in a command and return it as a string.
/// If incl_rsp_file is enabled, the string will also contain the
/// full contents of a response file (if applicable)
string EvaluateCommand(bool incl_rsp_file = false); // XXX move to env, take env ptr
string EvaluateDepFile();
string GetDescription();
/// Does the edge use a response file?
bool HasRspFile();
/// Get the path to the response file
string GetRspFile();
/// Get the contents of the response file
string GetRspFileContent();
bool LoadDepFile(State* state, DiskInterface* disk_interface, string* err);
void Dump();
const Rule* rule_;
vector<Node*> inputs_;
vector<Node*> outputs_;
Env* env_;
bool outputs_ready_;
const Rule& rule() const { return *rule_; }
bool outputs_ready() const { return outputs_ready_; }
// XXX There are three types of inputs.
// 1) explicit deps, which show up as $in on the command line;
// 2) implicit deps, which the target depends on implicitly (e.g. C headers),
// and changes in them cause the target to rebuild;
// 3) order-only deps, which are needed before the target builds but which
// don't cause the target to rebuild.
// Currently we stuff all of these into inputs_ and keep counts of #2 and #3
// when we need to compute subsets. This is suboptimal; should think of a
// better representation. (Could make each pointer into a pair of a pointer
// and a type of input, or if memory matters could use the low bits of the
// pointer...)
int implicit_deps_;
int order_only_deps_;
bool is_implicit(int index) {
return index >= ((int)inputs_.size()) - order_only_deps_ - implicit_deps_ &&
!is_order_only(index);
}
bool is_order_only(int index) {
return index >= ((int)inputs_.size()) - order_only_deps_;
}
bool is_phony() const;
};
#endif // NINJA_GRAPH_H_