[C++] Split CommandEvaluator from Executor
This is the first step of --ninja support
diff --git a/Makefile b/Makefile
index 46d7730..bb91bf2 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@
GO_SRCS:=$(wildcard *.go)
CXX_SRCS:= \
ast.cc \
+ command.cc \
dep.cc \
eval.cc \
exec.cc \
@@ -24,6 +25,7 @@
flags.cc \
func.cc \
main.cc \
+ ninja.cc \
parser.cc \
rule.cc \
string_piece.cc \
diff --git a/command.cc b/command.cc
new file mode 100644
index 0000000..39aa9fc
--- /dev/null
+++ b/command.cc
@@ -0,0 +1,214 @@
+// Copyright 2015 Google Inc. All rights reserved
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build ignore
+
+#include "command.h"
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "dep.h"
+#include "eval.h"
+#include "log.h"
+#include "strutil.h"
+#include "var.h"
+
+namespace {
+
+class AutoVar : public Var {
+ public:
+ virtual const char* Flavor() const override {
+ return "undefined";
+ }
+ virtual VarOrigin Origin() const override {
+ return VarOrigin::AUTOMATIC;
+ }
+
+ virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
+
+ virtual StringPiece String() const override {
+ ERROR("$(value %s) is not implemented yet", sym_);
+ return "";
+ }
+
+ virtual string DebugString() const override {
+ return string("AutoVar(") + sym_ + ")";
+ }
+
+ protected:
+ AutoVar(CommandEvaluator* ce, const char* sym) : ce_(ce), sym_(sym) {}
+ virtual ~AutoVar() = default;
+
+ CommandEvaluator* ce_;
+ const char* sym_;
+};
+
+#define DECLARE_AUTO_VAR_CLASS(name) \
+ class name : public AutoVar { \
+ public: \
+ name(CommandEvaluator* ce, const char* sym) \
+ : AutoVar(ce, sym) {} \
+ virtual ~name() = default; \
+ virtual void Eval(Evaluator* ev, string* s) const override; \
+ }
+
+DECLARE_AUTO_VAR_CLASS(AutoAtVar);
+DECLARE_AUTO_VAR_CLASS(AutoLessVar);
+DECLARE_AUTO_VAR_CLASS(AutoHatVar);
+DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
+DECLARE_AUTO_VAR_CLASS(AutoStarVar);
+
+class AutoSuffixDVar : public AutoVar {
+ public:
+ AutoSuffixDVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
+ : AutoVar(ce, sym), wrapped_(wrapped) {
+ }
+ virtual ~AutoSuffixDVar() = default;
+ virtual void Eval(Evaluator* ev, string* s) const override;
+
+ private:
+ Var* wrapped_;
+};
+
+class AutoSuffixFVar : public AutoVar {
+ public:
+ AutoSuffixFVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
+ : AutoVar(ce, sym), wrapped_(wrapped) {}
+ virtual ~AutoSuffixFVar() = default;
+ virtual void Eval(Evaluator* ev, string* s) const override;
+
+ private:
+ Var* wrapped_;
+};
+
+void AutoAtVar::Eval(Evaluator*, string* s) const {
+ AppendString(ce_->current_dep_node()->output, s);
+}
+
+void AutoLessVar::Eval(Evaluator*, string* s) const {
+ auto& ai = ce_->current_dep_node()->actual_inputs;
+ if (!ai.empty())
+ AppendString(ai[0], s);
+}
+
+void AutoHatVar::Eval(Evaluator*, string* s) const {
+ unordered_set<StringPiece> seen;
+ WordWriter ww(s);
+ for (StringPiece ai : ce_->current_dep_node()->actual_inputs) {
+ if (seen.insert(ai).second)
+ ww.Write(ai);
+ }
+}
+
+void AutoPlusVar::Eval(Evaluator*, string* s) const {
+ WordWriter ww(s);
+ for (StringPiece ai : ce_->current_dep_node()->actual_inputs) {
+ ww.Write(ai);
+ }
+}
+
+void AutoStarVar::Eval(Evaluator*, string* s) const {
+ AppendString(StripExt(ce_->current_dep_node()->output), s);
+}
+
+void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const {
+ string buf;
+ wrapped_->Eval(ev, &buf);
+ WordWriter ww(s);
+ for (StringPiece tok : WordScanner(buf)) {
+ ww.Write(Dirname(tok));
+ }
+}
+
+void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const {
+ string buf;
+ wrapped_->Eval(ev, &buf);
+ WordWriter ww(s);
+ for (StringPiece tok : WordScanner(buf)) {
+ ww.Write(Basename(tok));
+ }
+}
+
+void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) {
+ *s = TrimLeftSpace(*s);
+ while (true) {
+ char c = s->get(0);
+ if (c == '@') {
+ *echo = false;
+ } else if (c == '-') {
+ *ignore_error = true;
+ } else {
+ break;
+ }
+ *s = TrimLeftSpace(s->substr(1));
+ }
+}
+
+} // namespace
+
+CommandEvaluator::CommandEvaluator(Evaluator* ev)
+ : ev_(ev) {
+ Vars* vars = ev_->mutable_vars();
+#define INSERT_AUTO_VAR(name, sym) do { \
+ Var* v = new name(this, sym); \
+ (*vars)[STRING_PIECE(sym)] = v; \
+ (*vars)[STRING_PIECE(sym"D")] = new AutoSuffixDVar(this, sym"D", v); \
+ (*vars)[STRING_PIECE(sym"F")] = new AutoSuffixFVar(this, sym"F", v); \
+ } while (0)
+ INSERT_AUTO_VAR(AutoAtVar, "@");
+ INSERT_AUTO_VAR(AutoLessVar, "<");
+ INSERT_AUTO_VAR(AutoHatVar, "^");
+ INSERT_AUTO_VAR(AutoPlusVar, "+");
+ INSERT_AUTO_VAR(AutoStarVar, "*");
+}
+
+void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) {
+ ev_->set_current_scope(n->rule_vars);
+ current_dep_node_ = n;
+ for (Value* v : n->cmds) {
+ shared_ptr<string> cmds_buf = v->Eval(ev_);
+ StringPiece cmds = *cmds_buf;
+ bool global_echo = true;
+ bool global_ignore_error = false;
+ ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
+ if (cmds == "")
+ continue;
+ while (true) {
+ size_t lf_cnt;
+ size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
+ if (index == cmds.size())
+ index = string::npos;
+ StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
+ cmds = cmds.substr(index + 1);
+
+ bool echo = global_echo;
+ bool ignore_error = global_ignore_error;
+ ParseCommandPrefixes(&cmd, &echo, &ignore_error);
+
+ if (!cmd.empty()) {
+ Command* command = new Command;
+ command->output = n->output;
+ command->cmd = make_shared<string>(cmd.as_string());
+ command->echo = echo;
+ command->ignore_error = ignore_error;
+ commands->push_back(command);
+ }
+ if (index == string::npos)
+ break;
+ }
+ continue;
+ }
+ ev_->set_current_scope(NULL);
+}
diff --git a/command.h b/command.h
new file mode 100644
index 0000000..f06533f
--- /dev/null
+++ b/command.h
@@ -0,0 +1,50 @@
+// Copyright 2015 Google Inc. All rights reserved
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COMMAND_H_
+#define COMMAND_H_
+
+#include <memory>
+#include <vector>
+
+#include "string_piece.h"
+
+using namespace std;
+
+struct DepNode;
+class Evaluator;
+
+struct Command {
+ Command()
+ : echo(true), ignore_error(false) {
+ }
+ StringPiece output;
+ shared_ptr<string> cmd;
+ bool echo;
+ bool ignore_error;
+ //StringPiece shell;
+};
+
+class CommandEvaluator {
+ public:
+ explicit CommandEvaluator(Evaluator* ev);
+ void Eval(DepNode* n, vector<Command*>* commands);
+ const DepNode* current_dep_node() const { return current_dep_node_; }
+
+ private:
+ Evaluator* ev_;
+ DepNode* current_dep_node_;
+};
+
+#endif // COMMAND_H_
diff --git a/exec.cc b/exec.cc
index 9e6b1ab..69cf4ea 100644
--- a/exec.cc
+++ b/exec.cc
@@ -21,10 +21,10 @@
#include <memory>
#include <unordered_map>
-#include <unordered_set>
#include <utility>
#include <vector>
+#include "command.h"
#include "dep.h"
#include "eval.h"
#include "fileutil.h"
@@ -37,101 +37,10 @@
namespace {
-class Executor;
-
-class AutoVar : public Var {
- public:
- virtual const char* Flavor() const override {
- return "undefined";
- }
- virtual VarOrigin Origin() const override {
- return VarOrigin::AUTOMATIC;
- }
-
- virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
-
- virtual StringPiece String() const override {
- ERROR("$(value %s) is not implemented yet", sym_);
- return "";
- }
-
- virtual string DebugString() const override {
- return string("AutoVar(") + sym_ + ")";
- }
-
- protected:
- AutoVar(Executor* ex, const char* sym) : ex_(ex), sym_(sym) {}
- virtual ~AutoVar() = default;
-
- Executor* ex_;
- const char* sym_;
-};
-
-#define DECLARE_AUTO_VAR_CLASS(name) \
- class name : public AutoVar { \
- public: \
- name(Executor* ex, const char* sym) \
- : AutoVar(ex, sym) {} \
- virtual ~name() = default; \
- virtual void Eval(Evaluator* ev, string* s) const override; \
- }
-
-DECLARE_AUTO_VAR_CLASS(AutoAtVar);
-DECLARE_AUTO_VAR_CLASS(AutoLessVar);
-DECLARE_AUTO_VAR_CLASS(AutoHatVar);
-DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
-DECLARE_AUTO_VAR_CLASS(AutoStarVar);
-
-class AutoSuffixDVar : public AutoVar {
- public:
- AutoSuffixDVar(Executor* ex, const char* sym, Var* wrapped)
- : AutoVar(ex, sym), wrapped_(wrapped) {
- }
- virtual ~AutoSuffixDVar() = default;
- virtual void Eval(Evaluator* ev, string* s) const override;
-
- private:
- Var* wrapped_;
-};
-
-class AutoSuffixFVar : public AutoVar {
- public:
- AutoSuffixFVar(Executor* ex, const char* sym, Var* wrapped)
- : AutoVar(ex, sym), wrapped_(wrapped) {}
- virtual ~AutoSuffixFVar() = default;
- virtual void Eval(Evaluator* ev, string* s) const override;
-
- private:
- Var* wrapped_;
-};
-
-struct Runner {
- Runner()
- : echo(true), ignore_error(false) {
- }
- StringPiece output;
- shared_ptr<string> cmd;
- bool echo;
- bool ignore_error;
- //StringPiece shell;
-};
-
class Executor {
public:
explicit Executor(Evaluator* ev)
- : ev_(ev) {
- Vars* vars = ev_->mutable_vars();
-#define INSERT_AUTO_VAR(name, sym) do { \
- Var* v = new name(this, sym); \
- (*vars)[STRING_PIECE(sym)] = v; \
- (*vars)[STRING_PIECE(sym"D")] = new AutoSuffixDVar(this, sym"D", v); \
- (*vars)[STRING_PIECE(sym"F")] = new AutoSuffixFVar(this, sym"F", v); \
- } while (0)
- INSERT_AUTO_VAR(AutoAtVar, "@");
- INSERT_AUTO_VAR(AutoLessVar, "<");
- INSERT_AUTO_VAR(AutoHatVar, "^");
- INSERT_AUTO_VAR(AutoPlusVar, "+");
- INSERT_AUTO_VAR(AutoStarVar, "*");
+ : ce_(ev) {
}
void ExecNode(DepNode* n, DepNode* needed_by) {
@@ -154,141 +63,35 @@
ExecNode(d, n);
}
- vector<Runner*> runners;
- CreateRunners(n, &runners);
- for (Runner* runner : runners) {
- if (runner->echo) {
- printf("%s\n", runner->cmd->c_str());
+ vector<Command*> commands;
+ ce_.Eval(n, &commands);
+ for (Command* command : commands) {
+ if (command->echo) {
+ printf("%s\n", command->cmd->c_str());
fflush(stdout);
}
if (!g_is_dry_run) {
- int result = system(runner->cmd->c_str());
+ int result = system(command->cmd->c_str());
if (result != 0) {
- if (runner->ignore_error) {
+ if (command->ignore_error) {
fprintf(stderr, "[%.*s] Error %d (ignored)\n",
- SPF(runner->output), WEXITSTATUS(result));
+ SPF(command->output), WEXITSTATUS(result));
} else {
fprintf(stderr, "*** [%.*s] Error %d\n",
- SPF(runner->output), WEXITSTATUS(result));
+ SPF(command->output), WEXITSTATUS(result));
exit(1);
}
}
}
- delete runner;
+ delete command;
}
}
- void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) {
- *s = TrimLeftSpace(*s);
- while (true) {
- char c = s->get(0);
- if (c == '@') {
- *echo = false;
- } else if (c == '-') {
- *ignore_error = true;
- } else {
- break;
- }
- *s = TrimLeftSpace(s->substr(1));
- }
- }
-
- void CreateRunners(DepNode* n, vector<Runner*>* runners) {
- ev_->set_current_scope(n->rule_vars);
- current_dep_node_ = n;
- for (Value* v : n->cmds) {
- shared_ptr<string> cmds_buf = v->Eval(ev_);
- StringPiece cmds = *cmds_buf;
- bool global_echo = true;
- bool global_ignore_error = false;
- ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
- if (cmds == "")
- continue;
- while (true) {
- size_t lf_cnt;
- size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
- if (index == cmds.size())
- index = string::npos;
- StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
- cmds = cmds.substr(index + 1);
-
- bool echo = global_echo;
- bool ignore_error = global_ignore_error;
- ParseCommandPrefixes(&cmd, &echo, &ignore_error);
-
- if (!cmd.empty()) {
- Runner* runner = new Runner;
- runner->output = n->output;
- runner->cmd = make_shared<string>(cmd.as_string());
- runner->echo = echo;
- runner->ignore_error = ignore_error;
- runners->push_back(runner);
- }
- if (index == string::npos)
- break;
- }
- continue;
- }
- ev_->set_current_scope(NULL);
- }
-
- const DepNode* current_dep_node() const { return current_dep_node_; }
-
private:
- Vars* vars_;
- Evaluator* ev_;
+ CommandEvaluator ce_;
unordered_map<StringPiece, bool> done_;
- DepNode* current_dep_node_;
};
-void AutoAtVar::Eval(Evaluator*, string* s) const {
- AppendString(ex_->current_dep_node()->output, s);
-}
-
-void AutoLessVar::Eval(Evaluator*, string* s) const {
- auto& ai = ex_->current_dep_node()->actual_inputs;
- if (!ai.empty())
- AppendString(ai[0], s);
-}
-
-void AutoHatVar::Eval(Evaluator*, string* s) const {
- unordered_set<StringPiece> seen;
- WordWriter ww(s);
- for (StringPiece ai : ex_->current_dep_node()->actual_inputs) {
- if (seen.insert(ai).second)
- ww.Write(ai);
- }
-}
-
-void AutoPlusVar::Eval(Evaluator*, string* s) const {
- WordWriter ww(s);
- for (StringPiece ai : ex_->current_dep_node()->actual_inputs) {
- ww.Write(ai);
- }
-}
-
-void AutoStarVar::Eval(Evaluator*, string* s) const {
- AppendString(StripExt(ex_->current_dep_node()->output), s);
-}
-
-void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const {
- string buf;
- wrapped_->Eval(ev, &buf);
- WordWriter ww(s);
- for (StringPiece tok : WordScanner(buf)) {
- ww.Write(Dirname(tok));
- }
-}
-
-void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const {
- string buf;
- wrapped_->Eval(ev, &buf);
- WordWriter ww(s);
- for (StringPiece tok : WordScanner(buf)) {
- ww.Write(Basename(tok));
- }
-}
-
} // namespace
void Exec(const vector<DepNode*>& roots, Evaluator* ev) {
diff --git a/main.cc b/main.cc
index 314df7e..4392f2a 100644
--- a/main.cc
+++ b/main.cc
@@ -29,6 +29,7 @@
#include "flags.h"
#include "func.h"
#include "log.h"
+#include "ninja.h"
#include "parser.h"
#include "string_piece.h"
#include "stringprintf.h"
@@ -38,6 +39,7 @@
static const char* g_makefile;
static bool g_is_syntax_check_only;
+static bool g_generate_ninja;
static void ParseCommandLine(int argc, char* argv[],
vector<StringPiece>* targets,
@@ -52,6 +54,8 @@
g_is_dry_run = true;
} else if (!strcmp(arg, "--kati_stats")) {
g_enable_stat_logs = true;
+ } else if (!strcmp(arg, "--ninja")) {
+ g_generate_ninja = true;
} else if (arg[0] == '-') {
ERROR("Unknown flag: %s", arg);
} else {
@@ -194,6 +198,12 @@
if (g_is_syntax_check_only)
return 0;
+ if (g_generate_ninja) {
+ ScopedTimeReporter tr("generate ninja time");
+ GenerateNinja(nodes, ev);
+ return 0;
+ }
+
{
ScopedTimeReporter tr("exec time");
Exec(nodes, ev);
diff --git a/ninja.cc b/ninja.cc
new file mode 100644
index 0000000..a14e3f1
--- /dev/null
+++ b/ninja.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 Google Inc. All rights reserved
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build ignore
+
+#include "ninja.h"
+
+void GenerateNinja(const vector<DepNode*>& nodes, Evaluator* ev) {
+
+}
diff --git a/ninja.h b/ninja.h
new file mode 100644
index 0000000..74cad0d
--- /dev/null
+++ b/ninja.h
@@ -0,0 +1,27 @@
+// Copyright 2015 Google Inc. All rights reserved
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef NINJA_H_
+#define NINJA_H_
+
+#include <vector>
+
+using namespace std;
+
+class DepNode;
+class Evaluator;
+
+void GenerateNinja(const vector<DepNode*>& nodes, Evaluator* ev);
+
+#endif // NINJA_H_