2015-08-16 00:06:42 +00:00
|
|
|
#include <ostd/types.hh>
|
2015-11-27 22:11:46 +00:00
|
|
|
#include <ostd/functional.hh>
|
2015-08-16 00:06:42 +00:00
|
|
|
#include <ostd/string.hh>
|
2015-08-14 01:54:00 +00:00
|
|
|
#include <ostd/vector.hh>
|
2015-10-15 08:42:43 +00:00
|
|
|
#include <ostd/map.hh>
|
2015-08-24 18:16:55 +00:00
|
|
|
#include <ostd/atomic.hh>
|
2015-09-04 17:59:05 +00:00
|
|
|
#include <ostd/filesystem.hh>
|
2016-02-28 22:21:47 +00:00
|
|
|
#include <ostd/io.hh>
|
2015-09-26 14:13:17 +00:00
|
|
|
#include <ostd/platform.hh>
|
2015-11-27 22:11:46 +00:00
|
|
|
#include <ostd/utility.hh>
|
2016-03-18 21:54:24 +00:00
|
|
|
#include <ostd/environ.hh>
|
2016-01-23 22:38:59 +00:00
|
|
|
#include <ostd/thread.hh>
|
|
|
|
#include <ostd/mutex.hh>
|
|
|
|
#include <ostd/condition.hh>
|
2015-08-14 01:54:00 +00:00
|
|
|
|
2015-08-16 00:06:42 +00:00
|
|
|
#include <cubescript.hh>
|
2015-08-14 01:54:00 +00:00
|
|
|
|
2016-02-13 20:47:54 +00:00
|
|
|
void cs_register_globs(cscript::CsState &cs);
|
2015-08-24 07:41:46 +00:00
|
|
|
|
2015-08-31 13:47:39 +00:00
|
|
|
using ostd::ConstCharRange;
|
|
|
|
using ostd::Vector;
|
2015-10-15 08:42:43 +00:00
|
|
|
using ostd::Map;
|
2015-08-31 13:47:39 +00:00
|
|
|
using ostd::String;
|
2015-09-01 17:50:00 +00:00
|
|
|
using ostd::Uint32;
|
|
|
|
using ostd::slice_until;
|
2016-01-23 22:38:59 +00:00
|
|
|
using ostd::Thread;
|
|
|
|
using ostd::UniqueLock;
|
|
|
|
using ostd::Mutex;
|
|
|
|
using ostd::Condition;
|
2015-08-31 13:47:39 +00:00
|
|
|
|
2015-10-13 20:23:41 +00:00
|
|
|
using cscript::CsState;
|
|
|
|
using cscript::TvalRange;
|
|
|
|
using cscript::StackedValue;
|
2015-12-23 12:52:27 +00:00
|
|
|
using cscript::Bytecode;
|
2015-10-13 20:23:41 +00:00
|
|
|
|
2015-11-27 22:11:46 +00:00
|
|
|
/* thread pool */
|
|
|
|
|
|
|
|
struct ThreadPool {
|
|
|
|
ThreadPool() {}
|
|
|
|
|
|
|
|
~ThreadPool() {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (running) {
|
|
|
|
destroy();
|
|
|
|
}
|
2015-11-27 22:11:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *thr_func(void *ptr) {
|
2016-07-31 23:09:29 +00:00
|
|
|
static_cast<ThreadPool *>(ptr)->run();
|
2015-11-27 22:11:46 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool init(ostd::Size size) {
|
|
|
|
running = true;
|
|
|
|
for (ostd::Size i = 0; i < size; ++i) {
|
2016-01-23 22:38:59 +00:00
|
|
|
Thread tid([this]() { run(); });
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!tid) {
|
2015-11-27 22:11:46 +00:00
|
|
|
return false;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2016-01-23 22:38:59 +00:00
|
|
|
thrs.push(ostd::move(tid));
|
2015-11-27 22:11:46 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroy() {
|
|
|
|
mtx.lock();
|
|
|
|
running = false;
|
|
|
|
mtx.unlock();
|
|
|
|
cond.broadcast();
|
2016-01-23 22:38:59 +00:00
|
|
|
for (Thread &tid: thrs.iter()) {
|
|
|
|
tid.join();
|
2015-11-27 22:11:46 +00:00
|
|
|
cond.broadcast();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void run() {
|
|
|
|
for (;;) {
|
2016-01-23 22:38:59 +00:00
|
|
|
UniqueLock<Mutex> l(mtx);
|
2016-07-31 23:09:29 +00:00
|
|
|
while (running && (tasks == nullptr)) {
|
2016-01-23 22:38:59 +00:00
|
|
|
cond.wait(l);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-27 22:11:46 +00:00
|
|
|
if (!running) {
|
2016-01-23 22:38:59 +00:00
|
|
|
l.unlock();
|
|
|
|
ostd::this_thread::exit();
|
2015-11-27 22:11:46 +00:00
|
|
|
}
|
|
|
|
Task *t = tasks;
|
|
|
|
tasks = t->next;
|
2016-07-31 23:09:29 +00:00
|
|
|
if (last_task == t) {
|
2015-11-27 22:11:46 +00:00
|
|
|
last_task = nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2016-01-23 22:38:59 +00:00
|
|
|
l.unlock();
|
2015-11-27 22:11:46 +00:00
|
|
|
t->cb();
|
|
|
|
delete t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void push(ostd::Function<void()> func) {
|
|
|
|
mtx.lock();
|
|
|
|
Task *t = new Task(ostd::move(func));
|
2016-07-31 23:09:29 +00:00
|
|
|
if (last_task) {
|
2015-11-27 22:11:46 +00:00
|
|
|
last_task->next = t;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-27 22:11:46 +00:00
|
|
|
last_task = t;
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!tasks) {
|
2015-11-27 22:11:46 +00:00
|
|
|
tasks = t;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-27 22:11:46 +00:00
|
|
|
cond.signal();
|
|
|
|
mtx.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2016-04-11 19:01:26 +00:00
|
|
|
struct Task {
|
|
|
|
ostd::Function<void()> cb;
|
|
|
|
Task *next = nullptr;
|
|
|
|
Task() = delete;
|
2016-07-31 23:09:29 +00:00
|
|
|
Task(Task const &) = delete;
|
2016-04-11 19:01:26 +00:00
|
|
|
Task(Task &&) = delete;
|
|
|
|
Task(ostd::Function<void()> &&cbf): cb(ostd::move(cbf)) {}
|
2016-07-31 23:09:29 +00:00
|
|
|
Task &operator=(Task const &) = delete;
|
2016-04-11 19:01:26 +00:00
|
|
|
Task &operator=(Task &&) = delete;
|
|
|
|
};
|
|
|
|
|
2016-01-23 22:38:59 +00:00
|
|
|
Condition cond;
|
2015-11-27 22:11:46 +00:00
|
|
|
Mutex mtx;
|
2016-01-23 22:38:59 +00:00
|
|
|
Vector<Thread> thrs;
|
2015-11-27 22:11:46 +00:00
|
|
|
Task *tasks;
|
|
|
|
Task *last_task;
|
2016-07-31 23:09:29 +00:00
|
|
|
bool volatile running;
|
2015-11-27 22:11:46 +00:00
|
|
|
};
|
|
|
|
|
2015-08-22 07:31:33 +00:00
|
|
|
/* check funcs */
|
2015-08-14 01:54:00 +00:00
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
static bool ob_check_ts(ConstCharRange tname, Vector<String> const &deps) {
|
2015-12-23 12:52:27 +00:00
|
|
|
auto get_ts = [](ConstCharRange fname) {
|
2015-09-04 17:59:05 +00:00
|
|
|
ostd::FileInfo fi(fname);
|
2016-07-31 23:09:29 +00:00
|
|
|
if (fi.type() != ostd::FileType::regular) {
|
2015-12-23 12:52:27 +00:00
|
|
|
return time_t(0);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-09-04 17:59:05 +00:00
|
|
|
return fi.mtime();
|
2015-08-22 07:31:33 +00:00
|
|
|
};
|
2015-09-04 18:29:51 +00:00
|
|
|
time_t tts = get_ts(tname);
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!tts) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
for (auto &dep: deps.iter()) {
|
2015-09-04 18:29:51 +00:00
|
|
|
time_t sts = get_ts(dep);
|
2016-07-31 23:09:29 +00:00
|
|
|
if (sts && (tts < sts)) {
|
|
|
|
return true;
|
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-31 13:47:39 +00:00
|
|
|
static bool ob_check_file(ConstCharRange fname) {
|
2015-08-16 00:06:42 +00:00
|
|
|
return ostd::FileStream(fname, ostd::StreamMode::read).is_open();
|
2015-08-14 01:54:00 +00:00
|
|
|
}
|
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
static bool ob_check_exec(ConstCharRange tname, Vector<String> const &deps) {
|
|
|
|
if (!ob_check_file(tname)) {
|
2015-08-16 00:06:42 +00:00
|
|
|
return true;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
for (auto &dep: deps.iter()) {
|
|
|
|
if (!ob_check_file(dep)) {
|
2015-08-16 00:06:42 +00:00
|
|
|
return true;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
}
|
2015-08-16 00:06:42 +00:00
|
|
|
return ob_check_ts(tname, deps);
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:31:33 +00:00
|
|
|
/* this lets us properly match % patterns in target names */
|
2016-07-31 23:09:29 +00:00
|
|
|
static ConstCharRange ob_compare_subst(
|
|
|
|
ConstCharRange expanded, ConstCharRange toexpand
|
|
|
|
) {
|
2015-08-14 01:54:00 +00:00
|
|
|
auto rep = ostd::find(toexpand, '%');
|
|
|
|
/* no subst found */
|
2016-07-31 23:09:29 +00:00
|
|
|
if (rep.empty()) {
|
2015-08-21 18:14:24 +00:00
|
|
|
return nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
/* get the part before % */
|
2015-09-01 17:50:00 +00:00
|
|
|
auto fp = slice_until(toexpand, rep);
|
2015-08-14 01:54:00 +00:00
|
|
|
/* part before % does not compare, so ignore */
|
2016-07-31 23:09:29 +00:00
|
|
|
if (expanded.size() <= fp.size()) {
|
2015-08-21 18:14:24 +00:00
|
|
|
return nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
if (expanded.slice(0, fp.size()) != fp) {
|
2015-08-21 18:14:24 +00:00
|
|
|
return nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
/* pop out front part */
|
2015-12-14 19:20:43 +00:00
|
|
|
expanded += fp.size();
|
2015-08-14 01:54:00 +00:00
|
|
|
/* part after % */
|
2015-12-14 19:20:43 +00:00
|
|
|
++rep;
|
2016-07-31 23:09:29 +00:00
|
|
|
if (rep.empty()) {
|
2015-08-14 01:54:00 +00:00
|
|
|
return expanded;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
/* part after % does not compare, so ignore */
|
2016-07-31 23:09:29 +00:00
|
|
|
if (expanded.size() <= rep.size()) {
|
2015-08-21 18:14:24 +00:00
|
|
|
return nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-10-02 18:25:08 +00:00
|
|
|
ostd::Size es = expanded.size();
|
2016-07-31 23:09:29 +00:00
|
|
|
if (expanded.slice(es - rep.size(), es) != rep) {
|
2015-08-21 18:14:24 +00:00
|
|
|
return nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-14 01:54:00 +00:00
|
|
|
/* cut off latter part */
|
|
|
|
expanded.pop_back_n(rep.size());
|
|
|
|
/* we got what we wanted... */
|
|
|
|
return expanded;
|
|
|
|
}
|
|
|
|
|
2015-10-26 17:58:47 +00:00
|
|
|
static ThreadPool tpool;
|
|
|
|
|
2015-12-07 21:41:37 +00:00
|
|
|
struct ObState: CsState {
|
2015-08-31 13:47:39 +00:00
|
|
|
ConstCharRange progname;
|
2015-08-24 03:54:03 +00:00
|
|
|
int jobs = 1;
|
2015-10-15 22:09:16 +00:00
|
|
|
bool ignore_env = false;
|
2015-08-21 19:02:31 +00:00
|
|
|
|
2015-10-15 22:36:39 +00:00
|
|
|
/* represents a rule definition, possibly with a function */
|
|
|
|
struct Rule {
|
|
|
|
String target;
|
|
|
|
Vector<String> deps;
|
2015-12-23 12:52:27 +00:00
|
|
|
Bytecode func;
|
2015-10-26 17:58:47 +00:00
|
|
|
bool action;
|
2015-10-15 22:36:39 +00:00
|
|
|
|
2015-12-19 15:06:11 +00:00
|
|
|
Rule(): target(), deps(), func(), action(false) {}
|
2016-07-31 23:09:29 +00:00
|
|
|
Rule(Rule const &r):
|
|
|
|
target(r.target), deps(r.deps), func(r.func), action(r.action)
|
|
|
|
{}
|
2015-10-15 22:36:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Vector<Rule> rules;
|
|
|
|
|
2015-08-22 07:31:33 +00:00
|
|
|
struct SubRule {
|
2015-08-31 13:47:39 +00:00
|
|
|
ConstCharRange sub;
|
2015-08-22 07:31:33 +00:00
|
|
|
Rule *rule;
|
|
|
|
};
|
|
|
|
|
2015-10-15 08:42:43 +00:00
|
|
|
Map<ConstCharRange, Vector<SubRule>> cache;
|
|
|
|
|
2015-10-15 22:36:39 +00:00
|
|
|
struct RuleCounter {
|
2015-11-04 17:46:01 +00:00
|
|
|
RuleCounter(): cond(), mtx(), counter(0), result(0) {}
|
2015-10-15 22:36:39 +00:00
|
|
|
|
|
|
|
void wait() {
|
2016-01-23 22:38:59 +00:00
|
|
|
UniqueLock<Mutex> l(mtx);
|
2016-07-31 23:09:29 +00:00
|
|
|
while (counter) {
|
2016-01-23 22:38:59 +00:00
|
|
|
cond.wait(l);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-10-15 22:36:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void incr() {
|
2016-01-23 22:38:59 +00:00
|
|
|
UniqueLock<Mutex> l(mtx);
|
2015-10-15 22:36:39 +00:00
|
|
|
++counter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void decr() {
|
2016-01-23 22:38:59 +00:00
|
|
|
UniqueLock<Mutex> l(mtx);
|
2015-10-15 22:36:39 +00:00
|
|
|
if (!--counter) {
|
2016-01-23 22:38:59 +00:00
|
|
|
l.unlock();
|
2015-10-15 22:36:39 +00:00
|
|
|
cond.broadcast();
|
2016-01-23 22:38:59 +00:00
|
|
|
}
|
2015-10-15 22:36:39 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 22:38:59 +00:00
|
|
|
Condition cond;
|
2015-10-15 22:36:39 +00:00
|
|
|
Mutex mtx;
|
2016-07-31 23:09:29 +00:00
|
|
|
int volatile counter;
|
2015-10-15 22:36:39 +00:00
|
|
|
ostd::AtomicInt result;
|
|
|
|
};
|
|
|
|
|
|
|
|
Vector<RuleCounter *> counters;
|
|
|
|
|
2015-11-04 17:46:01 +00:00
|
|
|
template<typename F>
|
|
|
|
int wait_result(F func) {
|
|
|
|
RuleCounter ctr;
|
|
|
|
counters.push(&ctr);
|
|
|
|
int ret = func();
|
|
|
|
counters.pop();
|
2016-07-31 23:09:29 +00:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2015-11-04 17:46:01 +00:00
|
|
|
ctr.wait();
|
|
|
|
return ctr.result;
|
|
|
|
}
|
|
|
|
|
2015-08-21 19:02:31 +00:00
|
|
|
template<typename ...A>
|
2015-08-31 13:47:39 +00:00
|
|
|
int error(int retcode, ConstCharRange fmt, A &&...args) {
|
2015-08-21 19:02:31 +00:00
|
|
|
ostd::err.write(progname, ": ");
|
|
|
|
ostd::err.writefln(fmt, ostd::forward<A>(args)...);
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
int exec_list(
|
|
|
|
Vector<SubRule> const &rlist, Vector<String> &subdeps,
|
|
|
|
ConstCharRange tname
|
|
|
|
) {
|
2015-08-31 13:47:39 +00:00
|
|
|
String repd;
|
2015-11-05 18:43:58 +00:00
|
|
|
for (auto &sr: rlist.iter()) for (auto &target: sr.rule->deps.iter()) {
|
|
|
|
ConstCharRange atgt = target.iter();
|
|
|
|
repd.clear();
|
|
|
|
auto lp = ostd::find(atgt, '%');
|
|
|
|
if (!lp.empty()) {
|
|
|
|
repd.append(slice_until(atgt, lp));
|
|
|
|
repd.append(sr.sub);
|
2015-12-23 12:52:27 +00:00
|
|
|
++lp;
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!lp.empty()) {
|
|
|
|
repd.append(lp);
|
|
|
|
}
|
2015-11-05 18:43:58 +00:00
|
|
|
atgt = repd.iter();
|
2015-08-21 19:02:31 +00:00
|
|
|
}
|
2015-11-05 18:43:58 +00:00
|
|
|
subdeps.push(atgt);
|
|
|
|
int r = exec_rule(atgt, tname);
|
2016-07-31 23:09:29 +00:00
|
|
|
if (r) {
|
|
|
|
return r;
|
|
|
|
}
|
2015-11-05 18:43:58 +00:00
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
int exec_func(ConstCharRange tname, Vector<SubRule> const &rlist) {
|
2015-08-31 13:47:39 +00:00
|
|
|
Vector<String> subdeps;
|
2015-11-04 17:46:01 +00:00
|
|
|
int ret = wait_result([&rlist, &subdeps, &tname, this]() {
|
|
|
|
return exec_list(rlist, subdeps, tname);
|
|
|
|
});
|
2015-12-23 12:52:27 +00:00
|
|
|
Bytecode *func = nullptr;
|
2015-11-21 18:30:11 +00:00
|
|
|
bool act = false;
|
2016-07-31 23:09:29 +00:00
|
|
|
for (auto &sr: rlist.iter()) {
|
|
|
|
if (sr.rule->func) {
|
|
|
|
func = &sr.rule->func;
|
|
|
|
act = sr.rule->action;
|
|
|
|
break;
|
|
|
|
}
|
2015-11-21 18:30:11 +00:00
|
|
|
}
|
|
|
|
if ((!ret && (act || ob_check_exec(tname, subdeps))) && func) {
|
|
|
|
StackedValue targetv, sourcev, sourcesv;
|
2015-12-28 15:17:20 +00:00
|
|
|
CsState &cs = *this;
|
2015-11-21 18:30:11 +00:00
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!targetv.alias(cs, "target")) {
|
2015-11-21 18:30:11 +00:00
|
|
|
return 1;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-21 18:30:11 +00:00
|
|
|
targetv.set_cstr(tname);
|
|
|
|
targetv.push();
|
|
|
|
|
2015-12-23 12:52:27 +00:00
|
|
|
if (!subdeps.empty()) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!sourcev.alias(cs, "source")) {
|
2015-11-21 18:30:11 +00:00
|
|
|
return 1;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
if (!sourcesv.alias(cs, "sources")) {
|
2015-08-21 19:02:31 +00:00
|
|
|
return 1;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-21 18:30:11 +00:00
|
|
|
|
|
|
|
sourcev.set_cstr(subdeps[0]);
|
|
|
|
sourcev.push();
|
|
|
|
|
|
|
|
auto dsv = ostd::appender<String>();
|
|
|
|
ostd::concat(dsv, subdeps);
|
2016-07-13 17:50:31 +00:00
|
|
|
sourcesv.set_str(ostd::move(dsv.get()));
|
2015-11-21 18:30:11 +00:00
|
|
|
sourcesv.push();
|
2015-08-21 19:02:31 +00:00
|
|
|
}
|
2015-11-21 18:30:11 +00:00
|
|
|
|
2015-12-19 23:21:39 +00:00
|
|
|
return run_int(*func);
|
2015-08-14 01:54:00 +00:00
|
|
|
}
|
2015-11-03 18:34:16 +00:00
|
|
|
return ret;
|
2015-08-14 01:54:00 +00:00
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
|
2015-10-26 17:58:47 +00:00
|
|
|
int exec_action(Rule *rule) {
|
2015-12-07 22:37:38 +00:00
|
|
|
return run_int(rule->func);
|
2015-10-26 17:58:47 +00:00
|
|
|
}
|
|
|
|
|
2015-10-15 08:42:43 +00:00
|
|
|
int find_rules(ConstCharRange target, Vector<SubRule> &rlist) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!rlist.empty()) {
|
2015-10-15 08:42:43 +00:00
|
|
|
return 0;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-10-03 16:25:52 +00:00
|
|
|
SubRule *frule = nullptr;
|
|
|
|
bool exact = false;
|
2015-08-21 19:02:31 +00:00
|
|
|
for (auto &rule: rules.iter()) {
|
|
|
|
if (target == rule.target) {
|
|
|
|
rlist.push().rule = &rule;
|
2015-10-03 16:25:52 +00:00
|
|
|
if (rule.func) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (frule && exact) {
|
|
|
|
return error(1, "redefinition of rule '%s'", target);
|
|
|
|
}
|
|
|
|
if (!frule) {
|
2015-10-03 16:25:52 +00:00
|
|
|
frule = &rlist.back();
|
2016-07-31 23:09:29 +00:00
|
|
|
} else {
|
2015-10-03 16:25:52 +00:00
|
|
|
*frule = rlist.back();
|
|
|
|
rlist.pop();
|
|
|
|
}
|
|
|
|
exact = true;
|
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-31 23:09:29 +00:00
|
|
|
if (exact || !rule.func) {
|
2015-10-03 16:25:52 +00:00
|
|
|
continue;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-31 13:47:39 +00:00
|
|
|
ConstCharRange sub = ob_compare_subst(target, rule.target);
|
2015-08-21 19:02:31 +00:00
|
|
|
if (!sub.empty()) {
|
|
|
|
SubRule &sr = rlist.push();
|
|
|
|
sr.rule = &rule;
|
|
|
|
sr.sub = sub;
|
2015-10-03 16:25:52 +00:00
|
|
|
if (frule) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (sub.size() == frule->sub.size()) {
|
|
|
|
return error(1, "redefinition of rule '%s'", target);
|
|
|
|
}
|
2015-10-03 16:25:52 +00:00
|
|
|
if (sub.size() < frule->sub.size()) {
|
2015-11-14 01:08:27 +00:00
|
|
|
*frule = sr;
|
|
|
|
rlist.pop();
|
2015-10-03 16:25:52 +00:00
|
|
|
}
|
2016-07-31 23:09:29 +00:00
|
|
|
} else {
|
|
|
|
frule = &sr;
|
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-15 08:42:43 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int exec_rule(ConstCharRange target, ConstCharRange from = nullptr) {
|
|
|
|
Vector<SubRule> &rlist = cache[target];
|
|
|
|
int fret = find_rules(target, rlist);
|
2016-07-31 23:09:29 +00:00
|
|
|
if (fret) {
|
2015-10-15 08:42:43 +00:00
|
|
|
return fret;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
if ((rlist.size() == 1) && rlist[0].rule->action) {
|
2015-10-26 17:58:47 +00:00
|
|
|
return exec_action(rlist[0].rule);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
if (rlist.empty() && !ob_check_file(target)) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (from.empty()) {
|
2015-08-21 19:02:31 +00:00
|
|
|
return error(1, "no rule to run target '%s'", target);
|
2016-07-31 23:09:29 +00:00
|
|
|
} else {
|
|
|
|
return error(
|
|
|
|
1, "no rule to run target '%s' (needed by '%s')",
|
|
|
|
target, from
|
|
|
|
);
|
|
|
|
}
|
2015-08-21 19:02:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return exec_func(target, rlist);
|
2015-08-16 00:06:42 +00:00
|
|
|
}
|
2015-10-15 22:36:39 +00:00
|
|
|
|
2015-10-21 20:09:21 +00:00
|
|
|
int exec_main(ConstCharRange target) {
|
2015-11-04 17:46:01 +00:00
|
|
|
return wait_result([&target, this]() { return exec_rule(target); });
|
2015-10-21 20:09:21 +00:00
|
|
|
}
|
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
void rule_add(
|
|
|
|
ConstCharRange tgt, ConstCharRange dep, Uint32 *body,
|
|
|
|
bool action = false
|
|
|
|
) {
|
2015-10-15 22:36:39 +00:00
|
|
|
auto targets = cscript::util::list_explode(tgt);
|
|
|
|
for (auto &target: targets.iter()) {
|
|
|
|
Rule &r = rules.push();
|
|
|
|
r.target = target;
|
2015-10-26 17:58:47 +00:00
|
|
|
r.action = action;
|
2015-12-19 15:06:11 +00:00
|
|
|
r.func = body;
|
2015-11-23 21:26:51 +00:00
|
|
|
r.deps = cscript::util::list_explode(dep);
|
2015-10-15 22:36:39 +00:00
|
|
|
}
|
|
|
|
}
|
2015-11-14 01:28:07 +00:00
|
|
|
|
2016-07-31 23:09:29 +00:00
|
|
|
void rule_dup(
|
|
|
|
ConstCharRange tgt, ConstCharRange ptgt, ConstCharRange dep,
|
|
|
|
bool inherit_deps
|
|
|
|
) {
|
2015-11-14 01:28:07 +00:00
|
|
|
Rule *oldr = nullptr;
|
2016-07-31 23:09:29 +00:00
|
|
|
for (auto &rule: rules.iter()) {
|
2015-12-27 17:20:47 +00:00
|
|
|
if (ptgt == rule.target) {
|
2015-11-14 01:28:07 +00:00
|
|
|
oldr = &rule;
|
2015-12-27 17:20:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
if (!oldr) {
|
2015-11-14 01:28:07 +00:00
|
|
|
return;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-14 01:28:07 +00:00
|
|
|
Rule &r = rules.push();
|
|
|
|
r.target = tgt;
|
|
|
|
r.action = oldr->action;
|
2015-12-19 15:06:11 +00:00
|
|
|
r.func = oldr->func;
|
2015-11-24 20:14:37 +00:00
|
|
|
r.deps = inherit_deps ? oldr->deps : cscript::util::list_explode(dep);
|
2015-11-14 01:28:07 +00:00
|
|
|
}
|
2015-11-25 20:36:46 +00:00
|
|
|
|
|
|
|
void register_rulecmds() {
|
2016-08-01 18:34:04 +00:00
|
|
|
add_command("rule", "sseN", [this](cscript::TvalRange args) {
|
2016-08-01 18:17:44 +00:00
|
|
|
rule_add(
|
2016-07-30 23:50:00 +00:00
|
|
|
args[0].get_strr(), args[1].get_strr(),
|
|
|
|
(args[3].get_int() > 2) ? args[2].get_code() : nullptr
|
|
|
|
);
|
2015-11-25 20:36:46 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
add_command("action", "se", [this](cscript::TvalRange args) {
|
2016-08-01 18:17:44 +00:00
|
|
|
rule_add(args[0].get_strr(), nullptr, args[1].get_code(), true);
|
2015-11-25 20:36:46 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
add_command("depend", "ss", [this](cscript::TvalRange args) {
|
2016-08-01 18:17:44 +00:00
|
|
|
rule_add(args[0].get_strr(), args[1].get_str().iter(), nullptr);
|
2015-11-25 20:36:46 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
add_command("duprule", "sssN", [this](cscript::TvalRange args) {
|
2016-08-01 18:17:44 +00:00
|
|
|
rule_dup(
|
2016-07-30 23:50:00 +00:00
|
|
|
args[0].get_strr(), args[1].get_strr(),
|
|
|
|
args[2].get_strr(), args[3].get_int() <= 2
|
|
|
|
);
|
2015-11-25 20:36:46 +00:00
|
|
|
});
|
|
|
|
}
|
2015-11-09 18:51:55 +00:00
|
|
|
|
2016-08-01 18:51:07 +00:00
|
|
|
int print_help(bool error, ConstCharRange deffile) {
|
2015-12-26 13:29:55 +00:00
|
|
|
ostd::Stream &os = error ? ostd::err : ostd::out;
|
2016-07-31 23:09:29 +00:00
|
|
|
os.writeln(
|
|
|
|
"Usage: ", progname, " [options] [action]\n",
|
|
|
|
"Options:\n"
|
|
|
|
" -C DIRECTORY\tChange to DIRECTORY before running.\n",
|
|
|
|
" -f FILE\tSpecify the file to run (default: ", deffile, ").\n"
|
|
|
|
" -h\t\tPrint this message.\n"
|
|
|
|
" -j N\t\tSpecify the number of jobs to use (default: 1).\n"
|
|
|
|
" -e STR\tEvaluate a string instead of a file.\n"
|
|
|
|
" -E\t\tIgnore environment variables."
|
|
|
|
);
|
2015-12-26 13:29:55 +00:00
|
|
|
return error;
|
2015-12-03 19:09:44 +00:00
|
|
|
}
|
|
|
|
};
|
2015-08-24 03:54:03 +00:00
|
|
|
|
2015-08-14 01:54:00 +00:00
|
|
|
int main(int argc, char **argv) {
|
2016-08-01 18:17:44 +00:00
|
|
|
ObState os;
|
2015-08-31 13:47:39 +00:00
|
|
|
ConstCharRange pn = argv[0];
|
|
|
|
ConstCharRange lslash = ostd::find_last(pn, '/');
|
2016-08-01 18:17:44 +00:00
|
|
|
os.progname = lslash.empty() ? pn : (lslash + 1);
|
2015-08-16 00:06:42 +00:00
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
cscript::init_libs(os);
|
2015-08-16 00:06:42 +00:00
|
|
|
|
2016-01-26 19:02:32 +00:00
|
|
|
int ncpus = ostd::Thread::hardware_concurrency();
|
2016-08-01 18:17:44 +00:00
|
|
|
os.add_ident(cscript::ID_VAR, "numcpus", 4096, 1, &ncpus);
|
|
|
|
os.add_ident(cscript::ID_VAR, "numjobs", 4096, 1, &os.jobs);
|
2015-09-26 14:13:17 +00:00
|
|
|
|
2015-09-20 19:54:19 +00:00
|
|
|
ConstCharRange fcont;
|
2016-08-01 18:51:07 +00:00
|
|
|
ConstCharRange deffile = "obuild.cfg";
|
2015-08-24 03:54:03 +00:00
|
|
|
|
2015-11-30 21:14:59 +00:00
|
|
|
int posarg = argc;
|
2016-07-31 23:09:29 +00:00
|
|
|
for (int i = 1; i < argc; ++i) {
|
|
|
|
if (argv[i][0] == '-') {
|
|
|
|
char argn = argv[i][1];
|
|
|
|
if (argn == 'E') {
|
2016-08-01 18:17:44 +00:00
|
|
|
os.ignore_env = true;
|
2016-07-31 23:09:29 +00:00
|
|
|
continue;
|
|
|
|
} else if ((argn == 'h') || (!argv[i][2] && ((i + 1) >= argc))) {
|
2016-08-01 18:51:07 +00:00
|
|
|
return os.print_help(argn != 'h', deffile);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
ConstCharRange val = (argv[i][2] == '\0') ? argv[++i] : &argv[i][2];
|
|
|
|
switch (argn) {
|
|
|
|
case 'C':
|
|
|
|
if (!ostd::directory_change(val)) {
|
2016-08-01 18:17:44 +00:00
|
|
|
return os.error(1, "failed changing directory: %s", val);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
deffile = val;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
fcont = val;
|
|
|
|
break;
|
|
|
|
case 'j': {
|
|
|
|
int ival = atoi(val.data());
|
|
|
|
if (!ival) {
|
|
|
|
ival = ncpus;
|
|
|
|
}
|
2016-08-01 18:17:44 +00:00
|
|
|
os.jobs = ostd::max(1, ival);
|
2016-07-31 23:09:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2016-08-01 18:51:07 +00:00
|
|
|
return os.print_help(true, deffile);
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
posarg = i;
|
2015-08-24 03:54:03 +00:00
|
|
|
break;
|
2015-09-26 14:13:17 +00:00
|
|
|
}
|
2015-08-24 03:54:03 +00:00
|
|
|
}
|
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
tpool.init(os.jobs);
|
2015-08-24 18:16:55 +00:00
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
os.register_rulecmds();
|
2015-11-25 20:36:46 +00:00
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
os.add_command("shell", "C", [&os](TvalRange args) {
|
2015-12-08 21:36:55 +00:00
|
|
|
auto cnt = os.counters.back();
|
2015-08-24 18:16:55 +00:00
|
|
|
cnt->incr();
|
2016-07-31 23:34:26 +00:00
|
|
|
tpool.push([cnt, ds = String(args[0].get_strr())]() {
|
2015-11-01 18:45:03 +00:00
|
|
|
int ret = system(ds.data());
|
2016-07-31 23:09:29 +00:00
|
|
|
if (ret && !cnt->result) {
|
2015-08-24 18:16:55 +00:00
|
|
|
cnt->result = ret;
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-24 18:16:55 +00:00
|
|
|
cnt->decr();
|
|
|
|
});
|
2016-08-01 18:34:04 +00:00
|
|
|
os.result->set_int(0);
|
2015-08-14 01:54:00 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
os.add_command("getenv", "ss", [&os](TvalRange args) {
|
2015-12-08 21:36:55 +00:00
|
|
|
if (os.ignore_env) {
|
2016-08-01 18:34:04 +00:00
|
|
|
os.result->set_cstr("");
|
2015-09-21 19:44:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-08-01 18:34:04 +00:00
|
|
|
os.result->set_str(ostd::move(
|
2016-07-31 23:09:29 +00:00
|
|
|
ostd::env_get(args[0].get_str()).value_or(args[1].get_str())
|
|
|
|
));
|
2015-09-21 19:44:48 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
os.add_command("extreplace", "sss", [&os](TvalRange args) {
|
2016-07-31 23:16:22 +00:00
|
|
|
ConstCharRange lst = args[0].get_strr();
|
|
|
|
ConstCharRange oldext = args[1].get_strr();
|
|
|
|
ConstCharRange newext = args[2].get_strr();
|
2015-11-07 16:57:29 +00:00
|
|
|
String ret;
|
2016-07-31 23:16:22 +00:00
|
|
|
if (oldext.front() == '.') {
|
|
|
|
oldext.pop_front();
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2016-07-31 23:16:22 +00:00
|
|
|
if (newext.front() == '.') {
|
|
|
|
newext.pop_front();
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-11-07 16:57:29 +00:00
|
|
|
auto fnames = cscript::util::list_explode(lst);
|
|
|
|
for (ConstCharRange it: fnames.iter()) {
|
2016-07-31 23:09:29 +00:00
|
|
|
if (!ret.empty()) {
|
|
|
|
ret += ' ';
|
|
|
|
}
|
2015-11-07 16:57:29 +00:00
|
|
|
auto dot = ostd::find_last(it, '.');
|
|
|
|
if (!dot.empty() && ((dot + 1) == oldext)) {
|
|
|
|
ret += ostd::slice_until(it, dot);
|
|
|
|
ret += '.';
|
|
|
|
ret += newext;
|
|
|
|
} else {
|
|
|
|
ret += it;
|
|
|
|
}
|
|
|
|
}
|
2016-08-01 18:34:04 +00:00
|
|
|
os.result->set_str(ostd::move(ret));
|
2015-11-07 16:57:29 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:34:04 +00:00
|
|
|
os.add_command("invoke", "s", [&os](TvalRange args) {
|
|
|
|
os.result->set_int(os.exec_main(args[0].get_strr()));
|
2015-10-29 17:34:33 +00:00
|
|
|
});
|
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
cs_register_globs(os);
|
2015-08-23 08:03:30 +00:00
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
if ((!fcont.empty() && !os.run_bool(fcont)) || !os.run_file(deffile)) {
|
|
|
|
return os.error(1, "failed creating rules");
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-16 00:06:42 +00:00
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
if (os.rules.empty()) {
|
|
|
|
return os.error(1, "no targets");
|
2016-07-31 23:09:29 +00:00
|
|
|
}
|
2015-08-16 00:06:42 +00:00
|
|
|
|
2016-08-01 18:17:44 +00:00
|
|
|
return os.exec_main((posarg < argc) ? argv[posarg] : "default");
|
2016-02-07 21:20:28 +00:00
|
|
|
}
|