Commit 845fcace authored by jan.koester's avatar jan.koester
Browse files

test

parent 3a69fed7
Loading
Loading
Loading
Loading
+16 −4
Changes for executor.cpp: 16 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -246,11 +246,14 @@ const Rule* Executor::find_rule(const std::string& target_in, std::string& stem)
}

std::vector<std::string> Executor::expand_prereqs(const std::string& target,
                                                  const Rule* rule, const std::string& stem) {
                                                  const Rule* rule, const std::string& stem,
                                                  bool as_written) {
    std::vector<std::string> prereqs;

    auto add_prereqs = [&](const Rule* r, bool pattern) {
        for (const auto& p : r->prerequisites) {
        const auto& src = (as_written && !r->prerequisites_raw.empty())
            ? r->prerequisites_raw : r->prerequisites;
        for (const auto& p : src) {
            std::string ep = p;
            if (pattern) {
                size_t pct = ep.find('%');
@@ -262,6 +265,7 @@ std::vector<std::string> Executor::expand_prereqs(const std::string& target,
            std::string expanded = parser_.expand(ep, mf_);
            auto words = Parser::split_words(expanded);
            for (auto& w : words) {
                std::string written = Parser::strip_dot_slash(w);
                w = Parser::normalize_target(w);
                // GNU make directory search: a prerequisite that does not
                // exist locally and has no local rule may still be found via
@@ -270,7 +274,8 @@ std::vector<std::string> Executor::expand_prereqs(const std::string& target,
                // located via "vpath %.c $(ZSTD_SUBDIR)"). Substitute the
                // resolved path so $<, $^, and mtime comparisons see the file
                // make actually found rather than the bare, nonexistent name.
                w = resolve_vpath(w);
                std::string found = resolve_vpath(w);
                w = (as_written && found == w) ? written : found;
            }
            prereqs.insert(prereqs.end(), words.begin(), words.end());
        }
@@ -581,8 +586,15 @@ std::map<std::string, std::string> Executor::compute_target_scope(
}

int Executor::execute_rule(const std::string& target, const Rule* rule,
                           const std::string& stem, const std::vector<std::string>& prereqs,
                           const std::string& stem, const std::vector<std::string>& prereqs_in,
                           const std::map<std::string, std::string>& scope) {
    // $^/$</$+/$? as written in the makefile, not normalize_target()'s
    // lookup names ("a//b" stays "a//b", like GNU make); same files
    std::vector<std::string> prereqs = prereqs_in;
    if (!rule->double_colon) {
        auto written = expand_prereqs(target, rule, stem, true);
        if (written.size() == prereqs.size()) prereqs.swap(written);
    }
    std::string first_prereq = prereqs.empty() ? "" : prereqs[0];

    const Makefile* mfp = &mf_;
+5 −1
Changes for executor.h: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -114,8 +114,12 @@ private:
    // to prerequisites). Returns the effective override map for `target`.
    std::map<std::string, std::string> compute_target_scope(
        const std::string& target, const std::map<std::string, std::string>& inherited);
    // as_written: the prerequisites spelled as in the makefile (vpath
    // resolution still applied), for the automatic variables; otherwise
    // normalize_target()'s names, for lookups. Same order and count.
    std::vector<std::string> expand_prereqs(const std::string& target,
                                            const Rule* rule, const std::string& stem);
                                            const Rule* rule, const std::string& stem,
                                            bool as_written = false);
    // Order-only prerequisites ('target: normal-prereqs | order-only-prereqs').
    // Must exist/be built before the recipe runs, but (unlike expand_prereqs)
    // never force a rebuild by themselves and are excluded from the automatic
+53 −7
Changes for parser.cpp: 53 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -70,6 +70,24 @@ std::string Parser::normalize_target(const std::string& s) {
    return r;
}

std::string Parser::strip_dot_slash(const std::string& s) {
    std::string r = s;
    while (r.size() >= 2 && r[0] == '.' && r[1] == '/') {
        size_t i = 2;
        while (i < r.size() && r[i] == '/') i++;
        r = r.substr(i);
    }
    return r.empty() && !s.empty() ? "." : r;
}

// rule.prerequisites_raw: set only when some prerequisite's written
// spelling differs from its normalized one
static void set_raw_prereqs(Rule& rule, std::vector<std::string> raw) {
    if (raw.size() != rule.prerequisites.size()) return;
    for (auto& p : raw) p = Parser::strip_dot_slash(p);
    if (raw != rule.prerequisites) rule.prerequisites_raw = std::move(raw);
}

bool Parser::glob_match(const std::string& pattern, const std::string& str) {
    size_t pi = 0, si = 0;
    size_t star_p = std::string::npos, star_s = 0;
@@ -549,6 +567,22 @@ void Parser::process_line(const std::string& line, Makefile& mf, Rule*& current_
        return;
    }

    // "override NAME op VALUE" (libbpf's "override CFLAGS += $(INCLUDES)");
    // without this, "override CFLAGS" became the variable's name
    if (trimmed.size() > 9 && trimmed.compare(0, 9, "override ") == 0) {
        std::string rest = trim(trimmed.substr(9));
        if (rest.compare(0, 7, "export ") == 0) {
            rest = trim(rest.substr(7));
            size_t ne = rest.find_first_of(":+?!=");
            std::string nm = trim(rest.substr(0, ne));
            if (!nm.empty()) mf.exported.insert(expand(nm, mf));
        }
        if (try_parse_assignment(rest, mf, true)) {
            current_rule = nullptr;
            return;
        }
    }

    // export / unexport
    if (trimmed == "export") {
        mf.export_all = true;
@@ -653,7 +687,7 @@ void Parser::process_line(const std::string& line, Makefile& mf, Rule*& current_
    current_rule = nullptr;
}

bool Parser::try_parse_assignment(const std::string& line, Makefile& mf) {
bool Parser::try_parse_assignment(const std::string& line, Makefile& mf, bool is_override) {
    int depth = 0;
    size_t eq_pos = std::string::npos;

@@ -702,7 +736,8 @@ bool Parser::try_parse_assignment(const std::string& line, Makefile& mf) {
            if (!value.empty() && value[0] == ' ') value = value.substr(1);
            auto it = mf.variables.find(name);
            if (it != mf.variables.end()) {
                if (!it->second.from_cmdline) {
                bool locked = it->second.from_cmdline || it->second.is_override;
                if (is_override || !locked) {
                    // GNU make: when '+=' appends to a simply-expanded (':=')
                    // variable, the appended text is expanded immediately;
                    // for a recursive variable it is stored verbatim. Without
@@ -713,9 +748,13 @@ bool Parser::try_parse_assignment(const std::string& line, Makefile& mf) {
                        ? expand(value, mf) : value;
                    if (it->second.value.empty()) it->second.value = appended;
                    else it->second.value += " " + appended;
                    if (is_override) {
                        it->second.from_cmdline = false;
                        it->second.is_override = true;
                    }
                }
            } else {
                mf.variables[name] = {value, VarFlavor::Recursive, false};
                mf.variables[name] = {value, VarFlavor::Recursive, false, is_override};
            }
            return true;
        } else if (prev == '?') {
@@ -735,8 +774,9 @@ bool Parser::try_parse_assignment(const std::string& line, Makefile& mf) {
            cmd = expand(cmd, mf);
            std::string value = func_shell(cmd);
            auto it = mf.variables.find(name);
            if (it == mf.variables.end() || !it->second.from_cmdline) {
                mf.variables[name] = {value, VarFlavor::Simple, false};
            if (is_override || it == mf.variables.end() ||
                !(it->second.from_cmdline || it->second.is_override)) {
                mf.variables[name] = {value, VarFlavor::Simple, false, is_override};
            }
            return true;
        }
@@ -749,13 +789,14 @@ bool Parser::try_parse_assignment(const std::string& line, Makefile& mf) {
    if (name.empty()) return false;

    auto it = mf.variables.find(name);
    if (it != mf.variables.end() && it->second.from_cmdline) return true;
    if (!is_override && it != mf.variables.end() &&
        (it->second.from_cmdline || it->second.is_override)) return true;

    if (flavor == VarFlavor::Simple) {
        value = expand(value, mf);
    }

    mf.variables[name] = {value, flavor, false};
    mf.variables[name] = {value, flavor, false, is_override};
    return true;
}

@@ -904,11 +945,13 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren
                } else {
                    pprereqs = split_words(ppat);
                }
                std::vector<std::string> pprereqs_raw = pprereqs;
                for (auto& p : pprereqs) p = normalize_target(p);
                for (auto& p : poo) p = normalize_target(p);
                Rule rule;
                rule.targets = targets;
                rule.prerequisites = pprereqs;
                set_raw_prereqs(rule, pprereqs_raw);
                rule.order_only_prereqs = poo;
                rule.is_pattern = false;
                rule.target_pattern = tpat;
@@ -1019,6 +1062,7 @@ bool Parser::try_parse_rule(const std::string& line, Makefile& mf, Rule*& curren
    };
    glob_words(prereqs);
    glob_words(order_only);
    std::vector<std::string> prereqs_raw = prereqs;
    for (auto& p : prereqs) p = normalize_target(p);
    for (auto& p : order_only) p = normalize_target(p);

@@ -1093,6 +1137,7 @@ 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();
    set_raw_prereqs(*current_rule, prereqs_raw);
    current_rule->double_colon = double_colon && !is_pattern;

    if (has_inline_recipe) {
@@ -1997,6 +2042,7 @@ std::string Parser::expand_function(const std::string& name, const std::string&
        std::string var = trim(do_expand(args, mf, auto_vars));
        auto it = mf.variables.find(var);
        if (it == mf.variables.end()) return "undefined";
        if (it->second.is_override) return "override";
        if (it->second.from_cmdline) return "command line";
        return "file";
    }
+12 −1
Changes for parser.h: 12 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -17,6 +17,9 @@ struct Variable {
    std::string value;
    VarFlavor flavor = VarFlavor::Recursive;
    bool from_cmdline = false;
    // set by "override NAME op VALUE": beats the command line, and later
    // plain assignments in the makefile leave it alone (GNU make)
    bool is_override = false;
};

struct Rule {
@@ -32,6 +35,11 @@ struct Rule {
    // "target :: prereqs": each double-colon rule of a target is
    // independent, with its own recipe run when its own prereqs require it.
    bool double_colon = false;
    // The prerequisites as written (only a leading "./" stripped), when that
    // differs from normalize_target()'s spelling in `prerequisites`: lookups
    // use the normalized names, $^/$</$+/$? the written ones like GNU make
    // (tools/build's "$(filter $(obj-y),$^)" with "dir//x.o" in obj-y).
    std::vector<std::string> prerequisites_raw = {};
};

struct Makefile {
@@ -112,6 +120,9 @@ public:
    // "kernel/bounds.s". Apply this consistently to targets, prerequisites,
    // patterns, and requested goals.
    static std::string normalize_target(const std::string& s);
    // Only the leading "./" segments normalize_target() strips, which GNU
    // make strips from prerequisite names too.
    static std::string strip_dot_slash(const std::string& s);

private:
    std::string error_;
@@ -132,7 +143,7 @@ private:
    // Detect 'NAME op VALUE' target-specific variable bodies after a ':'.
    bool parse_target_var(const std::string& rest, std::string& name,
                          std::string& op, std::string& value) const;
    bool try_parse_assignment(const std::string& line, Makefile& mf);
    bool try_parse_assignment(const std::string& line, Makefile& mf, bool is_override = false);
    bool try_parse_rule(const std::string& line, Makefile& mf, Rule*& current_rule);
    void handle_include(const std::string& args, Makefile& mf, bool optional);
    bool handle_conditional(const std::string& line, Makefile& mf);