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

     1  // Copyright 2015 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  #include "dyndep.h"
    16  
    17  #include <assert.h>
    18  #include <stdio.h>
    19  
    20  #include "debug_flags.h"
    21  #include "disk_interface.h"
    22  #include "dyndep_parser.h"
    23  #include "graph.h"
    24  #include "state.h"
    25  #include "util.h"
    26  
    27  using namespace std;
    28  
    29  bool DyndepLoader::LoadDyndeps(Node* node, std::string* err) const {
    30    DyndepFile ddf;
    31    return LoadDyndeps(node, &ddf, err);
    32  }
    33  
    34  bool DyndepLoader::LoadDyndeps(Node* node, DyndepFile* ddf,
    35                                 std::string* err) const {
    36    // We are loading the dyndep file now so it is no longer pending.
    37    node->set_dyndep_pending(false);
    38  
    39    // Load the dyndep information from the file.
    40    EXPLAIN("loading dyndep file '%s'", node->path().c_str());
    41    if (!LoadDyndepFile(node, ddf, err))
    42      return false;
    43  
    44    // Update each edge that specified this node as its dyndep binding.
    45    std::vector<Edge*> const& out_edges = node->out_edges();
    46    for (std::vector<Edge*>::const_iterator oe = out_edges.begin();
    47         oe != out_edges.end(); ++oe) {
    48      Edge* const edge = *oe;
    49      if (edge->dyndep_ != node)
    50        continue;
    51  
    52      DyndepFile::iterator ddi = ddf->find(edge);
    53      if (ddi == ddf->end()) {
    54        *err = ("'" + edge->outputs_[0]->path() + "' "
    55                "not mentioned in its dyndep file "
    56                "'" + node->path() + "'");
    57        return false;
    58      }
    59  
    60      ddi->second.used_ = true;
    61      Dyndeps const& dyndeps = ddi->second;
    62      if (!UpdateEdge(edge, &dyndeps, err)) {
    63        return false;
    64      }
    65    }
    66  
    67    // Reject extra outputs in dyndep file.
    68    for (DyndepFile::const_iterator oe = ddf->begin(); oe != ddf->end();
    69         ++oe) {
    70      if (!oe->second.used_) {
    71        Edge* const edge = oe->first;
    72        *err = ("dyndep file '" + node->path() + "' mentions output "
    73                "'" + edge->outputs_[0]->path() + "' whose build statement "
    74                "does not have a dyndep binding for the file");
    75        return false;
    76      }
    77    }
    78  
    79    return true;
    80  }
    81  
    82  bool DyndepLoader::UpdateEdge(Edge* edge, Dyndeps const* dyndeps,
    83                                std::string* err) const {
    84    // Add dyndep-discovered bindings to the edge.
    85    // We know the edge already has its own binding
    86    // scope because it has a "dyndep" binding.
    87    if (dyndeps->restat_)
    88      edge->env_->AddBinding("restat", "1");
    89  
    90    // Add the dyndep-discovered outputs to the edge.
    91    edge->outputs_.insert(edge->outputs_.end(),
    92                          dyndeps->implicit_outputs_.begin(),
    93                          dyndeps->implicit_outputs_.end());
    94    edge->implicit_outs_ += dyndeps->implicit_outputs_.size();
    95  
    96    // Add this edge as incoming to each new output.
    97    for (std::vector<Node*>::const_iterator i =
    98             dyndeps->implicit_outputs_.begin();
    99         i != dyndeps->implicit_outputs_.end(); ++i) {
   100      if (Edge* old_in_edge = (*i)->in_edge()) {
   101        // This node already has an edge producing it.  Fail with an error
   102        // unless the edge was generated by ImplicitDepLoader, in which
   103        // case we can replace it with the now-known real producer.
   104        if (!old_in_edge->generated_by_dep_loader_) {
   105          *err = "multiple rules generate " + (*i)->path();
   106          return false;
   107        }
   108        old_in_edge->outputs_.clear();
   109      }
   110      (*i)->set_in_edge(edge);
   111    }
   112  
   113    // Add the dyndep-discovered inputs to the edge.
   114    edge->inputs_.insert(edge->inputs_.end() - edge->order_only_deps_,
   115                         dyndeps->implicit_inputs_.begin(),
   116                         dyndeps->implicit_inputs_.end());
   117    edge->implicit_deps_ += dyndeps->implicit_inputs_.size();
   118  
   119    // Add this edge as outgoing from each new input.
   120    for (std::vector<Node*>::const_iterator i =
   121             dyndeps->implicit_inputs_.begin();
   122         i != dyndeps->implicit_inputs_.end(); ++i)
   123      (*i)->AddOutEdge(edge);
   124  
   125    return true;
   126  }
   127  
   128  bool DyndepLoader::LoadDyndepFile(Node* file, DyndepFile* ddf,
   129                                    std::string* err) const {
   130    DyndepParser parser(state_, disk_interface_, ddf);
   131    return parser.Load(file->path(), err);
   132  }