forked from OctaForge/OctaBuild
Compare commits
4 Commits
Author | SHA1 | Date |
---|---|---|
Daniel Kolesa | 4af8dc8e25 | |
Daniel Kolesa | 57fef39b5e | |
Daniel Kolesa | 1a6b137935 | |
Daniel Kolesa | 876250f0c8 |
35
COPYING.md
35
COPYING.md
|
@ -1,14 +1,7 @@
|
||||||
OctaBuild is licensed under the University of Illinois/NCSA Open Source License,
|
Copyright (c) 2015-2020 Daniel "q66" Kolesa. All rights reserved.
|
||||||
a permissive, non-copyleft, BSD style license. The license text goes as follows:
|
|
||||||
|
|
||||||
Copyright (c) 2015 Daniel "q66" Kolesa. All rights reserved.
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal with
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice,
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
this list of conditions and the following disclaimers.
|
this list of conditions and the following disclaimers.
|
||||||
|
@ -17,14 +10,14 @@ so, subject to the following conditions:
|
||||||
this list of conditions and the following disclaimers in the
|
this list of conditions and the following disclaimers in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
* Neither the names of OctaSTD developers nor any contributors may be
|
**THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
used to endorse or promote products derived from this Software without
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
specific prior written permission.
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||||
SOFTWARE.**
|
THE POSSIBILITY OF SUCH DAMAGE.**
|
||||||
|
|
198
main.cc
198
main.cc
|
@ -11,130 +11,124 @@
|
||||||
#include <ostd/argparse.hh>
|
#include <ostd/argparse.hh>
|
||||||
|
|
||||||
#include <ostd/build/make.hh>
|
#include <ostd/build/make.hh>
|
||||||
|
#include <ostd/build/make_coroutine.hh>
|
||||||
|
|
||||||
#include <cubescript/cubescript.hh>
|
#include <cubescript/cubescript.hh>
|
||||||
|
|
||||||
using ostd::string_range;
|
namespace cs = cubescript;
|
||||||
using ostd::path;
|
|
||||||
|
|
||||||
using cscript::cs_state;
|
|
||||||
using cscript::cs_value_r;
|
|
||||||
using cscript::cs_value;
|
|
||||||
using cscript::cs_stacked_value;
|
|
||||||
using cscript::cs_bcode_ref;
|
|
||||||
using cscript::cs_bcode;
|
|
||||||
using cscript::util::list_parser;
|
|
||||||
|
|
||||||
namespace fs = ostd::fs;
|
namespace fs = ostd::fs;
|
||||||
namespace build = ostd::build;
|
namespace build = ostd::build;
|
||||||
|
|
||||||
static void rule_add(
|
static void rule_add(
|
||||||
cs_state &cs, build::make &mk,
|
cs::state &cs, build::make &mk,
|
||||||
string_range target, string_range depends,
|
std::string_view target, std::string_view depends,
|
||||||
cs_bcode *body, bool action = false
|
cs::bcode_ref body, bool action = false
|
||||||
) {
|
) {
|
||||||
build::make_rule::body_func bodyf{};
|
build::make_rule::body_func bodyf{};
|
||||||
if (!cscript::cs_code_is_empty(body)) {
|
if (!body.empty()) {
|
||||||
bodyf = [body = cs_bcode_ref(body), &cs](auto tgt, auto srcs) {
|
bodyf = [body, &cs](auto tgt, auto srcs) {
|
||||||
cs_stacked_value targetv, sourcev, sourcesv;
|
auto ts = cs.new_thread();
|
||||||
|
cs::alias_local target{ts, "target"};
|
||||||
|
cs::alias_local source{ts, "source"};
|
||||||
|
cs::alias_local sources{ts, "sources"};
|
||||||
|
|
||||||
if (!targetv.set_alias(cs.new_ident("target"))) {
|
cs::any_value idv{};
|
||||||
throw build::make_error{
|
idv.set_string(tgt, ts);
|
||||||
"internal error: could not set alias 'target'"
|
target.set(std::move(idv));
|
||||||
};
|
|
||||||
}
|
|
||||||
targetv.set_cstr(tgt);
|
|
||||||
targetv.push();
|
|
||||||
|
|
||||||
if (!srcs.empty()) {
|
if (!srcs.empty()) {
|
||||||
if (!sourcev.set_alias(cs.new_ident("source"))) {
|
|
||||||
throw build::make_error{
|
|
||||||
"internal error: could not set alias 'source'"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!sourcesv.set_alias(cs.new_ident("sources"))) {
|
|
||||||
throw build::make_error{
|
|
||||||
"internal error: could not set alias 'sources'"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sourcev.set_cstr(srcs[0]);
|
idv.set_string(srcs[0], ts);
|
||||||
sourcev.push();
|
source.set(std::move(idv));
|
||||||
|
|
||||||
auto dsv = ostd::appender<std::string>();
|
auto dsv = ostd::appender<std::string>();
|
||||||
ostd::format(dsv, "%(%s %)", srcs);
|
ostd::format(dsv, "%(%s %)", srcs);
|
||||||
sourcesv.set_str(std::move(dsv.get()));
|
idv.set_string(dsv.get(), cs);
|
||||||
sourcesv.push();
|
sources.set(std::move(idv));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cs.run(body);
|
body.call(ts);
|
||||||
} catch (cscript::cs_error const &e) {
|
} catch (cs::error const &e) {
|
||||||
throw build::make_error{e.what()};
|
throw build::make_error{e.what()};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
list_parser p{cs, target};
|
cs::list_parser p{cs, target};
|
||||||
for (auto tr: p.iter()) {
|
while (p.parse()) {
|
||||||
list_parser lp{cs, depends};
|
cs::list_parser lp{cs, depends};
|
||||||
mk.rule(tr).action(action).body(bodyf).depend(lp.iter());
|
auto &r = mk.rule(
|
||||||
|
std::string_view{p.get_item()}
|
||||||
|
).action(action).body(bodyf);
|
||||||
|
while (lp.parse()) {
|
||||||
|
r.depend(std::string_view{lp.get_item()});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_rulelib(cs_state &cs, build::make &mk) {
|
static void init_rulelib(cs::state &s, build::make &mk) {
|
||||||
cs.new_command("rule", "sse", [&cs, &mk](auto &, auto args, auto &) {
|
s.new_command("rule", "ssb", [&mk](auto &css, auto args, auto &) {
|
||||||
rule_add(
|
rule_add(
|
||||||
cs, mk, args[0].get_strr(), args[1].get_strr(), args[2].get_code()
|
css, mk, args[0].get_string(css),
|
||||||
|
args[1].get_string(css), args[2].get_code()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("action", "se", [&cs, &mk](auto &, auto args, auto &) {
|
s.new_command("action", "sb", [&mk](auto &css, auto args, auto &) {
|
||||||
rule_add(
|
rule_add(
|
||||||
cs, mk, args[0].get_strr(), nullptr, args[1].get_code(), true
|
css, mk, args[0].get_string(css), std::string_view{},
|
||||||
|
args[1].get_code(), true
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("depend", "ss", [&cs, &mk](auto &, auto args, auto &) {
|
s.new_command("depend", "ss", [&mk](auto &css, auto args, auto &) {
|
||||||
rule_add(cs, mk, args[0].get_strr(), args[1].get_strr(), nullptr);
|
rule_add(
|
||||||
|
css, mk, args[0].get_string(css), args[1].get_string(css),
|
||||||
|
cs::bcode_ref{}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_baselib(cs_state &cs, build::make &mk, bool ignore_env) {
|
static void init_baselib(cs::state &s, build::make &mk, bool ignore_env) {
|
||||||
cs.new_command("echo", "C", [](auto &, auto args, auto &) {
|
s.new_command("echo", "...", [](auto &css, auto args, auto &) {
|
||||||
writeln(args[0].get_strr());
|
ostd::writeln(cs::concat_values(css, args, " ").view());
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("shell", "C", [&mk](auto &, auto args, auto &) {
|
s.new_command("shell", "...", [&mk](auto &css, auto args, auto &) {
|
||||||
mk.push_task([ds = std::string(args[0].get_strr())]() {
|
mk.push_task([
|
||||||
|
ds = std::string{cs::concat_values(css, args, " ").view()}
|
||||||
|
]() {
|
||||||
if (system(ds.data())) {
|
if (system(ds.data())) {
|
||||||
throw build::make_error{""};
|
throw build::make_error{""};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("getenv", "ss", [ignore_env](auto &, auto args, auto &res) {
|
s.new_command("getenv", "ss", [ignore_env](auto &css, auto args, auto &res) {
|
||||||
if (ignore_env) {
|
if (ignore_env) {
|
||||||
res.set_cstr("");
|
res.set_string("", css);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.set_str(std::move(
|
res.set_string(ostd::env_get(
|
||||||
ostd::env_get(args[0].get_str()).value_or(args[1].get_str())
|
std::string_view{args[0].get_string(css)}
|
||||||
));
|
).value_or(
|
||||||
|
std::string{std::string_view{args[1].get_string(css)}}
|
||||||
|
), css);
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("invoke", "s", [&mk](auto &, auto args, auto &) {
|
s.new_command("invoke", "s", [&mk](auto &css, auto args, auto &) {
|
||||||
mk.exec(args[0].get_strr());
|
mk.exec(std::string_view{args[0].get_string(css)});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_pathlib(cs_state &cs) {
|
static void init_pathlib(cs::state &s) {
|
||||||
cs.new_command("extreplace", "sss", [](auto &cs, auto args, auto &res) {
|
s.new_command("extreplace", "sss", [](auto &css, auto args, auto &res) {
|
||||||
string_range oldext = args[1].get_strr();
|
ostd::string_range oldext = std::string_view{args[1].get_string(css)};
|
||||||
string_range newext = args[2].get_strr();
|
ostd::string_range newext = std::string_view{args[2].get_string(css)};
|
||||||
std::string ret;
|
std::string ret;
|
||||||
list_parser p{cs, args[0].get_strr()};
|
cs::list_parser p{css, args[0].get_string(css)};
|
||||||
for (auto ps: p.iter()) {
|
while (p.parse()) {
|
||||||
ostd::path np{ps};
|
ostd::path np{std::string_view{p.get_item()}};
|
||||||
if (!ret.empty()) {
|
if (!ret.empty()) {
|
||||||
ret += ' ';
|
ret += ' ';
|
||||||
}
|
}
|
||||||
|
@ -142,25 +136,51 @@ static void init_pathlib(cs_state &cs) {
|
||||||
(np.suffixes() == oldext) ? np.with_suffixes(newext) : np
|
(np.suffixes() == oldext) ? np.with_suffixes(newext) : np
|
||||||
).string();
|
).string();
|
||||||
}
|
}
|
||||||
res.set_str(std::move(ret));
|
res.set_string(ret, css);
|
||||||
});
|
});
|
||||||
|
|
||||||
cs.new_command("glob", "C", [](auto &cs, auto args, auto &res) {
|
s.new_command("glob", "...", [](auto &css, auto args, auto &res) {
|
||||||
auto app = ostd::appender<std::vector<path>>();
|
auto app = ostd::appender<std::vector<ostd::path>>();
|
||||||
list_parser p{cs, args[0].get_strr()};
|
cs::list_parser p{css, cs::concat_values(css, args, " ")};
|
||||||
for (auto ps: p.iter()) {
|
while (p.parse()) {
|
||||||
fs::glob_match(app, ps);
|
auto it = p.get_item();
|
||||||
|
fs::glob_match(app, std::string_view{it});
|
||||||
}
|
}
|
||||||
res.set_str(ostd::format(
|
res.set_string(ostd::format(
|
||||||
ostd::appender<std::string>(), "%(%s %)", app.get()
|
ostd::appender<std::string>(), "%(%s %)", app.get()
|
||||||
).get());
|
).get(), css);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool do_run_file(cs::state &s, std::string_view fname) {
|
||||||
|
ostd::file_stream f{fname};
|
||||||
|
if (!f.is_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.seek(0, ostd::stream_seek::END);
|
||||||
|
auto len = f.tell();
|
||||||
|
f.seek(0);
|
||||||
|
|
||||||
|
auto buf = std::make_unique<char[]>(len + 1);
|
||||||
|
if (!buf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.read_bytes(buf.get(), len) != std::size_t(len)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
|
||||||
|
s.compile(std::string_view{buf.get(), std::size_t(len)}, fname).call(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void do_main(int argc, char **argv) {
|
void do_main(int argc, char **argv) {
|
||||||
/* cubescript interpreter */
|
/* cubescript interpreter */
|
||||||
cs_state cs;
|
cs::state s;
|
||||||
cs.init_libs();
|
cs::std_init_all(s);
|
||||||
|
|
||||||
/* arg values */
|
/* arg values */
|
||||||
std::string action = "default";
|
std::string action = "default";
|
||||||
|
@ -221,8 +241,8 @@ void do_main(int argc, char **argv) {
|
||||||
jobs = std::max(1, jobs ? jobs : ncpus);
|
jobs = std::max(1, jobs ? jobs : ncpus);
|
||||||
|
|
||||||
/* core cubescript variables */
|
/* core cubescript variables */
|
||||||
cs.new_ivar("numcpus", 4096, 1, ncpus);
|
s.new_var("numcpus", ncpus, true);
|
||||||
cs.new_ivar("numjobs", 4096, 1, jobs);
|
s.new_var("numjobs", jobs, true);
|
||||||
|
|
||||||
/* switch to target directory */
|
/* switch to target directory */
|
||||||
try {
|
try {
|
||||||
|
@ -235,16 +255,18 @@ void do_main(int argc, char **argv) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init buildsystem, use simple tasks, cubescript cannot into coroutines */
|
/* init buildsystem, use coroutine tasks */
|
||||||
build::make mk{build::make_task_simple, jobs};
|
build::make mk{build::make_task_coroutine, jobs};
|
||||||
|
|
||||||
/* octabuild cubescript libs */
|
/* octabuild cubescript libs */
|
||||||
init_rulelib(cs, mk);
|
init_rulelib(s, mk);
|
||||||
init_baselib(cs, mk, ignore_env);
|
init_baselib(s, mk, ignore_env);
|
||||||
init_pathlib(cs);
|
init_pathlib(s);
|
||||||
|
|
||||||
/* parse rules */
|
/* parse rules */
|
||||||
if ((!fcont.empty() && !cs.run_bool(fcont)) || !cs.run_file(deffile)) {
|
if ((
|
||||||
|
!fcont.empty() && !s.compile(fcont).call(s).get_bool()
|
||||||
|
) || !do_run_file(s, deffile)) {
|
||||||
throw build::make_error{"failed creating rules"};
|
throw build::make_error{"failed creating rules"};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,6 @@ action clean [
|
||||||
shell rm -f $FILES obuild_ob
|
shell rm -f $FILES obuild_ob
|
||||||
]
|
]
|
||||||
|
|
||||||
depend main_ob.o [tpool.hh @CS_PATH/include/cubescript/cubescript.hh]
|
depend main_ob.o [@CS_PATH/include/cubescript/cubescript.hh]
|
||||||
|
|
||||||
rule default obuild
|
rule default obuild
|
||||||
|
|
Loading…
Reference in New Issue