commit 39a528a8b1b7a4a8e4ad8234f5dfc55ae00e6a68
parent fde5bd23a1f6d118398fbc2eb885f660ab7e5611
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 12 Mar 2021 09:23:05 -0500
Generalize dependency planning
Diffstat:
M | plan.ha | | | 78 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
M | subcmds.ha | | | 22 | ++++++++-------------- |
2 files changed, 71 insertions(+), 29 deletions(-)
diff --git a/plan.ha b/plan.ha
@@ -1,5 +1,8 @@
use fmt;
+use hare::ast;
use hare::module;
+use hash::fnv;
+use hash;
use os::exec;
use os;
use path;
@@ -18,26 +21,20 @@ type task = struct {
cmd: []str,
};
+fn task_free(task: *task) void = {
+ free(task.depend);
+ free(task.output);
+ free(task.cmd);
+ free(task);
+};
+
type plan = struct {
workdir: str,
counter: uint,
scheduled: []*task,
complete: []*task,
script: str,
-};
-
-type goal = enum {
- OBJ,
- EXE,
- RUN,
- TEST,
-};
-
-fn task_free(task: *task) void = {
- free(task.depend);
- free(task.output);
- free(task.cmd);
- free(task);
+ modset: [64][]u32,
};
fn mkplan(ctx: *module::context) plan = {
@@ -61,9 +58,60 @@ fn plan_finish(plan: *plan) void = {
let task = plan.complete[i];
task_free(task);
};
+ free(plan.complete);
+ for (let i = 0z; i < len(plan.scheduled); i += 1) {
+ let task = plan.scheduled[i];
+ task_free(task);
+ };
free(plan.scheduled);
- free(plan.complete);
+
+ for (let i = 0z; i < len(plan.modset); i += 1) {
+ free(plan.modset[i]);
+ };
+};
+
+fn ident_hash(ident: ast::ident) u32 = {
+ let hash = fnv::fnv32();
+ defer hash::close(hash);
+ for (let i = 0z; i < len(ident); i += 1) {
+ hash::write(hash, strings::to_utf8(ident[i]));
+ hash::write(hash, [0]);
+ };
+ return fnv::sum32(hash);
+};
+
+fn sched_module(
+ plan: *plan,
+ ctx: *module::context,
+ depends: *[]*task,
+ ident: ast::ident,
+) void = {
+ let hash = ident_hash(ident);
+ // TODO: We should not have to dereference the bucket
+ // TODO: We should not have to cast the length
+ let bucket = &plan.modset[hash % len(plan.modset): u32];
+ for (let i = 0z; i < len(*bucket); i += 1) {
+ if (bucket[i] == hash) {
+ fmt::println("mod cache hit");
+ return;
+ };
+ };
+ fmt::println("mod cache miss");
+ append(*bucket, hash);
+
+ let ver = match (module::lookup(ctx, ident)) {
+ err: module::error => {
+ let ident = ast::ident_unparse_s(ident);
+ fmt::fatal("Error resolving {}: {}",
+ ident, module::errstr(err));
+ },
+ ver: module::version => ver,
+ };
+ let ns = ast::ident_unparse_s(ident);
+ let obj = sched_hare_object(plan, ver.inputs, ns);
+ // TODO: Unnecessary dereference
+ append(*depends, obj);
};
// Schedules a task which compiles objects into an executable.
diff --git a/subcmds.ha b/subcmds.ha
@@ -5,6 +5,13 @@ use hare::module;
use os;
use path;
+type goal = enum {
+ OBJ,
+ EXE,
+ RUN,
+ TEST,
+};
+
fn build(args: []str) void = {
let help: []getopt::help = [
"compiles Hare programs",
@@ -67,23 +74,10 @@ fn build(args: []str) void = {
// TODO:
// - Use the hare cache
// - Transitive dependencies
- // - Move this into a separate function, e.g. plan_module
let depends: []*task = [];
for (let i = 0z; i < len(ver.depends); i += 1z) {
const dep = ver.depends[i];
- match (module::lookup(&ctx, dep)) {
- err: module::error => {
- let ident = ast::ident_unparse_s(dep);
- fmt::fatal("Error resolving {}: {}",
- ident, module::errstr(err));
- },
- ver: module::version => {
- let ns = ast::ident_unparse_s(dep);
- let obj = sched_hare_object(
- &plan, ver.inputs, ns);
- append(depends, obj);
- },
- };
+ sched_module(&plan, &ctx, &depends, dep);
};
if (output == "") {