From 3506facc61846190c72a57cf30b9c22c8263fc5f Mon Sep 17 00:00:00 2001 From: q66 Date: Tue, 24 Apr 2018 01:24:48 +0200 Subject: [PATCH] move make impl bits into a source file --- ostd/build/make.hh | 267 +++------------------------------------------ src/build_make.cc | 259 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+), 252 deletions(-) diff --git a/ostd/build/make.hh b/ostd/build/make.hh index c22f4aa..aac7e7d 100644 --- a/ostd/build/make.hh +++ b/ostd/build/make.hh @@ -58,78 +58,6 @@ struct make_error: std::runtime_error { {} }; -namespace detail { - static bool check_exec( - string_range tname, std::vector const &deps - ) { - if (!fs::exists(tname)) { - return true; - } - for (auto &dep: deps) { - if (!fs::exists(dep)) { - return true; - } - } - auto get_ts = [](string_range fname) { - path p{fname}; - if (!fs::is_regular_file(p)) { - return fs::file_time_t{}; - } - return fs::last_write_time(p); - }; - auto tts = get_ts(tname); - if (tts == fs::file_time_t{}) { - return true; - } - for (auto &dep: deps) { - auto sts = get_ts(dep); - if ((sts != fs::file_time_t{}) && (tts < sts)) { - return true; - } - } - return false; - } - - /* this lets us properly match % patterns in target names */ - static string_range match_pattern( - string_range expanded, string_range toexpand - ) { - auto rep = ostd::find(toexpand, '%'); - /* no subst found */ - if (rep.empty()) { - return nullptr; - } - /* get the part before % */ - auto fp = toexpand.slice(0, &rep[0] - &toexpand[0]); - /* part before % does not compare, so ignore */ - if (expanded.size() <= fp.size()) { - return nullptr; - } - if (expanded.slice(0, fp.size()) != fp) { - return nullptr; - } - /* pop out front part */ - expanded = expanded.slice(fp.size(), expanded.size()); - /* part after % */ - ++rep; - if (rep.empty()) { - return expanded; - } - /* part after % does not compare, so ignore */ - if (expanded.size() <= rep.size()) { - return nullptr; - } - size_t es = expanded.size(); - if (expanded.slice(es - rep.size(), es) != rep) { - return nullptr; - } - /* cut off latter part */ - expanded = expanded.slice(0, expanded.size() - rep.size()); - /* we got what we wanted... */ - return expanded; - } -} - struct make_rule { using body_func = std::function< void(string_range, iterator_range) @@ -280,7 +208,7 @@ inline make_task *make_task_simple( return new detail::make_task_simple{target, std::move(deps), rl}; } -struct make { +struct OSTD_EXPORT make { using task_factory = std::function< make_task *(string_range, std::vector, make_rule &) >; @@ -291,24 +219,9 @@ struct make { p_tpool.start(threads); } - void exec(string_range target) { - wait_for([&target, this]() { - exec_rule(target); - }); - } + void exec(string_range target); - std::shared_future push_task(std::function func) { - return p_current->add_task( - p_tpool.push([func = std::move(func), this]() { - func(); - { - std::lock_guard l{p_mtx}; - p_avail = true; - } - p_cond.notify_one(); - }) - ); - } + std::shared_future push_task(std::function func); make_rule &rule(string_range tgt) { p_rules.emplace_back(tgt); @@ -325,6 +238,8 @@ private: make_rule *rule; }; + OSTD_LOCAL void wait_rest(std::queue> &tasks); + template void wait_for(F func) { std::queue> tasks; @@ -336,172 +251,20 @@ private: throw; } p_waiting.pop(); - if (tasks.empty()) { - /* nothing to wait for, so return */ - return; - } - /* cycle until tasks are done */ - std::unique_lock lk{p_mtx}; - while (!p_avail) { - p_cond.wait(lk); - } - std::queue> atasks; - while (!tasks.empty()) { - p_avail = false; - while (!tasks.empty()) { - try { - auto t = std::move(tasks.front()); - tasks.pop(); - p_current = t.get(); - t->resume(); - if (!t->done()) { - /* still not dead, re-push */ - atasks.push(std::move(t)); - } - } catch (make_error const &) { - writeln("waiting for the remaining tasks to finish..."); - for (; !tasks.empty(); tasks.pop()) { - try { - auto t = std::move(tasks.front()); - tasks.pop(); - while (!t->done()) { - p_current = t.get(); - t->resume(); - } - } catch (make_error const &) { - /* no rethrow */ - } - } - throw; - } - } - if (atasks.empty()) { - break; - } - tasks.swap(atasks); - /* so we're not busylooping */ - while (!p_avail) { - p_cond.wait(lk); - } - } + wait_rest(tasks); } - void exec_rlist(string_range tname, std::vector const &rlist) { - std::vector rdeps; - if ((rlist.size() > 1) || !rlist[0].deps.empty()) { - wait_for([&rlist, &rdeps, &tname, this]() { - for (auto &sr: rlist) { - for (auto &tgt: sr.deps) { - rdeps.push_back(tgt); - exec_rule(tgt, tname); - } - } - }); - } - make_rule *rl = nullptr; - for (auto &sr: rlist) { - if (sr.rule->has_body()) { - rl = sr.rule; - break; - } - } - if (rl && (rl->action() || detail::check_exec(tname, rdeps))) { - std::unique_ptr t{ - p_factory(tname, std::move(rdeps), *rl) - }; - p_current = t.get(); - t->resume(); - if (!t->done()) { - p_waiting.top()->push(std::move(t)); - } - } - } + OSTD_LOCAL void exec_rlist( + string_range tname, std::vector const &rlist + ); - void exec_rule(string_range target, string_range from = nullptr) { - std::vector &rlist = p_cache[target]; - find_rules(target, rlist); - if (rlist.empty()) { - if (fs::exists(target)) { - return; - } - if (from.empty()) { - throw make_error{"no rule to exec target '%s'", target}; - } else { - throw make_error{ - "no rule to exec target '%s' (needed by '%s')", target, from - }; - } - } - exec_rlist(target, rlist); - } + OSTD_LOCAL void exec_rule( + string_range target, string_range from = nullptr + ); - void find_rules(string_range target, std::vector &rlist) { - if (!rlist.empty()) { - return; - } - rule_inst *frule = nullptr; - bool exact = false; - string_range prev_sub{}; - for (auto &rule: p_rules) { - if (target == string_range{rule.target()}) { - rlist.emplace_back(); - rule_inst &sr = rlist.back(); - sr.rule = &rule; - sr.deps.reserve(rule.depends().size()); - for (auto &d: rule.depends()) { - sr.deps.push_back(d); - } - if (rule.has_body()) { - if (frule && exact) { - throw make_error{"redefinition of rule '%s'", target}; - } - if (!frule) { - frule = &rlist.back(); - } else { - *frule = rlist.back(); - rlist.pop_back(); - } - exact = true; - } - continue; - } - if (exact || !rule.has_body()) { - continue; - } - string_range sub = detail::match_pattern(target, rule.target()); - if (!sub.empty()) { - rlist.emplace_back(); - rule_inst &sr = rlist.back(); - sr.rule = &rule; - sr.deps.reserve(rule.depends().size()); - for (auto &d: rule.depends()) { - string_range dp = d; - 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)); - } else { - sr.deps.push_back(d); - } - } - if (frule) { - if (sub.size() == prev_sub.size()) { - throw make_error{"redefinition of rule '%s'", target}; - } - if (sub.size() < prev_sub.size()) { - *frule = sr; - rlist.pop_back(); - } - } else { - frule = &sr; - prev_sub = sub; - } - } - } - } + OSTD_LOCAL void find_rules( + string_range target, std::vector &rlist + ); std::vector p_rules{}; std::unordered_map> p_cache{}; diff --git a/src/build_make.cc b/src/build_make.cc index b597225..6307aa1 100644 --- a/src/build_make.cc +++ b/src/build_make.cc @@ -11,5 +11,264 @@ namespace build { /* place the vtable in here */ make_task::~make_task() {} +static bool check_exec( + string_range tname, std::vector const &deps +) { + if (!fs::exists(tname)) { + return true; + } + for (auto &dep: deps) { + if (!fs::exists(dep)) { + return true; + } + } + auto get_ts = [](string_range fname) { + path p{fname}; + if (!fs::is_regular_file(p)) { + return fs::file_time_t{}; + } + return fs::last_write_time(p); + }; + auto tts = get_ts(tname); + if (tts == fs::file_time_t{}) { + return true; + } + for (auto &dep: deps) { + auto sts = get_ts(dep); + if ((sts != fs::file_time_t{}) && (tts < sts)) { + return true; + } + } + return false; +} + +/* this lets us properly match % patterns in target names */ +static string_range match_pattern( + string_range expanded, string_range toexpand +) { + auto rep = ostd::find(toexpand, '%'); + /* no subst found */ + if (rep.empty()) { + return nullptr; + } + /* get the part before % */ + auto fp = toexpand.slice(0, &rep[0] - &toexpand[0]); + /* part before % does not compare, so ignore */ + if (expanded.size() <= fp.size()) { + return nullptr; + } + if (expanded.slice(0, fp.size()) != fp) { + return nullptr; + } + /* pop out front part */ + expanded = expanded.slice(fp.size(), expanded.size()); + /* part after % */ + ++rep; + if (rep.empty()) { + return expanded; + } + /* part after % does not compare, so ignore */ + if (expanded.size() <= rep.size()) { + return nullptr; + } + size_t es = expanded.size(); + if (expanded.slice(es - rep.size(), es) != rep) { + return nullptr; + } + /* cut off latter part */ + expanded = expanded.slice(0, expanded.size() - rep.size()); + /* we got what we wanted... */ + return expanded; +} + +void make::exec_rlist(string_range tname, std::vector const &rlist) { + std::vector rdeps; + if ((rlist.size() > 1) || !rlist[0].deps.empty()) { + wait_for([&rlist, &rdeps, &tname, this]() { + for (auto &sr: rlist) { + for (auto &tgt: sr.deps) { + rdeps.push_back(tgt); + exec_rule(tgt, tname); + } + } + }); + } + make_rule *rl = nullptr; + for (auto &sr: rlist) { + if (sr.rule->has_body()) { + rl = sr.rule; + break; + } + } + if (rl && (rl->action() || check_exec(tname, rdeps))) { + std::unique_ptr t{ + p_factory(tname, std::move(rdeps), *rl) + }; + p_current = t.get(); + t->resume(); + if (!t->done()) { + p_waiting.top()->push(std::move(t)); + } + } +} + +void make::exec_rule(string_range target, string_range from) { + std::vector &rlist = p_cache[target]; + find_rules(target, rlist); + if (rlist.empty()) { + if (fs::exists(target)) { + return; + } + if (from.empty()) { + throw make_error{"no rule to exec target '%s'", target}; + } else { + throw make_error{ + "no rule to exec target '%s' (needed by '%s')", target, from + }; + } + } + exec_rlist(target, rlist); +} + +void make::find_rules(string_range target, std::vector &rlist) { + if (!rlist.empty()) { + return; + } + rule_inst *frule = nullptr; + bool exact = false; + string_range prev_sub{}; + for (auto &rule: p_rules) { + if (target == string_range{rule.target()}) { + rlist.emplace_back(); + rule_inst &sr = rlist.back(); + sr.rule = &rule; + sr.deps.reserve(rule.depends().size()); + for (auto &d: rule.depends()) { + sr.deps.push_back(d); + } + if (rule.has_body()) { + if (frule && exact) { + throw make_error{"redefinition of rule '%s'", target}; + } + if (!frule) { + frule = &rlist.back(); + } else { + *frule = rlist.back(); + rlist.pop_back(); + } + exact = true; + } + continue; + } + if (exact || !rule.has_body()) { + continue; + } + string_range sub = match_pattern(target, rule.target()); + if (!sub.empty()) { + rlist.emplace_back(); + rule_inst &sr = rlist.back(); + sr.rule = &rule; + sr.deps.reserve(rule.depends().size()); + for (auto &d: rule.depends()) { + string_range dp = d; + 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)); + } else { + sr.deps.push_back(d); + } + } + if (frule) { + if (sub.size() == prev_sub.size()) { + throw make_error{"redefinition of rule '%s'", target}; + } + if (sub.size() < prev_sub.size()) { + *frule = sr; + rlist.pop_back(); + } + } else { + frule = &sr; + prev_sub = sub; + } + } + } +} + +void make::wait_rest(std::queue> &tasks) { + if (tasks.empty()) { + /* nothing to wait for, so return */ + return; + } + /* cycle until tasks are done */ + std::unique_lock lk{p_mtx}; + while (!p_avail) { + p_cond.wait(lk); + } + std::queue> atasks; + while (!tasks.empty()) { + p_avail = false; + while (!tasks.empty()) { + try { + auto t = std::move(tasks.front()); + tasks.pop(); + p_current = t.get(); + t->resume(); + if (!t->done()) { + /* still not dead, re-push */ + atasks.push(std::move(t)); + } + } catch (make_error const &) { + writeln("waiting for the remaining tasks to finish..."); + for (; !tasks.empty(); tasks.pop()) { + try { + auto t = std::move(tasks.front()); + tasks.pop(); + while (!t->done()) { + p_current = t.get(); + t->resume(); + } + } catch (make_error const &) { + /* no rethrow */ + } + } + throw; + } + } + if (atasks.empty()) { + break; + } + tasks.swap(atasks); + /* so we're not busylooping */ + while (!p_avail) { + p_cond.wait(lk); + } + } +} + +OSTD_EXPORT void make::exec(string_range target) { + wait_for([&target, this]() { + exec_rule(target); + }); +} + +OSTD_EXPORT std::shared_future make::push_task( + std::function func +) { + return p_current->add_task( + p_tpool.push([func = std::move(func), this]() { + func(); + { + std::lock_guard l{p_mtx}; + p_avail = true; + } + p_cond.notify_one(); + }) + ); +} + } /* namespace build */ } /* namespace ostd */