diff --git a/ostd/build/make.hh b/ostd/build/make.hh index 37360e8..019b838 100644 --- a/ostd/build/make.hh +++ b/ostd/build/make.hh @@ -58,6 +58,19 @@ struct make_error: std::runtime_error { {} }; +struct OSTD_EXPORT make_pattern { + make_pattern() = delete; + make_pattern(string_range target): + p_target(target) + {} + + std::pair match(string_range target); + std::string replace(string_range dep) const; +private: + std::string p_target; + std::vector p_subs{}; +}; + struct make_rule { using body_func = std::function< void(string_range, iterator_range) @@ -68,7 +81,11 @@ struct make_rule { p_target(target) {} - string_range target() const noexcept { + make_pattern &target() noexcept { + return p_target; + } + + make_pattern const &target() const noexcept { return p_target; } @@ -139,7 +156,7 @@ private: } } - std::string p_target; + make_pattern p_target; std::vector p_deps{}; body_func p_body{}; bool p_action = false; diff --git a/src/build_make.cc b/src/build_make.cc index b22fdfb..30ee49f 100644 --- a/src/build_make.cc +++ b/src/build_make.cc @@ -84,6 +84,42 @@ static string_range match_pattern( return expanded; } +OSTD_EXPORT std::pair< + std::size_t, std::size_t +> make_pattern::match(string_range target) { + using PT = std::pair; + + string_range sub = match_pattern(target, p_target); + p_subs.clear(); + + std::size_t subl = sub.size(); + if (subl == 0) { + return PT{0, 0}; + } + p_subs.push_back(sub); + + std::size_t tarl = target.size(); + if (subl == tarl) { + return PT{sub.size(), 0}; + } + return PT{target.data() + tarl - sub.data() - subl, subl}; +} + +OSTD_EXPORT std::string make_pattern::replace(string_range dep) const { + if (p_subs.empty()) { + return std::string{dep}; + } + auto lp = ostd::find(dep, '%'); + if (lp.empty()) { + return std::string{dep}; + } + auto ret = std::string{dep.slice(0, &lp[0] - &dep[0])}; + ret.append(p_subs[0]); + lp.pop_front(); + ret.append(lp); + return ret; +} + void make::exec_rlist(string_range tname, std::vector const &rlist) { std::vector rdeps; if ((rlist.size() > 1) || !rlist[0].deps.empty()) { @@ -138,44 +174,38 @@ void make::find_rules(string_range target, std::vector &rlist) { return; } rule_inst *frule = nullptr; - string_range prev_sub{}; + std::size_t pfnl = 0, psubl = 0; for (auto &rule: p_rules) { - string_range sub = match_pattern(target, rule.target()); - if (!sub.empty()) { + auto &tgt = rule.target(); + auto [fnl, subl] = tgt.match(target); + if ((fnl + subl) > 0) { rlist.emplace_back(); rule_inst &sr = rlist.back(); sr.rule = &rule; sr.deps.reserve(rule.depends().size()); - bool ematch = (sub.size() == target.size()); for (auto &d: rule.depends()) { - string_range dp = d; - if (!ematch) { - auto lp = ostd::find(dp, '%'); - if (!lp.empty()) { - auto repd = std::string{dp.slice(0, &lp[0] - &dp[0])}; - repd.append(sub); - lp.pop_front(); - repd.append(lp); - sr.deps.push_back(std::move(repd)); - continue; - } - } - sr.deps.push_back(d); + sr.deps.push_back(tgt.replace(d)); } - if (!rule.has_body() && !ematch) { - throw make_error{"pattern rule '%s' needs a body", target}; + if (!rule.has_body()) { + if (fnl != target.size()) { + throw make_error{"pattern rule '%s' needs a body", target}; + } + continue; } if (frule) { - if (sub.size() == prev_sub.size()) { + if ((pfnl == fnl) && (psubl == subl)) { throw make_error{"redefinition of rule '%s'", target}; } - if (sub.size() < prev_sub.size()) { + if ((fnl > pfnl) || ((fnl == pfnl) && (subl < psubl))) { *frule = sr; + pfnl = fnl; + psubl = subl; rlist.pop_back(); } } else { frule = &sr; - prev_sub = sub; + pfnl = fnl; + psubl = subl; } } }