hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit e3a8a3608adf0efd91a54165cc0ed2f0dbfdf7e8
parent 680ad341ca06ba932ac1442eab68004c196e28fc
Author: grobe0ba <grobe0ba@tcp80.org>
Date:   Wed, 31 Aug 2022 18:53:45 -0500

cmd/hare: accept build arguments from environment

Signed-off-by: grobe0ba <grobe0ba@tcp80.org>

Diffstat:
Mcmd/hare/plan.ha | 8++++++++
Mcmd/hare/schedule.ha | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 83 insertions(+), 21 deletions(-)

diff --git a/cmd/hare/plan.ha b/cmd/hare/plan.ha @@ -102,6 +102,14 @@ fn mkplan( break; }; + ar_tool.0 = target.ar_cmd; + as_tool.0 = target.as_cmd; + ld_tool.0 = if (len(libs) > 0) { + yield target.cc_cmd; + } else { + yield target.ld_cmd; + }; + return plan { context = ctx, target = target, diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha @@ -14,9 +14,63 @@ use hash::fnv; use hash; use os; use path; +use shlex; use strings; use strio; +fn getenv(var: str) []str = { + let vals: []str = []; + match(os::getenv(var)) { + case let val: str => + if(len(val) > 0) { + match(shlex::split(val)) { + case let val: []str => + for(let i = 0z; i < len(val); i += 1) { + append(vals, val[i]); + }; + case shlex::syntaxerr => void; + }; + }; + case void => void; + }; + + return vals; +}; + +// (executable name, executable variable, flags variable) +type tool = (str, str, str); + +let ld_tool: tool = ("", "LD", "LDFLAGS"); +let as_tool: tool = ("", "AS", "ASFLAGS"); +let ar_tool: tool = ("", "AR", "ARFLAGS"); +let qbe_tool: tool = ("qbe", "QBE", "QBEFLAGS"); + +fn getcmd(tool: *tool, args: str...) []str = { + let execargs: []str = []; + + let vals = getenv(tool.1); + defer free(vals); + if (len(vals) == 0) { + append(execargs, tool.0); + } else { + for(let i = 0z; i < len(vals); i += 1) { + append(execargs, vals[i]); + }; + }; + + let vals = getenv(tool.2); + defer free(vals); + for (let i = 0z; i < len(vals); i += 1) { + append(execargs, vals[i]); + }; + + for(let i = 0z; i < len(args); i += 1) { + append(execargs, args[i]); + }; + + return execargs; +}; + fn ident_hash(ident: ast::ident) u32 = { let hash = fnv::fnv32(); for (let i = 0z; i < len(ident); i += 1) { @@ -66,27 +120,18 @@ fn sched_module(plan: *plan, ident: ast::ident, link: *[]*task) *task = { // Schedules a task which compiles objects into an executable. fn sched_ld(plan: *plan, output: str, depend: *task...) *task = { - const ld_cmd = os::tryenv("LD", if (len(plan.libs) > 0) { - // C compiler is used as linker if we -l something - yield plan.target.cc_cmd; - } else { - yield plan.target.ld_cmd; - }); - let task = alloc(task { status = status::SCHEDULED, output = output, depend = alloc(depend...), - cmd = alloc([ - ld_cmd, + cmd = getcmd(&ld_tool, "-T", plan.script, - "-o", output, - ]), + "-o", output), module = void, }); // Using --gc-sections will not work when using cc as the linker - if (len(plan.libs) == 0) { + if (len(plan.libs) == 0 && task.cmd[0] == plan.target.ld_cmd) { append(task.cmd, "--gc-sections"); }; @@ -110,14 +155,24 @@ fn sched_ld(plan: *plan, output: str, depend: *task...) *task = { // Schedules a task which merges objects into an archive. fn sched_ar(plan: *plan, output: str, depend: *task...) *task = { - const ar_cmd = os::tryenv("AR", plan.target.ar_cmd); let task = alloc(task { status = status::SCHEDULED, output = output, depend = alloc(depend...), - cmd = alloc([ar_cmd, "-csr", output]), + cmd = getcmd(&ar_tool), module = void, }); + + // If you specify flags in `$ARFLAGS' or a different archiver in `$AR', + // this assumes that you will pass the correct flags for creating an + // archive, and will not pass the default `-csr', since `ar' is picky + // about the order flags are given. + if (len(task.cmd) == 1 && task.cmd[0] == plan.target.ar_cmd) { + append(task.cmd, "-csr"); + }; + + append(task.cmd, output); + for (let i = 0z; i < len(depend); i += 1) { assert(strings::hassuffix(depend[i].output, ".o")); append(task.cmd, depend[i].output); @@ -128,31 +183,30 @@ fn sched_ar(plan: *plan, output: str, depend: *task...) *task = { // Schedules a task which compiles assembly into an object. fn sched_as(plan: *plan, output: str, input: str, depend: *task...) *task = { - const as_cmd = os::tryenv("AS", plan.target.as_cmd); let task = alloc(task { status = status::SCHEDULED, output = output, depend = alloc(depend...), - cmd = alloc([as_cmd, "-g", "-o", output, input]), + cmd = getcmd(&as_tool, "-g", "-o", output), module = void, }); + + append(task.cmd, input); + append(plan.scheduled, task); return task; }; // Schedules a task which compiles an SSA file into assembly. fn sched_qbe(plan: *plan, output: str, depend: *task) *task = { - const qbe_cmd = os::tryenv("QBE", "qbe"); let task = alloc(task { status = status::SCHEDULED, output = output, depend = alloc([depend]), - cmd = alloc([ - qbe_cmd, + cmd = getcmd(&qbe_tool, "-t", plan.target.qbe_target, "-o", output, - depend.output, - ]), + depend.output), module = void, }); append(plan.scheduled, task);