Loading executor.cpp +29 −0 Changes for executor.cpp: 29 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -371,6 +371,23 @@ bool Executor::needs_rebuild(const std::string& target, const std::vector<std::s return false; } int Executor::execute_double_colon(const std::string& target, const std::map<std::string, std::string>& scope) { for (const auto& r : mf_.rules) { if (!r.double_colon) continue; if (std::find(r.targets.begin(), r.targets.end(), target) == r.targets.end()) continue; std::vector<std::string> prereqs; for (const auto& p : r.prerequisites) { for (auto& w : Parser::split_words(parser_.expand(p, mf_))) prereqs.push_back(resolve_vpath(Parser::normalize_target(w))); } if (!prereqs.empty() && !needs_rebuild(target, prereqs)) continue; int rc = execute_rule(target, &r, "", prereqs, scope); if (rc != 0) return rc; } return 0; } // ======================== Command Execution ======================== int Executor::run_command(const std::string& cmd, const std::vector<std::string>& extra_env) { Loading Loading @@ -700,6 +717,13 @@ int Executor::build_sequential(const std::string& target_in, } } if (rule->double_colon) { int rc = execute_double_colon(target, scope); if (rc == 0) rebuilt_.insert(target); visited_[target] = rc; return rc; } if (!needs_rebuild(target, prereqs)) { visited_[target] = 0; return 0; Loading Loading @@ -804,6 +828,11 @@ void Executor::worker_thread() { std::cerr << "makeplus: *** No rule to make target '" << target << "'. Stop." << std::endl; success = false; } } else if (node.rule->double_colon) { bool used_free = false; js_acquire(used_free); if (execute_double_colon(target, node.scope) != 0) success = false; js_release(used_free); } else { if (needs_rebuild(target, node.prereqs)) { // Hold a jobserver token for the duration of this recipe so the Loading executor.h +4 −0 Changes for executor.h: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -123,6 +123,10 @@ private: std::vector<std::string> expand_order_only(const std::string& target, const Rule* rule, const std::string& stem); bool needs_rebuild(const std::string& target, const std::vector<std::string>& prereqs); // Runs every double-colon rule of `target` in makefile order, each one // whose own prerequisites make it out of date (or that has none). int execute_double_colon(const std::string& target, const std::map<std::string, std::string>& scope); int execute_rule(const std::string& target, const Rule* rule, const std::string& stem, const std::vector<std::string>& prereqs, const std::map<std::string, std::string>& scope = {}); Loading parser.cpp +1 −0 Changes for parser.cpp: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1048,6 +1048,7 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren mf.rules.push_back({targets, prereqs, order_only, {}, is_pattern, ""}); current_rule = &mf.rules.back(); current_rule->double_colon = double_colon && !is_pattern; if (has_inline_recipe) { // GNU make: an inline recipe completes the rule; subsequent tab-indented Loading parser.h +3 −0 Changes for parser.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ struct Rule { // When set, targets are concrete but the stem is derived per target by // matching this pattern, and prerequisites contain '%' to substitute. std::string target_pattern; // "target :: prereqs": each double-colon rule of a target is // independent, with its own recipe run when its own prereqs require it. bool double_colon = false; }; struct Makefile { Loading Loading
executor.cpp +29 −0 Changes for executor.cpp: 29 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -371,6 +371,23 @@ bool Executor::needs_rebuild(const std::string& target, const std::vector<std::s return false; } int Executor::execute_double_colon(const std::string& target, const std::map<std::string, std::string>& scope) { for (const auto& r : mf_.rules) { if (!r.double_colon) continue; if (std::find(r.targets.begin(), r.targets.end(), target) == r.targets.end()) continue; std::vector<std::string> prereqs; for (const auto& p : r.prerequisites) { for (auto& w : Parser::split_words(parser_.expand(p, mf_))) prereqs.push_back(resolve_vpath(Parser::normalize_target(w))); } if (!prereqs.empty() && !needs_rebuild(target, prereqs)) continue; int rc = execute_rule(target, &r, "", prereqs, scope); if (rc != 0) return rc; } return 0; } // ======================== Command Execution ======================== int Executor::run_command(const std::string& cmd, const std::vector<std::string>& extra_env) { Loading Loading @@ -700,6 +717,13 @@ int Executor::build_sequential(const std::string& target_in, } } if (rule->double_colon) { int rc = execute_double_colon(target, scope); if (rc == 0) rebuilt_.insert(target); visited_[target] = rc; return rc; } if (!needs_rebuild(target, prereqs)) { visited_[target] = 0; return 0; Loading Loading @@ -804,6 +828,11 @@ void Executor::worker_thread() { std::cerr << "makeplus: *** No rule to make target '" << target << "'. Stop." << std::endl; success = false; } } else if (node.rule->double_colon) { bool used_free = false; js_acquire(used_free); if (execute_double_colon(target, node.scope) != 0) success = false; js_release(used_free); } else { if (needs_rebuild(target, node.prereqs)) { // Hold a jobserver token for the duration of this recipe so the Loading
executor.h +4 −0 Changes for executor.h: 4 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -123,6 +123,10 @@ private: std::vector<std::string> expand_order_only(const std::string& target, const Rule* rule, const std::string& stem); bool needs_rebuild(const std::string& target, const std::vector<std::string>& prereqs); // Runs every double-colon rule of `target` in makefile order, each one // whose own prerequisites make it out of date (or that has none). int execute_double_colon(const std::string& target, const std::map<std::string, std::string>& scope); int execute_rule(const std::string& target, const Rule* rule, const std::string& stem, const std::vector<std::string>& prereqs, const std::map<std::string, std::string>& scope = {}); Loading
parser.cpp +1 −0 Changes for parser.cpp: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1048,6 +1048,7 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren mf.rules.push_back({targets, prereqs, order_only, {}, is_pattern, ""}); current_rule = &mf.rules.back(); current_rule->double_colon = double_colon && !is_pattern; if (has_inline_recipe) { // GNU make: an inline recipe completes the rule; subsequent tab-indented Loading
parser.h +3 −0 Changes for parser.h: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,9 @@ struct Rule { // When set, targets are concrete but the stem is derived per target by // matching this pattern, and prerequisites contain '%' to substitute. std::string target_pattern; // "target :: prereqs": each double-colon rule of a target is // independent, with its own recipe run when its own prereqs require it. bool double_colon = false; }; struct Makefile { Loading