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:
Executor(Evaluator * ev)46 explicit Executor(Evaluator* ev)
47 : ce_(ev),
48 num_commands_(0) {
49 shell_ = ev->GetShell();
50 shellflag_ = ev->GetShellFlag();
51 }
52
ExecNode(DepNode * n,DepNode * needed_by)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
Count()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
Exec(const vector<DepNode * > & roots,Evaluator * ev)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