Home | History | Annotate | Download | only in kati
      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 // +build ignore
     16 
     17 #include "exec.h"
     18 
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 
     22 #include <memory>
     23 #include <unordered_map>
     24 #include <utility>
     25 #include <vector>
     26 
     27 #include "command.h"
     28 #include "dep.h"
     29 #include "eval.h"
     30 #include "expr.h"
     31 #include "fileutil.h"
     32 #include "flags.h"
     33 #include "log.h"
     34 #include "string_piece.h"
     35 #include "strutil.h"
     36 #include "symtab.h"
     37 #include "var.h"
     38 
     39 namespace {
     40 
     41 const double kNotExist = -2.0;
     42 const double kProcessing = -1.0;
     43 
     44 class Executor {
     45  public:
     46   explicit Executor(Evaluator* ev)
     47       : ce_(ev),
     48         num_commands_(0) {
     49     shell_ = ev->GetShell();
     50     shellflag_ = ev->GetShellFlag();
     51   }
     52 
     53   double ExecNode(DepNode* n, DepNode* needed_by) {
     54     auto found = done_.find(n->output);
     55     if (found != done_.end()) {
     56       if (found->second == kProcessing) {
     57         WARN("Circular %s <- %s dependency dropped.",
     58              needed_by ? needed_by->output.c_str() : "(null)",
     59              n->output.c_str());
     60       }
     61       return found->second;
     62     }
     63     done_[n->output] = kProcessing;
     64     double output_ts = GetTimestamp(n->output.c_str());
     65 
     66     LOG("ExecNode: %s for %s",
     67         n->output.c_str(),
     68         needed_by ? needed_by->output.c_str() : "(null)");
     69 
     70     if (!n->has_rule && output_ts == kNotExist && !n->is_phony) {
     71       if (needed_by) {
     72         ERROR("*** No rule to make target '%s', needed by '%s'.",
     73               n->output.c_str(), needed_by->output.c_str());
     74       } else {
     75         ERROR("*** No rule to make target '%s'.", n->output.c_str());
     76       }
     77     }
     78 
     79     double latest = kProcessing;
     80     for (DepNode* d : n->order_onlys) {
     81       if (Exists(d->output.str())) {
     82         continue;
     83       }
     84       double ts = ExecNode(d, n);
     85       if (latest < ts)
     86         latest = ts;
     87     }
     88 
     89     for (DepNode* d : n->deps) {
     90       double ts = ExecNode(d, n);
     91       if (latest < ts)
     92         latest = ts;
     93     }
     94 
     95     if (output_ts >= latest && !n->is_phony) {
     96       done_[n->output] = output_ts;
     97       return output_ts;
     98     }
     99 
    100     vector<Command*> commands;
    101     ce_.Eval(n, &commands);
    102     for (Command* command : commands) {
    103       num_commands_ += 1;
    104       if (command->echo) {
    105         printf("%s\n", command->cmd.c_str());
    106         fflush(stdout);
    107       }
    108       if (!g_flags.is_dry_run) {
    109         string out;
    110         int result = RunCommand(shell_, shellflag_,
    111                                 command->cmd.c_str(),
    112                                 RedirectStderr::STDOUT,
    113                                 &out);
    114         printf("%s", out.c_str());
    115         if (result != 0) {
    116           if (command->ignore_error) {
    117             fprintf(stderr, "[%s] Error %d (ignored)\n",
    118                     command->output.c_str(), WEXITSTATUS(result));
    119           } else {
    120             fprintf(stderr, "*** [%s] Error %d\n",
    121                     command->output.c_str(), WEXITSTATUS(result));
    122             exit(1);
    123           }
    124         }
    125       }
    126       delete command;
    127     }
    128 
    129     done_[n->output] = output_ts;
    130     return output_ts;
    131   }
    132 
    133   uint64_t Count() {
    134     return num_commands_;
    135   }
    136 
    137  private:
    138   CommandEvaluator ce_;
    139   unordered_map<Symbol, double> done_;
    140   string shell_;
    141   string shellflag_;
    142   uint64_t num_commands_;
    143 };
    144 
    145 }  // namespace
    146 
    147 void Exec(const vector<DepNode*>& roots, Evaluator* ev) {
    148   unique_ptr<Executor> executor(new Executor(ev));
    149   for (DepNode* root : roots) {
    150     executor->ExecNode(root, NULL);
    151   }
    152   if (executor->Count() == 0) {
    153     for (DepNode* root : roots) {
    154       printf("kati: Nothing to be done for `%s'.\n", root->output.c_str());
    155     }
    156   }
    157 }
    158