Loading parser.cpp +34 −1 Changes for parser.cpp: 34 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -696,6 +696,30 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren size_t prereq_start = colon_pos + 1 + (double_colon ? 1 : 0); std::string rhs_raw = prereq_start < line.size() ? trim(line.substr(prereq_start)) : ""; // Inline recipe form: "targets: prereqs ; recipe". A depth-0 ';' separates // the prerequisites from a single inline recipe line, which may be empty // (e.g. Kbuild's "$(sort ...): . ;" no-op rule that suppresses implicit // rules and asserts the target is produced by descending). Without this the // ';' was treated as a prerequisite ("No rule to make target ';'"). bool has_inline_recipe = false; std::string inline_recipe; { int d = 0; for (size_t i = 0; i < rhs_raw.size(); ++i) { char c = rhs_raw[i]; if (c == '$' && i + 1 < rhs_raw.size() && (rhs_raw[i+1] == '(' || rhs_raw[i+1] == '{')) { d++; i++; } else if ((c == ')' || c == '}') && d > 0) { d--; } else if (c == ';' && d == 0) { has_inline_recipe = true; inline_recipe = trim(rhs_raw.substr(i + 1)); rhs_raw = trim(rhs_raw.substr(0, i)); break; } } } targets_str = expand(targets_str, mf); auto targets = split_words(targets_str); Loading Loading @@ -730,8 +754,9 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren rule.prerequisites = pprereqs; rule.is_pattern = false; rule.target_pattern = tpat; if (has_inline_recipe) rule.recipes.push_back(inline_recipe); mf.rules.push_back(std::move(rule)); current_rule = &mf.rules.back(); current_rule = has_inline_recipe ? nullptr : &mf.rules.back(); return true; } } Loading Loading @@ -805,6 +830,14 @@ 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(); if (has_inline_recipe) { // GNU make: an inline recipe completes the rule; subsequent tab-indented // lines do not belong to it. Record it (an empty recipe still counts, // preventing implicit rules) and stop appending to this rule. current_rule->recipes.push_back(inline_recipe); current_rule = nullptr; } if (mf.default_target.empty() && !is_pattern && !targets.empty() && targets[0][0] != '.') { mf.default_target = targets[0]; } Loading Loading
parser.cpp +34 −1 Changes for parser.cpp: 34 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -696,6 +696,30 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren size_t prereq_start = colon_pos + 1 + (double_colon ? 1 : 0); std::string rhs_raw = prereq_start < line.size() ? trim(line.substr(prereq_start)) : ""; // Inline recipe form: "targets: prereqs ; recipe". A depth-0 ';' separates // the prerequisites from a single inline recipe line, which may be empty // (e.g. Kbuild's "$(sort ...): . ;" no-op rule that suppresses implicit // rules and asserts the target is produced by descending). Without this the // ';' was treated as a prerequisite ("No rule to make target ';'"). bool has_inline_recipe = false; std::string inline_recipe; { int d = 0; for (size_t i = 0; i < rhs_raw.size(); ++i) { char c = rhs_raw[i]; if (c == '$' && i + 1 < rhs_raw.size() && (rhs_raw[i+1] == '(' || rhs_raw[i+1] == '{')) { d++; i++; } else if ((c == ')' || c == '}') && d > 0) { d--; } else if (c == ';' && d == 0) { has_inline_recipe = true; inline_recipe = trim(rhs_raw.substr(i + 1)); rhs_raw = trim(rhs_raw.substr(0, i)); break; } } } targets_str = expand(targets_str, mf); auto targets = split_words(targets_str); Loading Loading @@ -730,8 +754,9 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren rule.prerequisites = pprereqs; rule.is_pattern = false; rule.target_pattern = tpat; if (has_inline_recipe) rule.recipes.push_back(inline_recipe); mf.rules.push_back(std::move(rule)); current_rule = &mf.rules.back(); current_rule = has_inline_recipe ? nullptr : &mf.rules.back(); return true; } } Loading Loading @@ -805,6 +830,14 @@ 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(); if (has_inline_recipe) { // GNU make: an inline recipe completes the rule; subsequent tab-indented // lines do not belong to it. Record it (an empty recipe still counts, // preventing implicit rules) and stop appending to this rule. current_rule->recipes.push_back(inline_recipe); current_rule = nullptr; } if (mf.default_target.empty() && !is_pattern && !targets.empty() && targets[0][0] != '.') { mf.default_target = targets[0]; } Loading