commit 46a829c092ede2b20837f42a3908c9646a5dd6f8
parent f5155ecdde0efa534bf811f7eab428331abb6747
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 10 Mar 2021 13:35:08 -0500
Incorporate modules into the build
Diffstat:
M | main.ha | | | 26 | ++++++++++++++------------ |
M | plan.ha | | | 77 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
2 files changed, 82 insertions(+), 21 deletions(-)
diff --git a/main.ha b/main.ha
@@ -54,27 +54,29 @@ export fn main() void = {
module::errstr(err)),
};
+ let depends: []*task = [];
for (let i = 0z; i < len(ver.depends); i += 1z) {
const dep = ver.depends[i];
- let ident = ast::ident_unparse_s(dep);
- defer free(ident);
match (module::lookup(&ctx, dep)) {
- err: module::error => fmt::fatal("Error resolving {}: {}",
- ident, module::errstr(err)),
+ err: module::error => {
+ let ident = ast::ident_unparse_s(dep);
+ fmt::fatal("Error resolving {}: {}",
+ ident, module::errstr(err));
+ },
ver: module::version => {
- let hash = hex::encode(ver.hash);
- defer free(hash);
- fmt::errorfln("{}: selecting version {}",
- ident, hash);
- for (let i = 0z; i < len(ver.inputs); i += 1) {
- fmt::errorfln("\t{}", ver.inputs[i].path);
- };
+ let ns = ast::ident_unparse_s(dep);
+ // TODO:
+ // - Use the cache
+ // - Transitive dependencies
+ let obj = sched_hare_object(&plan,
+ ver.inputs, ns);
+ append(depends, obj);
},
};
};
// TODO: Choose less stupid output name
- sched_hare_exe(&plan, ver.inputs, "a.out");
+ sched_hare_exe(&plan, ver.inputs, "a.out", depends...);
for (len(plan.scheduled) != 0) {
let next: nullable *task = null;
diff --git a/plan.ha b/plan.ha
@@ -51,14 +51,33 @@ fn sched_ld(plan: *plan, output: str, depend: *task...) *task = {
return task;
};
+// Schedules a task which merges objects into an archive.
+fn sched_ar(plan: *plan, output: str, depend: *task...) *task = {
+ let task = alloc(task {
+ status = status::SCHEDULED,
+ output = output,
+ depend = mkdepends(depend...),
+ cmd = alloc([
+ os::tryenv("AR", "ar"),
+ "-csr", output,
+ ]),
+ });
+ for (let i = 0z; i < len(depend); i += 1) {
+ assert(strings::has_suffix(depend[i].output, ".o"));
+ append(task.cmd, depend[i].output);
+ };
+ append(plan.scheduled, task);
+ return task;
+};
+
// Schedules a task which compiles assembly into an object.
-fn sched_as(plan: *plan, output: str, depend: *task) *task = {
+fn sched_as(plan: *plan, output: str, input: str, depend: *task...) *task = {
let task = alloc(task {
status = status::SCHEDULED,
output = output,
- depend = mkdepends(depend),
+ depend = mkdepends(depend...),
cmd = alloc([
- os::tryenv("AS", "as"), "-o", output, depend.output,
+ os::tryenv("AS", "as"), "-o", output, input,
]),
});
append(plan.scheduled, task);
@@ -80,13 +99,24 @@ fn sched_qbe(plan: *plan, output: str, depend: *task) *task = {
};
// Schedules tasks which compiles a Hare module into an object or archive.
+// Returns the output path, generated as an object or archive name.
+//
+// Takes ownership over namespace, if provided.
fn sched_hare_object(
plan: *plan,
inputs: []module::input,
- output: str,
+ namespace: (str | void),
depend: *task...
) *task = {
- // TODO: Handle mixed sources
+ // XXX: Do we care to support assembly-only modules?
+ let mixed = false;
+ for (let i = 0z; i < len(inputs); i += 1) {
+ if (strings::has_suffix(inputs[i].path, ".s")) {
+ mixed = true;
+ break;
+ };
+ };
+
let ssa = mkfile(plan, "ssa");
let s = mkfile(plan, "s");
@@ -98,14 +128,39 @@ fn sched_hare_object(
os::tryenv("HAREC", "harec"), "-o", ssa,
]),
});
+ match (namespace) {
+ void => void,
+ ns: str => append(harec.cmd, "-N", ns),
+ };
for (let i = 0z; i < len(inputs); i += 1) {
let path = inputs[i].path;
- append(harec.cmd, path);
+ if (strings::has_suffix(path, ".ha")) {
+ append(harec.cmd, path);
+ };
};
append(plan.scheduled, harec);
- return sched_as(plan, output, sched_qbe(plan, s, harec));
+ let as_out = mkfile(plan, "o");
+ let qbe = sched_qbe(plan, s, harec);
+ let hare_obj = sched_as(plan, as_out, s, qbe);
+ if (!mixed) {
+ return hare_obj;
+ };
+
+ let objs: []*task = alloc([hare_obj]);
+ defer free(objs);
+ for (let i = 0z; i < len(inputs); i += 1) {
+ // XXX: All of our assembly files don't depend on anything else,
+ // but that may not be generally true. We may have to address
+ // this at some point.
+ let path = inputs[i].path;
+ if (!strings::has_suffix(path, ".s")) {
+ continue;
+ };
+ append(objs, sched_as(plan, mkfile(plan, "o"), path));
+ };
+ return sched_ar(plan, mkfile(plan, "a"), objs...);
};
// Schedules tasks which compiles hare sources into an executable.
@@ -115,8 +170,12 @@ fn sched_hare_exe(
output: str,
depend: *task...
) *task = {
- let o = sched_hare_object(plan, inputs, mkfile(plan, "o"), depend...);
- return sched_ld(plan, strings::dup(output), o);
+ let obj = sched_hare_object(plan, inputs, void, depend...);
+ // TODO: We should be able to use partial variadic application
+ let link: []*task = alloc([], len(depend));
+ defer free(link);
+ append(link, obj, ...depend);
+ return sched_ld(plan, strings::dup(output), link...);
};
fn execute(