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