Loading executor.cpp +57 −25 Changes for executor.cpp: 57 added lines, 25 removed lines. Original line number Diff line number Diff line Loading @@ -273,16 +273,11 @@ void Executor::apply_exports(const Makefile& mf) { } } int Executor::execute_rule(const std::string& target, const Rule* rule, const std::string& stem, const std::vector<std::string>& prereqs) { std::string first_prereq = prereqs.empty() ? "" : prereqs[0]; std::map<std::string, std::string> Executor::compute_target_scope( const std::string& target, const std::map<std::string, std::string>& inherited) { std::map<std::string, std::string> scope = inherited; if (mf_.target_vars.empty()) return scope; // Apply target-specific variables (recursive flavor) for this target by // expanding the recipes against a local override of the makefile. Both // exact-name and pattern ('%') keys are honoured. const Makefile* mfp = &mf_; Makefile local_copy; bool have_overrides = false; auto pattern_key_matches = [](const std::string& key, const std::string& tgt) { size_t pct = key.find('%'); if (pct == std::string::npos) return false; Loading @@ -292,28 +287,58 @@ int Executor::execute_rule(const std::string& target, const Rule* rule, tgt.substr(0, prefix.size()) == prefix && (suffix.empty() || tgt.substr(tgt.size() - suffix.size()) == suffix); }; // Build an expansion context = global variables overlaid with the current // scope, so a binding value like "$(KBUILD_AFLAGS_32)" or one referencing // an inherited override resolves correctly. auto resolve = [&](const std::string& raw) { Makefile ctx = mf_; for (const auto& kv : scope) ctx.variables[kv.first] = {kv.second, VarFlavor::Simple, false}; return parser_.expand(raw, ctx); }; for (const auto& entry : mf_.target_vars) { if (entry.first != target && !pattern_key_matches(entry.first, target)) continue; if (entry.second.empty()) continue; if (!have_overrides) { local_copy = mf_; have_overrides = true; } for (const auto& kv : entry.second) { std::string value = kv.value; if (kv.append) { // GNU make: a target-specific 'VAR += x' appends to the value // VAR has in the surrounding scope. Resolve that base value now. auto git = mf_.variables.find(kv.name); for (const auto& b : entry.second) { std::string val = resolve(b.value); if (b.append) { std::string base; if (git != mf_.variables.end()) { auto sit = scope.find(b.name); if (sit != scope.end()) { base = sit->second; } else { auto git = mf_.variables.find(b.name); if (git != mf_.variables.end()) base = (git->second.flavor == VarFlavor::Recursive) ? parser_.expand(git->second.value, mf_) : git->second.value; } value = base.empty() ? kv.value : base + " " + kv.value; scope[b.name] = base.empty() ? val : base + " " + val; } else { scope[b.name] = val; } } } local_copy.variables[kv.name] = {value, VarFlavor::Recursive, false}; return scope; } int Executor::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) { std::string first_prereq = prereqs.empty() ? "" : prereqs[0]; // Apply target-specific variables (recursive flavor) for this target by // expanding the recipes against a local override of the makefile. The // `scope` already contains this target's own bindings merged with those // inherited from ancestor targets (see compute_target_scope). const Makefile* mfp = &mf_; Makefile local_copy; if (!scope.empty()) { local_copy = mf_; for (const auto& kv : scope) local_copy.variables[kv.first] = {kv.second, VarFlavor::Recursive, false}; mfp = &local_copy; } if (have_overrides) mfp = &local_copy; // Export marked variables into the environment so recipes and any // recursive sub-makes ($(MAKE)) inherit them. apply_exports(*mfp); Loading Loading @@ -384,7 +409,8 @@ int Executor::execute_rule(const std::string& target, const Rule* rule, // ======================== Sequential Build ======================== int Executor::build_sequential(const std::string& target_in) { int Executor::build_sequential(const std::string& target_in, const std::map<std::string, std::string>& inherited) { std::string target = Parser::normalize_target(target_in); auto it = visited_.find(target); if (it != visited_.end()) return it->second; Loading Loading @@ -426,9 +452,15 @@ int Executor::build_sequential(const std::string& target_in) { auto prereqs = expand_prereqs(target, rule, stem); // Compute the effective target-specific variable scope for this target: // inherited bindings from ancestors merged with this target's own bindings. // GNU make propagates target-specific variables to prerequisites, so this // scope is passed down when building each prerequisite. std::map<std::string, std::string> scope = compute_target_scope(target, inherited); // Build all prerequisites for (const auto& prereq : prereqs) { int rc = build_sequential(prereq); int rc = build_sequential(prereq, scope); if (rc != 0) { if (!keep_going_) { visited_[target] = rc; Loading @@ -442,7 +474,7 @@ int Executor::build_sequential(const std::string& target_in) { return 0; } int rc = execute_rule(target, rule, stem, prereqs); int rc = execute_rule(target, rule, stem, prereqs, scope); if (rc == 0) rebuilt_.insert(target); visited_[target] = rc; return rc; Loading Loading
executor.cpp +57 −25 Changes for executor.cpp: 57 added lines, 25 removed lines. Original line number Diff line number Diff line Loading @@ -273,16 +273,11 @@ void Executor::apply_exports(const Makefile& mf) { } } int Executor::execute_rule(const std::string& target, const Rule* rule, const std::string& stem, const std::vector<std::string>& prereqs) { std::string first_prereq = prereqs.empty() ? "" : prereqs[0]; std::map<std::string, std::string> Executor::compute_target_scope( const std::string& target, const std::map<std::string, std::string>& inherited) { std::map<std::string, std::string> scope = inherited; if (mf_.target_vars.empty()) return scope; // Apply target-specific variables (recursive flavor) for this target by // expanding the recipes against a local override of the makefile. Both // exact-name and pattern ('%') keys are honoured. const Makefile* mfp = &mf_; Makefile local_copy; bool have_overrides = false; auto pattern_key_matches = [](const std::string& key, const std::string& tgt) { size_t pct = key.find('%'); if (pct == std::string::npos) return false; Loading @@ -292,28 +287,58 @@ int Executor::execute_rule(const std::string& target, const Rule* rule, tgt.substr(0, prefix.size()) == prefix && (suffix.empty() || tgt.substr(tgt.size() - suffix.size()) == suffix); }; // Build an expansion context = global variables overlaid with the current // scope, so a binding value like "$(KBUILD_AFLAGS_32)" or one referencing // an inherited override resolves correctly. auto resolve = [&](const std::string& raw) { Makefile ctx = mf_; for (const auto& kv : scope) ctx.variables[kv.first] = {kv.second, VarFlavor::Simple, false}; return parser_.expand(raw, ctx); }; for (const auto& entry : mf_.target_vars) { if (entry.first != target && !pattern_key_matches(entry.first, target)) continue; if (entry.second.empty()) continue; if (!have_overrides) { local_copy = mf_; have_overrides = true; } for (const auto& kv : entry.second) { std::string value = kv.value; if (kv.append) { // GNU make: a target-specific 'VAR += x' appends to the value // VAR has in the surrounding scope. Resolve that base value now. auto git = mf_.variables.find(kv.name); for (const auto& b : entry.second) { std::string val = resolve(b.value); if (b.append) { std::string base; if (git != mf_.variables.end()) { auto sit = scope.find(b.name); if (sit != scope.end()) { base = sit->second; } else { auto git = mf_.variables.find(b.name); if (git != mf_.variables.end()) base = (git->second.flavor == VarFlavor::Recursive) ? parser_.expand(git->second.value, mf_) : git->second.value; } value = base.empty() ? kv.value : base + " " + kv.value; scope[b.name] = base.empty() ? val : base + " " + val; } else { scope[b.name] = val; } } } local_copy.variables[kv.name] = {value, VarFlavor::Recursive, false}; return scope; } int Executor::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) { std::string first_prereq = prereqs.empty() ? "" : prereqs[0]; // Apply target-specific variables (recursive flavor) for this target by // expanding the recipes against a local override of the makefile. The // `scope` already contains this target's own bindings merged with those // inherited from ancestor targets (see compute_target_scope). const Makefile* mfp = &mf_; Makefile local_copy; if (!scope.empty()) { local_copy = mf_; for (const auto& kv : scope) local_copy.variables[kv.first] = {kv.second, VarFlavor::Recursive, false}; mfp = &local_copy; } if (have_overrides) mfp = &local_copy; // Export marked variables into the environment so recipes and any // recursive sub-makes ($(MAKE)) inherit them. apply_exports(*mfp); Loading Loading @@ -384,7 +409,8 @@ int Executor::execute_rule(const std::string& target, const Rule* rule, // ======================== Sequential Build ======================== int Executor::build_sequential(const std::string& target_in) { int Executor::build_sequential(const std::string& target_in, const std::map<std::string, std::string>& inherited) { std::string target = Parser::normalize_target(target_in); auto it = visited_.find(target); if (it != visited_.end()) return it->second; Loading Loading @@ -426,9 +452,15 @@ int Executor::build_sequential(const std::string& target_in) { auto prereqs = expand_prereqs(target, rule, stem); // Compute the effective target-specific variable scope for this target: // inherited bindings from ancestors merged with this target's own bindings. // GNU make propagates target-specific variables to prerequisites, so this // scope is passed down when building each prerequisite. std::map<std::string, std::string> scope = compute_target_scope(target, inherited); // Build all prerequisites for (const auto& prereq : prereqs) { int rc = build_sequential(prereq); int rc = build_sequential(prereq, scope); if (rc != 0) { if (!keep_going_) { visited_[target] = rc; Loading @@ -442,7 +474,7 @@ int Executor::build_sequential(const std::string& target_in) { return 0; } int rc = execute_rule(target, rule, stem, prereqs); int rc = execute_rule(target, rule, stem, prereqs, scope); if (rc == 0) rebuilt_.insert(target); visited_[target] = rc; return rc; Loading