Commit 791886c6 authored by jan.koester's avatar jan.koester
Browse files

test

parent 3dc6b513
Loading
Loading
Loading
Loading
+15 −18
Changes for executor.cpp: 15 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -520,14 +520,14 @@ std::map<std::string, std::string> Executor::compute_target_scope(
               (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);
    // Scope values are kept unexpanded: execute_rule installs them as
    // recursive variables, so they are expanded in the recipe, with $@ set
    // and the whole scope (e.g. an inherited override) in effect -- as GNU
    // make does. Expanding here would see an empty $@. Values that were
    // already expanded (':=' bindings, simple globals) are escaped so the
    // recipe-time expansion reproduces them unchanged.
    auto unexpanded = [](const Makefile::TargetVar& b) {
        return b.recursive ? b.value : Parser::escape_dollars(b.value);
    };

    for (const auto& entry : mf_.target_vars) {
@@ -554,7 +554,7 @@ std::map<std::string, std::string> Executor::compute_target_scope(
                if (git != mf_.variables.end() && git->second.from_cmdline) continue;
            }

            std::string val = resolve(b.value);
            std::string val = unexpanded(b);
            if (b.append) {
                std::string base;
                auto sit = scope.find(b.name);
@@ -563,16 +563,13 @@ std::map<std::string, std::string> Executor::compute_target_scope(
                } else {
                    auto git = mf_.variables.find(b.name);
                    if (git != mf_.variables.end())
                        // Scope-aware, like `resolve` above: a recursively-
                        // expanded base value may itself reference a variable
                        // that the current target scope overrides (e.g.
                        // zstd's "CFLAGS += $(DEBUGFLAGS) ..." where a
                        // '%-release' pattern binds DEBUGFLAGS := "" for this
                        // target). Expanding against the un-scoped mf_ would
                        // resolve $(DEBUGFLAGS) to its global default instead
                        // of the target-specific override in effect here.
                        // Left unexpanded too: a recursively-expanded base
                        // may reference a variable the target scope overrides
                        // (e.g. zstd's "CFLAGS += $(DEBUGFLAGS) ..." where a
                        // '%-release' pattern binds DEBUGFLAGS := ""), which
                        // must resolve to the override, not the global value.
                        base = (git->second.flavor == VarFlavor::Recursive)
                            ? resolve(git->second.value) : git->second.value;
                            ? git->second.value : Parser::escape_dollars(git->second.value);
                }
                scope[b.name] = base.empty() ? val : base + " " + val;
            } else {
+18 −1
Changes for parser.cpp: 18 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -21,6 +21,16 @@ std::string Parser::trim(const std::string& s) {
    return s.substr(start, end - start + 1);
}

std::string Parser::escape_dollars(const std::string& s) {
    std::string out;
    out.reserve(s.size());
    for (char c : s) {
        if (c == '$') out += '$';
        out += c;
    }
    return out;
}

std::vector<std::string> Parser::split_words(const std::string& s) {
    std::vector<std::string> result;
    std::istringstream iss(s);
@@ -940,10 +950,17 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren
                for (auto& pr : vec) {
                    if (pr.name == tv_name) {
                        if (tv_op == "+=") {
                            // Appending to an already expanded ':=' binding:
                            // keep the merged text unexpanded-safe.
                            if (!pr.recursive) {
                                pr.value = escape_dollars(pr.value);
                                pr.recursive = true;
                            }
                            pr.value = pr.value.empty() ? val : pr.value + " " + val;
                        } else {
                            pr.value = val;
                            pr.append = false;
                            pr.recursive = tv_op != ":=";
                        }
                        // Sticky: once any binding for this (target, name)
                        // pair used 'override', treat the merged binding as
@@ -955,7 +972,7 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren
                }
                // A first-time '+=' must append to whatever value the variable
                // has in the surrounding (global) scope when the recipe runs.
                if (!found) vec.push_back({tv_name, val, tv_op == "+=", tv_override});
                if (!found) vec.push_back({tv_name, val, tv_op == "+=", tv_override, tv_op != ":="});
            }
            current_rule = nullptr;
            return true;
+9 −0
Changes for parser.h: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -62,6 +62,12 @@ struct Makefile {
        // make silently leaves a command-line-origin variable untouched
        // (see compute_target_scope).
        bool is_override = false;
        // Whether `value` is still unexpanded ('=', '+=', '?=') rather than
        // already expanded at parse time (':='). Recursive bindings must be
        // expanded only in the recipe, where $@ and friends are set: Kbuild's
        // '$(obj)/%.o: private objtool-enabled = $(if $(is-standard-object),...)'
        // depends on $@ and is empty when expanded any earlier.
        bool recursive = true;
    };
    std::map<std::string, std::vector<TargetVar>> target_vars;
    // Variables marked for export into the recipe / sub-make environment.
@@ -95,6 +101,9 @@ public:
    const std::string& error() const { return error_; }

    static std::string trim(const std::string& s);
    // "$" -> "$$": turns an already expanded value into text that expands
    // back to itself, for storing it where values are expanded again.
    static std::string escape_dollars(const std::string& s);
    static std::vector<std::string> split_words(const std::string& s);
    static bool glob_match(const std::string& pattern, const std::string& str);
    // GNU make strips a leading "./" from file/target/prereq names so that