[C++] ninja: Add $SHELL support
Ninja always executes commands with /bin/sh, which causes problems
on Darwin where the builtin echo does not support the -n argument.
Use $SHELL -c "cmd" or $SHELL out.rsp to run commands through the
shell selected by the makefiles.
diff --git a/ninja.cc b/ninja.cc
index 47aad7e..5e009a3 100644
--- a/ninja.cc
+++ b/ninja.cc
@@ -158,6 +158,7 @@
NinjaGenerator(const char* ninja_suffix, Evaluator* ev)
: ce_(ev), ev_(ev), fp_(NULL), rule_id_(0) {
ev_->set_avoid_io(true);
+ shell_ = ev->EvalVar(kShellSym);
if (g_goma_dir)
gomacc_ = StringPrintf("%s/gomacc ", g_goma_dir);
if (ninja_suffix) {
@@ -406,9 +407,9 @@
if (cmd_buf_.size() > 100 * 1000) {
fprintf(fp_, " rspfile = $out.rsp\n");
fprintf(fp_, " rspfile_content = %s\n", cmd_buf_.c_str());
- fprintf(fp_, " command = sh $out.rsp\n");
+ fprintf(fp_, " command = %s $out.rsp\n", shell_->c_str());
} else {
- fprintf(fp_, " command = %s\n", cmd_buf_.c_str());
+ fprintf(fp_, " command = %s -c \"%s\"\n", shell_->c_str(), EscapeShell(cmd_buf_).c_str());
}
}
@@ -442,6 +443,37 @@
return r;
}
+ string EscapeShell(string s) {
+ if (s.find_first_of("$`!\\\"") == string::npos)
+ return s;
+ string r;
+ bool lastDollar = false;
+ for (char c : s) {
+ switch (c) {
+ case '$':
+ if (lastDollar) {
+ r += c;
+ lastDollar = false;
+ } else {
+ r += '\\';
+ r += c;
+ lastDollar = true;
+ }
+ break;
+ case '`':
+ case '"':
+ case '!':
+ case '\\':
+ r += '\\';
+ // fall through.
+ default:
+ r += c;
+ lastDollar = false;
+ }
+ }
+ return r;
+ }
+
void EmitBuild(DepNode* node, const string& rule_name) {
fprintf(fp_, "build %s: %s",
EscapeBuildTarget(node->output).c_str(),
@@ -548,6 +580,7 @@
string gomacc_;
string ninja_suffix_;
unordered_map<Symbol, Symbol> short_names_;
+ shared_ptr<string> shell_;
};
void GenerateNinja(const char* ninja_suffix,