Commit fbde142f authored by jan.koester's avatar jan.koester
Browse files

compute scope implemeted

parent 991700f3
Loading
Loading
Loading
Loading
+57 −25
Changes for executor.cpp: 57 added lines, 25 removed lines.
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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;
@@ -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;
@@ -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;