diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-08 03:31:41 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-08 03:31:41 +0000 |
commit | 8863034cfb657b02b76889ef3e9470ff34c31af1 (patch) | |
tree | bb3ebd2cf181f276d1aeac9483e4f7ea97b5a699 | |
parent | 97a86efe130f4221e7329ec12856c6dea4ae3f1b (diff) | |
parent | 89a026243359a42eac9e8cab5b3ba9f6a54c3ed4 (diff) | |
download | kati-8863034cfb657b02b76889ef3e9470ff34c31af1.tar.gz |
Snap for 10084189 from 89a026243359a42eac9e8cab5b3ba9f6a54c3ed4 to build-tools-release
Change-Id: If8fd17cc5fd2367236bb17415304d2c42a5f1402
-rw-r--r-- | Makefile.ckati | 1 | ||||
-rw-r--r-- | src/Android.bp | 12 | ||||
-rw-r--r-- | src/eval.cc | 2 | ||||
-rw-r--r-- | src/file_cache.cc | 38 | ||||
-rw-r--r-- | src/file_cache.h | 15 | ||||
-rw-r--r-- | src/func.cc | 50 | ||||
-rw-r--r-- | src/main.cc | 15 | ||||
-rw-r--r-- | src/parser.cc | 89 | ||||
-rw-r--r-- | src/parser.h | 6 | ||||
-rw-r--r-- | src/regen.cc | 4 | ||||
-rw-r--r-- | src/regen_dump.cc | 29 | ||||
-rw-r--r-- | src/regen_dump.h | 22 | ||||
-rw-r--r-- | testcase/ninja_regen_extra_file_deps.sh | 63 | ||||
-rw-r--r-- | testcase/ninja_regen_extra_file_deps_error_on_missing_file.sh | 35 | ||||
-rw-r--r-- | testcase/ninja_shell_no_rerun.sh | 55 | ||||
-rw-r--r-- | testcase/ninja_shell_no_rerun_error_in_rule.sh | 39 |
16 files changed, 364 insertions, 111 deletions
diff --git a/Makefile.ckati b/Makefile.ckati index 322d747..05cdc0d 100644 --- a/Makefile.ckati +++ b/Makefile.ckati @@ -40,6 +40,7 @@ KATI_CXX_SRCS := \ ninja.cc \ parser.cc \ regen.cc \ + regen_dump.cc \ rule.cc \ stats.cc \ stmt.cc \ diff --git a/src/Android.bp b/src/Android.bp index c56ab34..f0723f9 100644 --- a/src/Android.bp +++ b/src/Android.bp @@ -64,7 +64,10 @@ cc_library_host_static { cc_binary_host { name: "ckati", defaults: ["ckati_defaults"], - srcs: ["main.cc"], + srcs: [ + "main.cc", + "regen_dump.cc", + ], whole_static_libs: ["libckati"], target: { linux_glibc: { @@ -73,13 +76,6 @@ cc_binary_host { }, } -cc_binary_host { - name: "ckati_stamp_dump", - defaults: ["ckati_defaults"], - srcs: ["regen_dump.cc"], - static_libs: ["libckati"], -} - cc_test_host { name: "ckati_test", defaults: ["ckati_defaults"], diff --git a/src/eval.cc b/src/eval.cc index aacb871..3393586 100644 --- a/src/eval.cc +++ b/src/eval.cc @@ -553,7 +553,7 @@ void Evaluator::EvalCommand(const CommandStmt* stmt) { if (!last_rule_) { std::vector<Stmt*> stmts; - ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts); + ParseNoStats(stmt->orig, stmt->loc(), &stmts); for (Stmt* a : stmts) a->Eval(this); return; diff --git a/src/file_cache.cc b/src/file_cache.cc index d0b4ea5..465c45a 100644 --- a/src/file_cache.cc +++ b/src/file_cache.cc @@ -19,30 +19,28 @@ #include "file.h" #include "file_cache.h" -MakefileCacheManager::MakefileCacheManager() = default; - -MakefileCacheManager::~MakefileCacheManager() = default; - -class MakefileCacheManagerImpl : public MakefileCacheManager { - public: - virtual const Makefile& ReadMakefile(const std::string& filename) override { - auto iter = cache_.find(filename); - if (iter != cache_.end()) { - return iter->second; - } - return (cache_.emplace(filename, filename).first)->second; +const Makefile& MakefileCacheManager::ReadMakefile( + const std::string& filename) { + auto iter = cache_.find(filename); + if (iter != cache_.end()) { + return iter->second; } + return (cache_.emplace(filename, filename).first)->second; +} - virtual void GetAllFilenames(std::unordered_set<std::string>* out) override { - for (const auto& p : cache_) - out->insert(p.first); - } +void MakefileCacheManager::GetAllFilenames( + std::unordered_set<std::string>* out) { + for (const auto& p : cache_) + out->insert(p.first); + for (const auto& f : extra_file_deps_) + out->insert(f); +} - private: - std::unordered_map<std::string, Makefile> cache_; -}; +void MakefileCacheManager::AddExtraFileDep(std::string_view dep) { + extra_file_deps_.emplace(dep); +} MakefileCacheManager& MakefileCacheManager::Get() { - static MakefileCacheManagerImpl instance; + static MakefileCacheManager instance; return instance; } diff --git a/src/file_cache.h b/src/file_cache.h index ce1cd9c..ce3be6a 100644 --- a/src/file_cache.h +++ b/src/file_cache.h @@ -22,15 +22,18 @@ class Makefile; class MakefileCacheManager { public: - virtual ~MakefileCacheManager(); - - virtual const Makefile& ReadMakefile(const std::string& filename) = 0; - virtual void GetAllFilenames(std::unordered_set<std::string>* out) = 0; + const Makefile& ReadMakefile(const std::string& filename); + void GetAllFilenames(std::unordered_set<std::string>* out); + void AddExtraFileDep(std::string_view dep); static MakefileCacheManager& Get(); - protected: - MakefileCacheManager(); + private: + MakefileCacheManager() = default; + MakefileCacheManager(const MakefileCacheManager&) = delete; + MakefileCacheManager(MakefileCacheManager&&) = delete; + std::unordered_map<std::string, Makefile> cache_; + std::unordered_set<std::string> extra_file_deps_; }; #endif // FILE_CACHE_H_ diff --git a/src/func.cc b/src/func.cc index 2345808..316e423 100644 --- a/src/func.cc +++ b/src/func.cc @@ -30,6 +30,7 @@ #include <unordered_map> #include "eval.h" +#include "file_cache.h" #include "fileutil.h" #include "find.h" #include "loc.h" @@ -608,8 +609,8 @@ void ShellFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) { return; } - const std::string&& shell = ev->GetShell(); - const std::string&& shellflag = ev->GetShellFlag(); + std::string shell = ev->GetShell(); + std::string shellflag = ev->GetShellFlag(); std::string out; FindCommand* fc = NULL; @@ -629,6 +630,32 @@ void ShellFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) { ShellStatusVar::SetValue(returnCode); } +void ShellFuncNoRerun(const std::vector<Value*>& args, + Evaluator* ev, + std::string* s) { + std::string cmd = args[0]->Eval(ev); + if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) { + // In the regular ShellFunc, if it sees a $(shell) inside of a rule when in + // ninja mode, the shell command will just be written to the ninja file + // instead of run directly by kati. So it already has the benefits of not + // rerunning every time kati is invoked. + ERROR_LOC(ev->loc(), + "KATI_shell_no_rerun provides no benefit over regular $(shell) " + "inside of a rule.", + cmd.c_str()); + return; + } + + std::string shell = ev->GetShell(); + std::string shellflag = ev->GetShellFlag(); + + std::string out; + FindCommand* fc = NULL; + int returnCode = ShellFuncImpl(shell, shellflag, cmd, ev->loc(), &out, &fc); + *s += out; + ShellStatusVar::SetValue(returnCode); +} + void CallFunc(const std::vector<Value*>& args, Evaluator* ev, std::string* s) { static const Symbol tmpvar_names[] = { Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"), @@ -1008,6 +1035,22 @@ void VariableLocationFunc(const std::vector<Value*>& args, } } +void ExtraFileDepsFunc(const std::vector<Value*>& args, + Evaluator* ev, + std::string*) { + for (auto arg : args) { + std::string files = arg->Eval(ev); + for (std::string_view file : WordScanner(files)) { + if (!Exists(file)) { + std::string errorMsg = "*** file does not exist: "; + errorMsg += file; + ev->Error(errorMsg); + } + MakefileCacheManager::Get().AddExtraFileDep(file); + } + } +} + #define ENTRY(name, args...) \ { \ name, { name, args } \ @@ -1066,6 +1109,9 @@ static const std::unordered_map<std::string_view, FuncInfo> g_func_info_map = { ENTRY("KATI_profile_makefile", &ProfileFunc, 0, 0, false, false), ENTRY("KATI_variable_location", &VariableLocationFunc, 1, 1, false, false), + + ENTRY("KATI_extra_file_deps", &ExtraFileDepsFunc, 0, 0, false, false), + ENTRY("KATI_shell_no_rerun", &ShellFuncNoRerun, 1, 1, false, false), }; } // namespace diff --git a/src/main.cc b/src/main.cc index a32d013..f6dcc7c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -37,6 +37,7 @@ #include "ninja.h" #include "parser.h" #include "regen.h" +#include "regen_dump.h" #include "stats.h" #include "stmt.h" #include "stringprintf.h" @@ -354,9 +355,17 @@ static void HandleRealpath(int argc, char** argv) { } int main(int argc, char* argv[]) { - if (argc >= 2 && !strcmp(argv[1], "--realpath")) { - HandleRealpath(argc - 2, argv + 2); - return 0; + if (argc >= 2) { + if (!strcmp(argv[1], "--realpath")) { + HandleRealpath(argc - 2, argv + 2); + return 0; + } else if (!strcmp(argv[1], "--dump_stamp_tool")) { + // Unfortunately, this can easily be confused with --dump_kati_stamp, + // which prints debug info about the stamp while executing a normal kati + // run. This tool flag only dumps information, and doesn't run the rest of + // kati. + return stamp_dump_main(argc, argv); + } } std::string orig_args; for (int i = 0; i < argc; i++) { diff --git a/src/parser.cc b/src/parser.cc index 11da3c7..5f2016d 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -28,12 +28,6 @@ #include "stmt.h" #include "strutil.h" -enum struct ParserState { - NOT_AFTER_RULE = 0, - AFTER_RULE, - MAYBE_AFTER_RULE, -}; - class Parser { struct IfState { IfStmt* stmt; @@ -48,20 +42,15 @@ class Parser { public: Parser(std::string_view buf, const char* filename, std::vector<Stmt*>* stmts) : buf_(buf), - state_(ParserState::NOT_AFTER_RULE), stmts_(stmts), out_stmts_(stmts), - num_define_nest_(0), - num_if_nest_(0), loc_(filename, 0), fixed_lineno_(false) {} Parser(std::string_view buf, const Loc& loc, std::vector<Stmt*>* stmts) : buf_(buf), - state_(ParserState::NOT_AFTER_RULE), stmts_(stmts), out_stmts_(stmts), - num_if_nest_(0), loc_(loc), fixed_lineno_(true) {} @@ -93,8 +82,6 @@ class Parser { "*** missing `endef', unterminated `define'."); } - void set_state(ParserState st) { state_ = st; } - static std::vector<ParseErrorStmt*> parse_errors; private: @@ -127,7 +114,7 @@ class Parser { current_directive_ = AssignDirective::NONE; - if (line[0] == '\t' && state_ != ParserState::NOT_AFTER_RULE) { + if (line[0] == '\t' && after_rule_) { CommandStmt* stmt = new CommandStmt(); stmt->set_loc(loc_); Loc mutable_loc(loc_); @@ -184,7 +171,6 @@ class Parser { return; } - const bool is_rule = sep != std::string::npos && line[sep] == ':'; RuleStmt* rule_stmt = new RuleStmt(); rule_stmt->set_loc(loc_); @@ -216,7 +202,7 @@ class Parser { rule_stmt->rhs = NULL; } out_stmts_->push_back(rule_stmt); - state_ = is_rule ? ParserState::AFTER_RULE : ParserState::MAYBE_AFTER_RULE; + after_rule_ = true; } void ParseAssign(std::string_view line, size_t separator_pos) { @@ -249,7 +235,7 @@ class Parser { stmt->directive = current_directive_; stmt->is_final = is_final; out_stmts_->push_back(stmt); - state_ = ParserState::NOT_AFTER_RULE; + after_rule_ = false; } void ParseInclude(std::string_view line, std::string_view directive) { @@ -259,7 +245,7 @@ class Parser { stmt->expr = ParseExpr(&mutable_loc, line); stmt->should_exist = directive[0] == 'i'; out_stmts_->push_back(stmt); - state_ = ParserState::NOT_AFTER_RULE; + after_rule_ = false; } void ParseDefine(std::string_view line, std::string_view) { @@ -271,7 +257,7 @@ class Parser { num_define_nest_ = 1; define_start_ = 0; define_start_line_ = loc_.lineno; - state_ = ParserState::NOT_AFTER_RULE; + after_rule_ = false; } void ParseInsideDefine(std::string_view line) { @@ -310,10 +296,10 @@ class Parser { } void EnterIf(IfStmt* stmt) { - IfState* st = new IfState(); - st->stmt = stmt; - st->is_in_else = false; - st->num_nest = num_if_nest_; + IfState st; + st.stmt = stmt; + st.is_in_else = false; + st.num_nest = num_if_nest_; if_stack_.push(st); out_stmts_ = &stmt->true_stmts; } @@ -390,19 +376,19 @@ class Parser { void ParseElse(std::string_view line, std::string_view) { if (!CheckIfStack("else")) return; - IfState* st = if_stack_.top(); - if (st->is_in_else) { + IfState& st = if_stack_.top(); + if (st.is_in_else) { Error("*** only one `else' per conditional."); return; } - st->is_in_else = true; - out_stmts_ = &st->stmt->false_stmts; + st.is_in_else = true; + out_stmts_ = &st.stmt->false_stmts; std::string_view next_if = TrimLeftSpace(line); if (next_if.empty()) return; - num_if_nest_ = st->num_nest + 1; + num_if_nest_ = st.num_nest + 1; if (!HandleDirective(next_if, else_if_directives_)) { WARN_LOC(loc_, "extraneous text after `else' directive"); } @@ -416,19 +402,18 @@ class Parser { Error("extraneous text after `endif` directive"); return; } - IfState st = *if_stack_.top(); - for (int t = 0; t <= st.num_nest; t++) { - delete if_stack_.top(); + int num_nest = if_stack_.top().num_nest; + for (int i = 0; i <= num_nest; i++) { if_stack_.pop(); - if (if_stack_.empty()) { - out_stmts_ = stmts_; - } else { - IfState* st = if_stack_.top(); - if (st->is_in_else) - out_stmts_ = &st->stmt->false_stmts; - else - out_stmts_ = &st->stmt->true_stmts; - } + } + if (if_stack_.empty()) { + out_stmts_ = stmts_; + } else { + const IfState& st = if_stack_.top(); + if (st.is_in_else) + out_stmts_ = &st.stmt->false_stmts; + else + out_stmts_ = &st.stmt->true_stmts; } } @@ -509,21 +494,24 @@ class Parser { std::string_view buf_; size_t l_; - ParserState state_; + // Represents if we just parsed a rule or an expression. + // Expressions are included because they can expand into + // a rule, see testcase/rule_in_var.mk. + bool after_rule_ = false; std::vector<Stmt*>* stmts_; std::vector<Stmt*>* out_stmts_; std::string_view define_name_; - int num_define_nest_; + int num_define_nest_ = 0; size_t define_start_; int define_start_line_; std::string_view orig_line_with_directives_; AssignDirective current_directive_; - int num_if_nest_; - std::stack<IfState*> if_stack_; + int num_if_nest_ = 0; + std::stack<IfState> if_stack_; Loc loc_; bool fixed_lineno_; @@ -537,8 +525,7 @@ class Parser { void Parse(Makefile* mk) { COLLECT_STATS("parse file time"); - Parser parser(std::string_view(mk->buf()), mk->filename().c_str(), - mk->mutable_stmts()); + Parser parser(mk->buf(), mk->filename().c_str(), mk->mutable_stmts()); parser.Parse(); } @@ -546,15 +533,13 @@ void Parse(std::string_view buf, const Loc& loc, std::vector<Stmt*>* out_stmts) { COLLECT_STATS("parse eval time"); - Parser parser(buf, loc, out_stmts); - parser.Parse(); + ParseNoStats(buf, loc, out_stmts); } -void ParseNotAfterRule(std::string_view buf, - const Loc& loc, - std::vector<Stmt*>* out_stmts) { +void ParseNoStats(std::string_view buf, + const Loc& loc, + std::vector<Stmt*>* out_stmts) { Parser parser(buf, loc, out_stmts); - parser.set_state(ParserState::NOT_AFTER_RULE); parser.Parse(); } diff --git a/src/parser.h b/src/parser.h index d0457d2..21673b3 100644 --- a/src/parser.h +++ b/src/parser.h @@ -25,9 +25,9 @@ class Makefile; void Parse(Makefile* mk); void Parse(std::string_view buf, const Loc& loc, std::vector<Stmt*>* out_asts); -void ParseNotAfterRule(std::string_view buf, - const Loc& loc, - std::vector<Stmt*>* out_asts); +void ParseNoStats(std::string_view buf, + const Loc& loc, + std::vector<Stmt*>* out_asts); void ParseAssignStatement(std::string_view line, size_t sep, diff --git a/src/regen.cc b/src/regen.cc index 458c4cd..c583556 100644 --- a/src/regen.cc +++ b/src/regen.cc @@ -161,7 +161,9 @@ class StampChecker { for (int i = 0; i < num_files; i++) { LOAD_STRING(fp, &s); double ts = GetTimestamp(s); - if (gen_time < ts) { + // GetTimestamp returns < 0 when there's an error reading the file, like + // when its been removed. + if (gen_time < ts || ts < 0) { if (g_flags.regen_ignoring_kati_binary) { if (s == GetExecutablePath()) { fprintf(stderr, "%s was modified, ignored.\n", s.c_str()); diff --git a/src/regen_dump.cc b/src/regen_dump.cc index 70034dc..bea1296 100644 --- a/src/regen_dump.cc +++ b/src/regen_dump.cc @@ -29,9 +29,7 @@ #include "log.h" #include "strutil.h" -using namespace std; - -vector<std::string> LoadVecString(FILE* fp) { +std::vector<std::string> LoadVecString(FILE* fp) { int count = LoadInt(fp); if (count < 0) { ERROR("Incomplete stamp file"); @@ -45,21 +43,22 @@ vector<std::string> LoadVecString(FILE* fp) { return ret; } -int main(int argc, char* argv[]) { +int stamp_dump_main(int argc, char* argv[]) { bool dump_files = false; bool dump_env = false; bool dump_globs = false; bool dump_cmds = false; bool dump_finds = false; - if (argc == 1) { - fprintf(stderr, - "Usage: ckati_stamp_dump [--env] [--files] [--globs] [--cmds] " - "[--finds] <stamp>\n"); + if (argc <= 2) { + fprintf( + stderr, + "Usage: ckati --dump_stamp_tool [--env] [--files] [--globs] [--cmds] " + "[--finds] <stamp>\n"); return 1; } - for (int i = 1; i < argc - 1; i++) { + for (int i = 2; i < argc - 1; i++) { const char* arg = argv[i]; if (!strcmp(arg, "--env")) { dump_env = true; @@ -72,7 +71,7 @@ int main(int argc, char* argv[]) { } else if (!strcmp(arg, "--finds")) { dump_finds = true; } else { - fprintf(stderr, "Unknown option: %s", arg); + fprintf(stderr, "Unknown option: %s\n", arg); return 1; } } @@ -83,7 +82,7 @@ int main(int argc, char* argv[]) { FILE* fp = fopen(argv[argc - 1], "rb"); if (!fp) - PERROR("fopen"); + PERROR(argv[argc - 1]); ScopedFile sfp(fp); double gen_time; @@ -117,8 +116,8 @@ int main(int argc, char* argv[]) { if (num_envs < 0) ERROR("Incomplete stamp file"); for (int i = 0; i < num_envs; i++) { - string name; - string val; + std::string name; + std::string val; if (!LoadString(fp, &name)) ERROR("Incomplete stamp file"); if (!LoadString(fp, &val)) @@ -131,7 +130,7 @@ int main(int argc, char* argv[]) { if (num_globs < 0) ERROR("Incomplete stamp file"); for (int i = 0; i < num_globs; i++) { - string pat; + std::string pat; if (!LoadString(fp, &pat)) ERROR("Incomplete stamp file"); @@ -150,7 +149,7 @@ int main(int argc, char* argv[]) { ERROR("Incomplete stamp file"); for (int i = 0; i < num_cmds; i++) { CommandOp op = static_cast<CommandOp>(LoadInt(fp)); - string shell, shellflag, cmd, result, file; + std::string shell, shellflag, cmd, result, file; if (!LoadString(fp, &shell)) ERROR("Incomplete stamp file"); if (!LoadString(fp, &shellflag)) diff --git a/src/regen_dump.h b/src/regen_dump.h new file mode 100644 index 0000000..c5b4ee5 --- /dev/null +++ b/src/regen_dump.h @@ -0,0 +1,22 @@ +// Copyright 2016 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 REGEN_DUMP_H_ +#define REGEN_DUMP_H_ + +#include <string> + +int stamp_dump_main(int argc, char* argv[]); + +#endif // REGEN_DUMP_H_ diff --git a/testcase/ninja_regen_extra_file_deps.sh b/testcase/ninja_regen_extra_file_deps.sh new file mode 100644 index 0000000..de21994 --- /dev/null +++ b/testcase/ninja_regen_extra_file_deps.sh @@ -0,0 +1,63 @@ +#!/bin/sh +# +# Copyright 2023 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. + +set -eu + +log=stderr_log +mk="$@" + +touch a.txt b.txt + +cat <<EOF > Makefile +EXTRA_DEPS := a.txt b.txt +\$(KATI_extra_file_deps \$(EXTRA_DEPS)) +all: + echo foo +EOF + +${mk} 2> ${log} +if [ -e ninja.sh ]; then + ./ninja.sh +fi + +${mk} 2> ${log} +if [ -e ninja.sh ]; then + if grep -q regenerating ${log}; then + echo 'Should not be regenerated' + fi + ./ninja.sh +fi + +touch a.txt + +${mk} 2> ${log} +if [ -e ninja.sh ]; then + if ! grep -q regenerating ${log}; then + echo 'Should have regenerated due to touched file' + fi + ./ninja.sh +fi + +rm a.txt + +# Ignore the error about a.txt missing on this run, we only care that kati tried to regenerate +${mk} 2> ${log} || true +if [ -e ninja.sh ]; then + if ! grep -q regenerating ${log}; then + echo 'Should have regenerated due to removed file' + fi + ./ninja.sh +fi diff --git a/testcase/ninja_regen_extra_file_deps_error_on_missing_file.sh b/testcase/ninja_regen_extra_file_deps_error_on_missing_file.sh new file mode 100644 index 0000000..b8e566a --- /dev/null +++ b/testcase/ninja_regen_extra_file_deps_error_on_missing_file.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Copyright 2023 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. + +set -eu + +log=stderr_log +mk="$@" + +cat <<EOF > Makefile +\$(KATI_extra_file_deps a.txt) +all: + echo foo +EOF + +${mk} 2> ${log} || true +if echo "${mk}" | grep -q kati; then + if grep -q "file does not exist: a.txt" ${log}; then + echo 'foo' + else + echo 'Expected a missing file error message' + fi +fi diff --git a/testcase/ninja_shell_no_rerun.sh b/testcase/ninja_shell_no_rerun.sh new file mode 100644 index 0000000..3b5fd7a --- /dev/null +++ b/testcase/ninja_shell_no_rerun.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Copyright 2023 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. + +set -eu + +log=stderr_log +mk="$@" + +echo foo > a.txt + +if echo "${mk}" | grep -q kati; then + cat <<EOF > Makefile +RESULT := \$(KATI_shell_no_rerun cat a.txt) +all: + echo \$(RESULT) +EOF +else + cat <<EOF > Makefile +RESULT := \$(shell cat a.txt) +all: + echo \$(RESULT) +EOF +fi + +${mk} 2> ${log} +if [ -e ninja.sh ]; then + ./ninja.sh +fi + +# Only change the file for kati so that make matches kati's broken output of printing foo 2 times. +# ("broken" because the user forgot to add a.txt to $(KATI_extra_file_deps)) +if echo "${mk}" | grep -q kati; then +echo bar > a.txt +fi + +${mk} 2> ${log} +if [ -e ninja.sh ]; then + if grep -q regenerating ${log}; then + echo 'Should not be regenerated' + fi + ./ninja.sh +fi diff --git a/testcase/ninja_shell_no_rerun_error_in_rule.sh b/testcase/ninja_shell_no_rerun_error_in_rule.sh new file mode 100644 index 0000000..a59c360 --- /dev/null +++ b/testcase/ninja_shell_no_rerun_error_in_rule.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# Copyright 2023 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. + +set -eu + +log=stderr_log +mk="$@" + +echo foo > a.txt + +if echo "${mk}" | grep -q kati; then + cat <<EOF > Makefile +all: + echo \$(KATI_shell_no_rerun echo foo) +EOF +else + cat <<EOF > Makefile +all: + echo foo +EOF +fi + +${mk} 2> ${log} || true +if grep -q "KATI_shell_no_rerun provides no benefit over regular \$(shell) inside of a rule" ${log}; then + echo foo +fi |