restructure octabuild

master
Daniel Kolesa 2018-04-24 01:50:55 +02:00
parent 4ee9ef89ea
commit bd3176cbbd
1 changed files with 163 additions and 151 deletions

314
main.cc
View File

@ -27,165 +27,86 @@ using cscript::cs_bcode;
namespace fs = ostd::fs;
namespace build = ostd::build;
struct ob_state: cs_state {
void rule_add(
build::make &mk, string_range tgt, string_range dep, cs_bcode *body,
bool action = false
) {
cscript::util::ListParser p{*this, tgt};
while (p.parse()) {
auto &rl = mk.rule(p.get_item()).action(action);
cscript::util::ListParser lp{*this, dep};
while (lp.parse()) {
rl.depend(lp.get_item());
}
if (cscript::cs_code_is_empty(body)) {
continue;
}
rl.body([body = cs_bcode_ref(body), this](auto tgt, auto srcs) {
cs_stacked_value targetv, sourcev, sourcesv;
static void rule_add(
cs_state &cs, build::make &mk,
string_range target, string_range depends,
cs_bcode *body, bool action = false
) {
cscript::util::ListParser p{cs, target};
while (p.parse()) {
auto &rl = mk.rule(p.get_item()).action(action);
cscript::util::ListParser lp{cs, depends};
while (lp.parse()) {
rl.depend(lp.get_item());
}
if (cscript::cs_code_is_empty(body)) {
continue;
}
rl.body([body = cs_bcode_ref(body), &cs](auto tgt, auto srcs) {
cs_stacked_value targetv, sourcev, sourcesv;
if (!targetv.set_alias(new_ident("target"))) {
if (!targetv.set_alias(cs.new_ident("target"))) {
throw build::make_error{
"internal error: could not set alias 'target'"
};
}
targetv.set_cstr(tgt);
targetv.push();
if (!srcs.empty()) {
if (!sourcev.set_alias(cs.new_ident("source"))) {
throw build::make_error{
"internal error: could not set alias 'target'"
"internal error: could not set alias 'source'"
};
}
targetv.set_cstr(tgt);
targetv.push();
if (!srcs.empty()) {
if (!sourcev.set_alias(new_ident("source"))) {
throw build::make_error{
"internal error: could not set alias 'source'"
};
}
if (!sourcesv.set_alias(new_ident("sources"))) {
throw build::make_error{
"internal error: could not set alias 'sources'"
};
}
sourcev.set_cstr(srcs[0]);
sourcev.push();
auto dsv = ostd::appender<std::string>();
ostd::format(dsv, "%(%s %)", srcs);
sourcesv.set_str(std::move(dsv.get()));
sourcesv.push();
if (!sourcesv.set_alias(cs.new_ident("sources"))) {
throw build::make_error{
"internal error: could not set alias 'sources'"
};
}
try {
this->run(body);
} catch (cscript::cs_error const &e) {
throw build::make_error{e.what()};
}
});
}
}
sourcev.set_cstr(srcs[0]);
sourcev.push();
void register_rulecmds(build::make &mk) {
new_command("rule", "sse", [this, &mk](auto &, auto args, auto &) {
this->rule_add(
mk, args[0].get_strr(), args[1].get_strr(), args[2].get_code()
);
auto dsv = ostd::appender<std::string>();
ostd::format(dsv, "%(%s %)", srcs);
sourcesv.set_str(std::move(dsv.get()));
sourcesv.push();
}
try {
cs.run(body);
} catch (cscript::cs_error const &e) {
throw build::make_error{e.what()};
}
});
new_command("action", "se", [this, &mk](auto &, auto args, auto &) {
this->rule_add(
mk, args[0].get_strr(), nullptr, args[1].get_code(), true
);
});
new_command("depend", "ss", [this, &mk](auto &, auto args, auto &) {
this->rule_add(mk, args[0].get_strr(), args[1].get_strr(), nullptr);
});
}
};
}
void do_main(int argc, char **argv) {
ob_state os;
os.init_libs();
static void init_rulelib(cs_state &cs, build::make &mk) {
cs.new_command("rule", "sse", [&cs, &mk](auto &, auto args, auto &) {
rule_add(
cs, mk, args[0].get_strr(), args[1].get_strr(), args[2].get_code()
);
});
bool ignore_env = false;
cs.new_command("action", "se", [&cs, &mk](auto &, auto args, auto &) {
rule_add(
cs, mk, args[0].get_strr(), nullptr, args[1].get_code(), true
);
});
int ncpus = std::thread::hardware_concurrency();
os.new_ivar("numcpus", 4096, 1, ncpus);
cs.new_command("depend", "ss", [&cs, &mk](auto &, auto args, auto &) {
rule_add(cs, mk, args[0].get_strr(), args[1].get_strr(), nullptr);
});
}
ostd::arg_parser ap;
auto &help = ap.add_optional("-h", "--help", 0)
.help("print this message and exit")
.action(ostd::arg_print_help(ap));
int jobs = 1;
ap.add_optional("-j", "--jobs", 1)
.help("specify the number of jobs to use (default: 1)")
.action(ostd::arg_store_format("%d", jobs));
std::string curdir;
ap.add_optional("-C", "--change-directory", 1)
.help("change to DIRECTORY before running")
.metavar("DIRECTORY")
.action(ostd::arg_store_str(curdir));
std::string deffile = "obuild.cfg";
ap.add_optional("-f", "--file", 1)
.help("specify the file to run (default: obuild.cfg)")
.action(ostd::arg_store_str(deffile));
std::string fcont;
ap.add_optional("-e", "--execute", 1)
.help("evaluate a string instead of a file")
.metavar("STR")
.action(ostd::arg_store_str(fcont));
ap.add_optional("-E", "--ignore-env", 0)
.help("ignore environment variables")
.action(ostd::arg_store_true(ignore_env));
std::string action = "default";
ap.add_positional("action", ostd::arg_value::OPTIONAL)
.help("the action to perform")
.action(ostd::arg_store_str(action));
try {
ap.parse(argc, argv);
} catch (ostd::arg_error const &e) {
ostd::cerr.writefln("%s: %s", argv[0], e.what());
ap.print_help(ostd::cerr.iter());
throw build::make_error{""};
}
if (help.used()) {
return;
}
if (!jobs) {
jobs = ncpus;
}
jobs = std::max(1, jobs);
try {
if (!curdir.empty()) {
fs::current_path(curdir);
}
} catch (fs::fs_error const &e) {
throw build::make_error{
"failed changing directory: %s (0s)", curdir, e.what()
};
}
os.new_ivar("numjobs", 4096, 1, jobs);
build::make mk{build::make_task_simple, jobs};
os.register_rulecmds(mk);
os.new_command("echo", "C", [](auto &, auto args, auto &) {
static void init_baselib(cs_state &cs, build::make &mk, bool ignore_env) {
cs.new_command("echo", "C", [](auto &, auto args, auto &) {
writeln(args[0].get_strr());
});
os.new_command("shell", "C", [&mk](auto &, auto args, auto &) {
cs.new_command("shell", "C", [&mk](auto &, auto args, auto &) {
mk.push_task([ds = std::string(args[0].get_strr())]() {
if (system(ds.data())) {
throw build::make_error{""};
@ -193,7 +114,7 @@ void do_main(int argc, char **argv) {
});
});
os.new_command("getenv", "ss", [ignore_env](auto &, auto args, auto &res) {
cs.new_command("getenv", "ss", [ignore_env](auto &, auto args, auto &res) {
if (ignore_env) {
res.set_cstr("");
return;
@ -203,7 +124,13 @@ void do_main(int argc, char **argv) {
));
});
os.new_command("extreplace", "sss", [](auto &cs, auto args, auto &res) {
cs.new_command("invoke", "s", [&mk](auto &, auto args, auto &) {
mk.exec(args[0].get_strr());
});
}
static void init_pathlib(cs_state &cs) {
cs.new_command("extreplace", "sss", [](auto &cs, auto args, auto &res) {
string_range lst = args[0].get_strr();
string_range oldext = args[1].get_strr();
string_range newext = args[2].get_strr();
@ -233,11 +160,7 @@ void do_main(int argc, char **argv) {
res.set_str(std::move(ret));
});
os.new_command("invoke", "s", [&mk](auto &, auto args, auto &) {
mk.exec(args[0].get_strr());
});
os.new_command("glob", "C", [](auto &cs, auto args, auto &res) {
cs.new_command("glob", "C", [](auto &cs, auto args, auto &res) {
auto ret = ostd::appender<std::string>();
auto app = ostd::appender<std::vector<path>>();
cscript::util::ListParser p{cs, args[0].get_strr()};
@ -247,11 +170,100 @@ void do_main(int argc, char **argv) {
ostd::format(ret, "%(%s %)", app.get());
res.set_str(std::move(ret.get()));
});
}
if ((!fcont.empty() && !os.run_bool(fcont)) || !os.run_file(deffile)) {
void do_main(int argc, char **argv) {
/* cubescript interpreter */
cs_state cs;
cs.init_libs();
/* arg values */
std::string action = "default";
std::string deffile = "obuild.cfg";
std::string curdir;
std::string fcont;
bool ignore_env = false;
int jobs = 1;
/* input options */
{
ostd::arg_parser ap;
auto &help = ap.add_optional("-h", "--help", 0)
.help("print this message and exit")
.action(ostd::arg_print_help(ap));
ap.add_optional("-j", "--jobs", 1)
.help("specify the number of jobs to use (default: 1)")
.action(ostd::arg_store_format("%d", jobs));
ap.add_optional("-C", "--change-directory", 1)
.help("change to DIRECTORY before running")
.metavar("DIRECTORY")
.action(ostd::arg_store_str(curdir));
ap.add_optional("-f", "--file", 1)
.help("specify the file to run (default: obuild.cfg)")
.action(ostd::arg_store_str(deffile));
ap.add_optional("-e", "--execute", 1)
.help("evaluate a string instead of a file")
.metavar("STR")
.action(ostd::arg_store_str(fcont));
ap.add_optional("-E", "--ignore-env", 0)
.help("ignore environment variables")
.action(ostd::arg_store_true(ignore_env));
ap.add_positional("action", ostd::arg_value::OPTIONAL)
.help("the action to perform")
.action(ostd::arg_store_str(action));
try {
ap.parse(argc, argv);
} catch (ostd::arg_error const &e) {
ostd::cerr.writefln("%s: %s", argv[0], e.what());
ap.print_help(ostd::cerr.iter());
throw build::make_error{""};
}
if (help.used()) {
return;
}
}
int ncpus = std::thread::hardware_concurrency();
jobs = std::max(1, jobs ? jobs : ncpus);
/* core cubescript variables */
cs.new_ivar("numcpus", 4096, 1, ncpus);
cs.new_ivar("numjobs", 4096, 1, jobs);
/* switch to target directory */
try {
if (!curdir.empty()) {
fs::current_path(curdir);
}
} catch (fs::fs_error const &e) {
throw build::make_error{
"failed changing directory: %s (%s)", curdir, e.what()
};
}
/* init buildsystem, use simple tasks, cubescript cannot into coroutines */
build::make mk{build::make_task_simple, jobs};
/* octabuild cubescript libs */
init_rulelib(cs, mk);
init_baselib(cs, mk, ignore_env);
init_pathlib(cs);
/* parse rules */
if ((!fcont.empty() && !cs.run_bool(fcont)) || !cs.run_file(deffile)) {
throw build::make_error{"failed creating rules"};
}
/* make */
mk.exec(action);
}