github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/src/graph.h (about)

     1  // Copyright 2011 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #ifndef NINJA_GRAPH_H_
    16  #define NINJA_GRAPH_H_
    17  
    18  #include <algorithm>
    19  #include <set>
    20  #include <string>
    21  #include <vector>
    22  
    23  #include "dyndep.h"
    24  #include "eval_env.h"
    25  #include "timestamp.h"
    26  #include "util.h"
    27  
    28  struct BuildLog;
    29  struct DepfileParserOptions;
    30  struct DiskInterface;
    31  struct DepsLog;
    32  struct Edge;
    33  struct Node;
    34  struct Pool;
    35  struct State;
    36  
    37  /// Information about a node in the dependency graph: the file, whether
    38  /// it's dirty, mtime, etc.
    39  struct Node {
    40    Node(const std::string& path, uint64_t slash_bits)
    41        : path_(path),
    42          slash_bits_(slash_bits),
    43          mtime_(-1),
    44          exists_(ExistenceStatusUnknown),
    45          dirty_(false),
    46          dyndep_pending_(false),
    47          in_edge_(NULL),
    48          id_(-1) {}
    49  
    50    /// Return false on error.
    51    bool Stat(DiskInterface* disk_interface, std::string* err);
    52  
    53    /// If the file doesn't exist, set the mtime_ from its dependencies
    54    void UpdatePhonyMtime(TimeStamp mtime);
    55  
    56    /// Return false on error.
    57    bool StatIfNecessary(DiskInterface* disk_interface, std::string* err) {
    58      if (status_known())
    59        return true;
    60      return Stat(disk_interface, err);
    61    }
    62  
    63    /// Mark as not-yet-stat()ed and not dirty.
    64    void ResetState() {
    65      mtime_ = -1;
    66      exists_ = ExistenceStatusUnknown;
    67      dirty_ = false;
    68    }
    69  
    70    /// Mark the Node as already-stat()ed and missing.
    71    void MarkMissing() {
    72      if (mtime_ == -1) {
    73        mtime_ = 0;
    74      }
    75      exists_ = ExistenceStatusMissing;
    76    }
    77  
    78    bool exists() const {
    79      return exists_ == ExistenceStatusExists;
    80    }
    81  
    82    bool status_known() const {
    83      return exists_ != ExistenceStatusUnknown;
    84    }
    85  
    86    const std::string& path() const { return path_; }
    87    /// Get |path()| but use slash_bits to convert back to original slash styles.
    88    std::string PathDecanonicalized() const {
    89      return PathDecanonicalized(path_, slash_bits_);
    90    }
    91    static std::string PathDecanonicalized(const std::string& path,
    92                                           uint64_t slash_bits);
    93    uint64_t slash_bits() const { return slash_bits_; }
    94  
    95    TimeStamp mtime() const { return mtime_; }
    96  
    97    bool dirty() const { return dirty_; }
    98    void set_dirty(bool dirty) { dirty_ = dirty; }
    99    void MarkDirty() { dirty_ = true; }
   100  
   101    bool dyndep_pending() const { return dyndep_pending_; }
   102    void set_dyndep_pending(bool pending) { dyndep_pending_ = pending; }
   103  
   104    Edge* in_edge() const { return in_edge_; }
   105    void set_in_edge(Edge* edge) { in_edge_ = edge; }
   106  
   107    int id() const { return id_; }
   108    void set_id(int id) { id_ = id; }
   109  
   110    const std::vector<Edge*>& out_edges() const { return out_edges_; }
   111    const std::vector<Edge*>& validation_out_edges() const { return validation_out_edges_; }
   112    void AddOutEdge(Edge* edge) { out_edges_.push_back(edge); }
   113    void AddValidationOutEdge(Edge* edge) { validation_out_edges_.push_back(edge); }
   114  
   115    void Dump(const char* prefix="") const;
   116  
   117  private:
   118    std::string path_;
   119  
   120    /// Set bits starting from lowest for backslashes that were normalized to
   121    /// forward slashes by CanonicalizePath. See |PathDecanonicalized|.
   122    uint64_t slash_bits_;
   123  
   124    /// Possible values of mtime_:
   125    ///   -1: file hasn't been examined
   126    ///   0:  we looked, and file doesn't exist
   127    ///   >0: actual file's mtime, or the latest mtime of its dependencies if it doesn't exist
   128    TimeStamp mtime_;
   129  
   130    enum ExistenceStatus {
   131      /// The file hasn't been examined.
   132      ExistenceStatusUnknown,
   133      /// The file doesn't exist. mtime_ will be the latest mtime of its dependencies.
   134      ExistenceStatusMissing,
   135      /// The path is an actual file. mtime_ will be the file's mtime.
   136      ExistenceStatusExists
   137    };
   138    ExistenceStatus exists_;
   139  
   140    /// Dirty is true when the underlying file is out-of-date.
   141    /// But note that Edge::outputs_ready_ is also used in judging which
   142    /// edges to build.
   143    bool dirty_;
   144  
   145    /// Store whether dyndep information is expected from this node but
   146    /// has not yet been loaded.
   147    bool dyndep_pending_;
   148  
   149    /// The Edge that produces this Node, or NULL when there is no
   150    /// known edge to produce it.
   151    Edge* in_edge_;
   152  
   153    /// All Edges that use this Node as an input.
   154    std::vector<Edge*> out_edges_;
   155  
   156    /// All Edges that use this Node as a validation.
   157    std::vector<Edge*> validation_out_edges_;
   158  
   159    /// A dense integer id for the node, assigned and used by DepsLog.
   160    int id_;
   161  };
   162  
   163  /// An edge in the dependency graph; links between Nodes using Rules.
   164  struct Edge {
   165    enum VisitMark {
   166      VisitNone,
   167      VisitInStack,
   168      VisitDone
   169    };
   170  
   171    Edge()
   172        : rule_(NULL), pool_(NULL), dyndep_(NULL), env_(NULL), mark_(VisitNone),
   173          id_(0), outputs_ready_(false), deps_loaded_(false),
   174          deps_missing_(false), generated_by_dep_loader_(false),
   175          implicit_deps_(0), order_only_deps_(0), implicit_outs_(0) {}
   176  
   177    /// Return true if all inputs' in-edges are ready.
   178    bool AllInputsReady() const;
   179  
   180    /// Expand all variables in a command and return it as a string.
   181    /// If incl_rsp_file is enabled, the string will also contain the
   182    /// full contents of a response file (if applicable)
   183    std::string EvaluateCommand(bool incl_rsp_file = false) const;
   184  
   185    /// Returns the shell-escaped value of |key|.
   186    std::string GetBinding(const std::string& key) const;
   187    bool GetBindingBool(const std::string& key) const;
   188  
   189    /// Like GetBinding("depfile"), but without shell escaping.
   190    std::string GetUnescapedDepfile() const;
   191    /// Like GetBinding("dyndep"), but without shell escaping.
   192    std::string GetUnescapedDyndep() const;
   193    /// Like GetBinding("rspfile"), but without shell escaping.
   194    std::string GetUnescapedRspfile() const;
   195  
   196    void Dump(const char* prefix="") const;
   197  
   198    const Rule* rule_;
   199    Pool* pool_;
   200    std::vector<Node*> inputs_;
   201    std::vector<Node*> outputs_;
   202    std::vector<Node*> validations_;
   203    Node* dyndep_;
   204    BindingEnv* env_;
   205    VisitMark mark_;
   206    size_t id_;
   207    bool outputs_ready_;
   208    bool deps_loaded_;
   209    bool deps_missing_;
   210    bool generated_by_dep_loader_;
   211  
   212    const Rule& rule() const { return *rule_; }
   213    Pool* pool() const { return pool_; }
   214    int weight() const { return 1; }
   215    bool outputs_ready() const { return outputs_ready_; }
   216  
   217    // There are three types of inputs.
   218    // 1) explicit deps, which show up as $in on the command line;
   219    // 2) implicit deps, which the target depends on implicitly (e.g. C headers),
   220    //                   and changes in them cause the target to rebuild;
   221    // 3) order-only deps, which are needed before the target builds but which
   222    //                     don't cause the target to rebuild.
   223    // These are stored in inputs_ in that order, and we keep counts of
   224    // #2 and #3 when we need to access the various subsets.
   225    int implicit_deps_;
   226    int order_only_deps_;
   227    bool is_implicit(size_t index) {
   228      return index >= inputs_.size() - order_only_deps_ - implicit_deps_ &&
   229          !is_order_only(index);
   230    }
   231    bool is_order_only(size_t index) {
   232      return index >= inputs_.size() - order_only_deps_;
   233    }
   234  
   235    // There are two types of outputs.
   236    // 1) explicit outs, which show up as $out on the command line;
   237    // 2) implicit outs, which the target generates but are not part of $out.
   238    // These are stored in outputs_ in that order, and we keep a count of
   239    // #2 to use when we need to access the various subsets.
   240    int implicit_outs_;
   241    bool is_implicit_out(size_t index) const {
   242      return index >= outputs_.size() - implicit_outs_;
   243    }
   244  
   245    bool is_phony() const;
   246    bool use_console() const;
   247    bool maybe_phonycycle_diagnostic() const;
   248  };
   249  
   250  struct EdgeCmp {
   251    bool operator()(const Edge* a, const Edge* b) const {
   252      return a->id_ < b->id_;
   253    }
   254  };
   255  
   256  typedef std::set<Edge*, EdgeCmp> EdgeSet;
   257  
   258  /// ImplicitDepLoader loads implicit dependencies, as referenced via the
   259  /// "depfile" attribute in build files.
   260  struct ImplicitDepLoader {
   261    ImplicitDepLoader(State* state, DepsLog* deps_log,
   262                      DiskInterface* disk_interface,
   263                      DepfileParserOptions const* depfile_parser_options)
   264        : state_(state), disk_interface_(disk_interface), deps_log_(deps_log),
   265          depfile_parser_options_(depfile_parser_options) {}
   266  
   267    /// Load implicit dependencies for \a edge.
   268    /// @return false on error (without filling \a err if info is just missing
   269    //                          or out of date).
   270    bool LoadDeps(Edge* edge, std::string* err);
   271  
   272    DepsLog* deps_log() const {
   273      return deps_log_;
   274    }
   275  
   276   protected:
   277    /// Process loaded implicit dependencies for \a edge and update the graph
   278    /// @return false on error (without filling \a err if info is just missing)
   279    virtual bool ProcessDepfileDeps(Edge* edge,
   280                                    std::vector<StringPiece>* depfile_ins,
   281                                    std::string* err);
   282  
   283    /// Load implicit dependencies for \a edge from a depfile attribute.
   284    /// @return false on error (without filling \a err if info is just missing).
   285    bool LoadDepFile(Edge* edge, const std::string& path, std::string* err);
   286  
   287    /// Load implicit dependencies for \a edge from the DepsLog.
   288    /// @return false on error (without filling \a err if info is just missing).
   289    bool LoadDepsFromLog(Edge* edge, std::string* err);
   290  
   291    /// Preallocate \a count spaces in the input array on \a edge, returning
   292    /// an iterator pointing at the first new space.
   293    std::vector<Node*>::iterator PreallocateSpace(Edge* edge, int count);
   294  
   295    /// If we don't have a edge that generates this input already,
   296    /// create one; this makes us not abort if the input is missing,
   297    /// but instead will rebuild in that circumstance.
   298    void CreatePhonyInEdge(Node* node);
   299  
   300    State* state_;
   301    DiskInterface* disk_interface_;
   302    DepsLog* deps_log_;
   303    DepfileParserOptions const* depfile_parser_options_;
   304  };
   305  
   306  
   307  /// DependencyScan manages the process of scanning the files in a graph
   308  /// and updating the dirty/outputs_ready state of all the nodes and edges.
   309  struct DependencyScan {
   310    DependencyScan(State* state, BuildLog* build_log, DepsLog* deps_log,
   311                   DiskInterface* disk_interface,
   312                   DepfileParserOptions const* depfile_parser_options)
   313        : build_log_(build_log),
   314          disk_interface_(disk_interface),
   315          dep_loader_(state, deps_log, disk_interface, depfile_parser_options),
   316          dyndep_loader_(state, disk_interface) {}
   317  
   318    /// Update the |dirty_| state of the given nodes by transitively inspecting
   319    /// their input edges.
   320    /// Examine inputs, outputs, and command lines to judge whether an edge
   321    /// needs to be re-run, and update outputs_ready_ and each outputs' |dirty_|
   322    /// state accordingly.
   323    /// Appends any validation nodes found to the nodes parameter.
   324    /// Returns false on failure.
   325    bool RecomputeDirty(Node* node, std::vector<Node*>* validation_nodes, std::string* err);
   326  
   327    /// Recompute whether any output of the edge is dirty, if so sets |*dirty|.
   328    /// Returns false on failure.
   329    bool RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
   330                               bool* dirty, std::string* err);
   331  
   332    BuildLog* build_log() const {
   333      return build_log_;
   334    }
   335    void set_build_log(BuildLog* log) {
   336      build_log_ = log;
   337    }
   338  
   339    DepsLog* deps_log() const {
   340      return dep_loader_.deps_log();
   341    }
   342  
   343    /// Load a dyndep file from the given node's path and update the
   344    /// build graph with the new information.  One overload accepts
   345    /// a caller-owned 'DyndepFile' object in which to store the
   346    /// information loaded from the dyndep file.
   347    bool LoadDyndeps(Node* node, std::string* err) const;
   348    bool LoadDyndeps(Node* node, DyndepFile* ddf, std::string* err) const;
   349  
   350   private:
   351    bool RecomputeNodeDirty(Node* node, std::vector<Node*>* stack,
   352                            std::vector<Node*>* validation_nodes, std::string* err);
   353    bool VerifyDAG(Node* node, std::vector<Node*>* stack, std::string* err);
   354  
   355    /// Recompute whether a given single output should be marked dirty.
   356    /// Returns true if so.
   357    bool RecomputeOutputDirty(const Edge* edge, const Node* most_recent_input,
   358                              const std::string& command, Node* output);
   359  
   360    BuildLog* build_log_;
   361    DiskInterface* disk_interface_;
   362    ImplicitDepLoader dep_loader_;
   363    DyndepLoader dyndep_loader_;
   364  };
   365  
   366  #endif  // NINJA_GRAPH_H_