Commit 7563b82e authored by jan.koester's avatar jan.koester
Browse files

test

parent 0689a722
Loading
Loading
Loading
Loading
+38 −8
Changes for executor.cpp: 38 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -14,7 +14,25 @@ Executor::Executor(Makefile& mf, Parser& parser) : mf_(mf), parser_(parser) {}

const Rule* Executor::find_rule(const std::string& target, std::string& stem) {
    const Rule* r = mf_.find_explicit_rule(target);
    if (r && !r->recipes.empty()) { stem.clear(); return r; }
    if (r && !r->recipes.empty()) {
        // Static pattern rule: derive the stem by matching the target pattern.
        if (!r->target_pattern.empty()) {
            size_t pct = r->target_pattern.find('%');
            std::string prefix = r->target_pattern.substr(0, pct);
            std::string suffix = r->target_pattern.substr(pct + 1);
            if (target.size() >= prefix.size() + suffix.size() &&
                target.substr(0, prefix.size()) == prefix &&
                (suffix.empty() || target.substr(target.size() - suffix.size()) == suffix)) {
                stem = target.substr(prefix.size(),
                                     target.size() - prefix.size() - suffix.size());
            } else {
                stem.clear();
            }
            return r;
        }
        stem.clear();
        return r;
    }

    // Explicit rule has no recipe - try pattern/implicit rules for recipe
    const Rule* pattern = mf_.find_pattern_rule(target, stem);
@@ -82,7 +100,7 @@ std::vector<std::string> Executor::expand_prereqs(const std::string& target,
    };

    // Collect prerequisites from the chosen rule.
    add_prereqs(rule, rule->is_pattern);
    add_prereqs(rule, rule->is_pattern || !rule->target_pattern.empty());

    // GNU Make merges prerequisites from all explicit rules for the same target.
    // CMake relies on this: a target's prerequisites are spread across several
@@ -160,16 +178,28 @@ int Executor::execute_rule(const std::string& target, const Rule* rule,
    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.
    // 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;
    auto tv = mf_.target_vars.find(target);
    if (tv != mf_.target_vars.end() && !tv->second.empty()) {
        local_copy = mf_;
        for (const auto& kv : tv->second)
    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;
        std::string prefix = key.substr(0, pct);
        std::string suffix = key.substr(pct + 1);
        return tgt.size() >= prefix.size() + suffix.size() &&
               tgt.substr(0, prefix.size()) == prefix &&
               (suffix.empty() || tgt.substr(tgt.size() - suffix.size()) == suffix);
    };
    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)
            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);
+36 −0
Changes for parser.cpp: 36 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -652,6 +652,42 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren
    auto targets = split_words(targets_str);
    if (targets.empty()) return false;

    // Static pattern rule:  targets : target-pattern : prereq-patterns
    // Detect a second depth-0 colon in the right-hand side whose left part is
    // a '%' pattern. (Distinguished from target-specific vars, which have '='.)
    {
        int d = 0;
        size_t c2 = std::string::npos;
        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) {
                if (i + 1 < rhs_raw.size() && rhs_raw[i+1] == '=') break;
                c2 = i; break;
            } else if (c == '=' && d == 0) {
                break; // target-specific variable, not a static pattern rule
            }
        }
        if (c2 != std::string::npos) {
            std::string tpat = expand(trim(rhs_raw.substr(0, c2)), mf);
            std::string ppat = expand(trim(rhs_raw.substr(c2 + 1)), mf);
            if (tpat.find('%') != std::string::npos) {
                auto pprereqs = split_words(ppat);
                Rule rule;
                rule.targets = targets;
                rule.prerequisites = pprereqs;
                rule.is_pattern = false;
                rule.target_pattern = tpat;
                mf.rules.push_back(std::move(rule));
                current_rule = &mf.rules.back();
                return true;
            }
        }
    }

    // Target-specific variable assignment:  targets: NAME op VALUE
    {
        std::string tv_name, tv_op, tv_value;
+4 −0
Changes for parser.h: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@ struct Rule {
    std::vector<std::string> order_only_prereqs;
    std::vector<std::string> recipes;
    bool is_pattern = false;
    // For static pattern rules ("targets: target-pattern: prereq-patterns").
    // 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;
};

struct Makefile {