diff options
author | Delilah Hoare <delilah@dhoare.me> | 2022-03-10 23:24:53 +1100 |
---|---|---|
committer | Cole Faust <colecfaust@gmail.com> | 2022-11-28 12:42:27 -0800 |
commit | d521068b030be1a6b2df61149a06d5f6bcda399e (patch) | |
tree | c0e7ee8c27cac5873d2b4fb439f78ae20149b4d0 | |
parent | a4f36671fe86d5f535a26047f275b5f356c5e6e6 (diff) | |
download | kati-d521068b030be1a6b2df61149a06d5f6bcda399e.tar.gz |
Implement $? for ninja
-rw-r--r-- | src/command.cc | 48 | ||||
-rw-r--r-- | src/command.h | 3 | ||||
-rw-r--r-- | src/eval.h | 9 | ||||
-rw-r--r-- | src/newer.cc | 53 | ||||
-rw-r--r-- | src/ninja.cc | 2 |
5 files changed, 101 insertions, 14 deletions
diff --git a/src/command.cc b/src/command.cc index 41393ab..ca8a86e 100644 --- a/src/command.cc +++ b/src/command.cc @@ -127,14 +127,34 @@ void AutoStarVar::Eval(Evaluator*, string* s) const { pat.Stem(n->output.str()).AppendToString(s); } -void AutoQuestionVar::Eval(Evaluator*, string* s) const { +void AutoQuestionVar::Eval(Evaluator* ev, string* s) const { unordered_set<StringPiece> seen; - WordWriter ww(s); - double target_age = GetTimestamp(ce_->current_dep_node()->output.str()); - for (Symbol ai : ce_->current_dep_node()->actual_inputs) { - if (seen.insert(ai.str()).second - && GetTimestamp(ai.str()) > target_age) { + + if (ev->avoid_io()) { + // Postpone checking timestamps to the start of rule execution using + // the helper application `ckati-newer'. + *s += "$KATI_NEW_INPUTS"; + if (ev->env_vars().find("KATI_NEW_INPUTS") == ev->env_vars().end()) { + string def; + + WordWriter ww(&def); + ww.Write("$(ckati-newer"); + ww.Write(ce_->current_dep_node()->output.str()); + for (Symbol ai : ce_->current_dep_node()->actual_inputs) { + if (seen.insert(ai.str()).second) { + ww.Write(ai.str()); + } + } + def += ")"; + ev->set_env_var("KATI_NEW_INPUTS", def); + } + } else { + WordWriter ww(s); + double target_age = GetTimestamp(ce_->current_dep_node()->output.str()); + for (Symbol ai : ce_->current_dep_node()->actual_inputs) { + if (seen.insert(ai.str()).second && GetTimestamp(ai.str()) > target_age) { ww.Write(ai.str()); + } } } } @@ -193,11 +213,7 @@ CommandEvaluator::CommandEvaluator(Evaluator* ev) : ev_(ev) { INSERT_AUTO_VAR(AutoHatVar, "^"); INSERT_AUTO_VAR(AutoPlusVar, "+"); INSERT_AUTO_VAR(AutoStarVar, "*"); - if (!g_flags.generate_ninja) { - INSERT_AUTO_VAR(AutoQuestionVar, "?"); - } else { - INSERT_AUTO_VAR(AutoNotImplementedVar, "?"); - } + INSERT_AUTO_VAR(AutoQuestionVar, "?"); // TODO: Implement them. INSERT_AUTO_VAR(AutoNotImplementedVar, "%"); INSERT_AUTO_VAR(AutoNotImplementedVar, "|"); @@ -242,8 +258,15 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) { continue; } - if (!ev_->delayed_output_commands().empty()) { + if (!ev_->delayed_output_commands().empty() || !ev_->env_vars().empty()) { std::vector<Command> output_commands; + for (auto& var : ev_->env_vars()) { + Command& c = output_commands.emplace_back(n.output); + c.cmd = var.first + "=" + var.second + " && export " + var.first; + c.echo = false; + c.ignore_error = false; + c.updates_environment = true; + } for (const string& cmd : ev_->delayed_output_commands()) { Command& c = output_commands.emplace_back(n.output); c.cmd = cmd; @@ -254,6 +277,7 @@ std::vector<Command> CommandEvaluator::Eval(const DepNode& n) { result.swap(output_commands); copy(output_commands.begin(), output_commands.end(), back_inserter(result)); ev_->clear_delayed_output_commands(); + ev_->clear_env_vars(); } ev_->set_current_scope(NULL); diff --git a/src/command.h b/src/command.h index 017f6bb..215502f 100644 --- a/src/command.h +++ b/src/command.h @@ -25,11 +25,12 @@ struct DepNode; class Evaluator; struct Command { - explicit Command(Symbol o) : output(o), echo(true), ignore_error(false) {} + explicit Command(Symbol o) : output(o), echo(true), ignore_error(false), updates_environment(false) {} Symbol output; string cmd; bool echo; bool ignore_error; + bool updates_environment; }; class CommandEvaluator { @@ -173,6 +173,14 @@ class Evaluator { } void clear_delayed_output_commands() { delayed_output_commands_.clear(); } + const unordered_map<string, string>& env_vars() const { + return env_vars_; + } + void set_env_var(const string& name, const string& value) { + env_vars_.insert_or_assign(name, value); + } + void clear_env_vars() { env_vars_.clear(); } + static const SymbolSet& used_undefined_vars() { return used_undefined_vars_; } int eval_depth() const { return eval_depth_; } @@ -270,6 +278,7 @@ class Evaluator { // Commands which should run at ninja-time (i.e., info, warning, and // error). vector<string> delayed_output_commands_; + unordered_map<string, string> env_vars_; Symbol posix_sym_; bool is_posix_; diff --git a/src/newer.cc b/src/newer.cc new file mode 100644 index 0000000..ef3f535 --- /dev/null +++ b/src/newer.cc @@ -0,0 +1,53 @@ +// Copyright 2022 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 + +// This is the only source file for ckati-newer, a helper utility +// invoked by generated Ninja files to evaluate `$?`. + +#include <stdbool.h> +#include <stdio.h> +#include <sys/stat.h> + +double GetTimestamp(const char* filename) { + struct stat st; + if (stat(filename, &st) < 0) { + return -2.0; + } +#if defined(__linux__) + return st.st_mtime + st.st_mtim.tv_nsec * 0.001 * 0.001 * 0.001; +#else + return st.st_mtime; +#endif +} + +int main(int argc, const char* argv[]) { + if (argc < 2) { + return 1; + } + double target_age = GetTimestamp(argv[1]); + bool first = true; + for (int i = 2; i < argc; i++) { + if (GetTimestamp(argv[i]) > target_age) { + if (first) { + first = false; + } else { + putchar(' '); + } + puts(argv[i]); + } + } + return 0; +} diff --git a/src/ninja.cc b/src/ninja.cc index ee4a87f..aa6a08f 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -414,7 +414,7 @@ class NinjaGenerator { while (isspace(*in)) in++; - bool needs_subshell = (command_count > 1 || c.ignore_error); + bool needs_subshell = (command_count > 1 || c.ignore_error) && !c.updates_environment; if (needs_subshell) *cmd_buf += '('; |