summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2015-04-17 11:43:11 -0700
committerOri Bernstein <ori@eigenstate.org>2015-04-17 11:43:11 -0700
commitc05e4d021a24645c06092dda39c6befdf77ec813 (patch)
tree6ba6f2c2c1f90653d1848ff837e6fdcef113f042
parent97f03b720b5d8656a316ce1ca14b89d4a411c59f (diff)
downloadmc-c05e4d021a24645c06092dda39c6befdf77ec813.tar.gz
Topologically sort targets.
This avoids tons of ugly, spurious chdir calls, as well as detecting cycles in library dependencies.
-rw-r--r--mbld/bld.sub1
-rw-r--r--mbld/build.myr29
-rw-r--r--mbld/clean.myr4
-rw-r--r--mbld/install.myr4
-rw-r--r--mbld/main.myr3
-rw-r--r--mbld/parse.myr53
-rw-r--r--mbld/subdir.myr23
-rw-r--r--mbld/test.myr5
-rw-r--r--mbld/types.myr9
-rw-r--r--mbld/util.myr13
10 files changed, 67 insertions, 77 deletions
diff --git a/mbld/bld.sub b/mbld/bld.sub
index 1986947..41d72bb 100644
--- a/mbld/bld.sub
+++ b/mbld/bld.sub
@@ -10,7 +10,6 @@ bin mbld =
main.myr
opts.myr
parse.myr
- subdir.myr
test.myr
types.myr
util.myr
diff --git a/mbld/build.myr b/mbld/build.myr
index 39caa9d..f470cba 100644
--- a/mbld/build.myr
+++ b/mbld/build.myr
@@ -17,6 +17,10 @@ pkg bld =
const buildall = {b
for tn in b.all
+ if std.hthas(b.built, tn)
+ continue
+ ;;
+ std.htput(b.built, tn, true)
match gettarg(b.targs, tn)
| `Bin bt: buildbin(b, bt, false)
| `Lib lt: buildlib(b, lt)
@@ -54,12 +58,8 @@ const build = {b, targ
const buildbin = {b, targ, addsrc
var dg, src
- if targ.built
- ->
- ;;
- pushdir(b, targ.dir)
+ setdir(b, targ.dir)
addincludes(b, targ)
- buildlibdeps(b, targ)
std.put("%s...\n", targ.name)
if !myrdeps(b, targ, false, false, addsrc, &dg)
std.fatal(1, "Could not load dependencies for %s\n", targ.name)
@@ -72,8 +72,6 @@ const buildbin = {b, targ, addsrc
linkbin(&dg, targ.name, src, targ.ldscript, targ.runtime, targ.incpath, targ.libdeps)
std.slfree(src)
;;
- targ.built = true
- popdir(b)
}
const buildlib = {b, targ
@@ -82,12 +80,8 @@ const buildlib = {b, targ
var dg
var lib, src
- if targ.built
- ->
- ;;
- pushdir(b, targ.dir)
+ setdir(b, targ.dir)
addincludes(b, targ)
- buildlibdeps(b, targ)
lib = targ.name
std.put("lib%s.a...\n", lib)
archive = std.fmt("lib%s.a", lib)
@@ -106,19 +100,16 @@ const buildlib = {b, targ
std.slfree(src)
;;
std.slfree(archive)
- targ.built = true
- popdir(b)
}
const genfiles = {b, gt
- pushdir(b, gt.dir)
+ setdir(b, gt.dir)
for f in gt.out
if !std.fexists(f)
run(gt.cmd)
break
;;
;;
- popdir(b)
}
const addincludes = {b, targ
@@ -129,12 +120,6 @@ const addincludes = {b, targ
;;
}
-const buildlibdeps = {b, targ
- for (inc, lib, subtarg) in targ.libdeps
- build(b, subtarg)
- ;;
-}
-
const hasinc = {path, t
for e in path
if std.sleq(e, t)
diff --git a/mbld/clean.myr b/mbld/clean.myr
index 5452ae5..69549fa 100644
--- a/mbld/clean.myr
+++ b/mbld/clean.myr
@@ -4,7 +4,6 @@ use "config.use"
use "deps.use"
use "opts.use"
use "parse.use"
-use "subdir.use"
use "types.use"
use "util.use"
@@ -70,7 +69,7 @@ const cleanup = {b, targ, leaves, islib
we want to automatically add 'clean' sources since otherwise,
mbld won't be able to clean code after changing a build file.
*/
- pushdir(b, targ.dir)
+ setdir(b, targ.dir)
if !myrdeps(b, targ, islib, true, true, &dg)
std.fatal(1, "Could not load dependencies for %s\n", targ.name)
;;
@@ -85,6 +84,5 @@ const cleanup = {b, targ, leaves, islib
std.put("\tclean %s\n", k)
;;
;;
- popdir(b)
}
diff --git a/mbld/install.myr b/mbld/install.myr
index ca053db..bc4dd27 100644
--- a/mbld/install.myr
+++ b/mbld/install.myr
@@ -4,7 +4,6 @@ use "config.use"
use "deps.use"
use "opts.use"
use "parse.use"
-use "subdir.use"
use "types.use"
use "util.use"
use "build.use"
@@ -52,7 +51,7 @@ const movetargs = {b, delete
const movefile = {b, delete, dir, file, instdir, destdir, prefix, perm
var path
- pushdir(b, dir)
+ setdir(b, dir)
path = std.pathjoin([destdir, instdir, prefix, file][:])
if delete
std.put("\tdelete %s\n", path)
@@ -72,7 +71,6 @@ const movefile = {b, delete, dir, file, instdir, destdir, prefix, perm
;;
;;
std.slfree(path)
- popdir(b)
}
const moveman = {b, delete, dir, man
diff --git a/mbld/main.myr b/mbld/main.myr
index 359da8c..0ccf212 100644
--- a/mbld/main.myr
+++ b/mbld/main.myr
@@ -105,10 +105,11 @@ const mkbuild = {bldfile
b = std.zalloc()
b.targs = std.mkht(std.strhash, std.streq)
b.gensrc = std.mkht(std.strhash, std.streq)
+ b.built = std.mkht(std.strhash, std.streq)
if !findbase(b, bldfile) || !std.chdir(b.basedir)
std.fatal(1, "could not find %s\n", bldfile)
;;
- bld.pushdir(b, "")
+ bld.setdir(b, "")
-> b
}
diff --git a/mbld/parse.myr b/mbld/parse.myr
index cca811e..cde1397 100644
--- a/mbld/parse.myr
+++ b/mbld/parse.myr
@@ -23,10 +23,14 @@ type parser = struct
;;
const load = {b
- -> loadall(b, b.bldfile, "")
+ var ok
+ ok = loadall(b, b.bldfile, "")
+ if ok
+ ok = sortdeps(b)
+ ;;
+ -> ok
}
-
const loadall = {b, path, dir
var p : parser#
var subpath, subbld, subproj, ok
@@ -65,6 +69,50 @@ const loadall = {b, path, dir
-> ok
}
+const sortdeps = {b
+ var looped
+ var marked
+ var all
+
+ all = [][:]
+ looped = std.mkht(std.strhash, std.streq)
+ marked = std.mkht(std.strhash, std.streq)
+ for dep in b.all
+ match gettarg(b.targs, dep)
+ | `Bin _: all = visit(all, b, dep, looped, marked)
+ | `Lib _: all = visit(all, b, dep, looped, marked)
+ | targ: all = std.slpush(all, dep)
+ ;;
+ ;;
+ std.slfree(b.all)
+ b.all = all
+ -> true
+}
+
+const visit = {all, b, targ, looped, marked
+ if std.hthas(looped, targ)
+ std.fatal(1, "cycle in build depgraph involving %s\n", targ)
+ elif std.hthas(marked, targ)
+ -> all
+ ;;
+
+ std.htput(looped, targ, true)
+ for (dir, lib, dep) in getdeps(gettarg(b.targs, targ))
+ all = visit(all, b, dep, looped, marked)
+ ;;
+ std.htdel(looped, targ)
+ std.htput(marked, targ, true)
+ -> std.slpush(all, targ)
+}
+
+const getdeps = {targ
+ match targ
+ | `Bin t: -> t.libdeps
+ | `Lib t: -> t.libdeps
+ | _: std.fatal(1, "depending on non-library target")
+ ;;
+}
+
const mkparser = {path, dir, basedir
var p
@@ -306,7 +354,6 @@ const myrtarget = {p, targ
.ldscript=ldscript,
.runtime=runtime,
.incpath=incpath,
- .built=false
])
}
diff --git a/mbld/subdir.myr b/mbld/subdir.myr
deleted file mode 100644
index 0efd958..0000000
--- a/mbld/subdir.myr
+++ /dev/null
@@ -1,23 +0,0 @@
-use std
-
-use "types.use"
-use "util.use"
-
-pkg bld =
- const subdirs : (p : build#, subs : byte[:][:], targ : std.option(byte[:]) -> void)
-;;
-
-const subdirs = {p, subs, targ
- for s in subs
- std.put("Entering directory '%s'\n", s)
- if !std.chdir(s)
- std.fatal(1, "unable to enter directory %s\n", s)
- ;;
- run(p.cmd)
- std.put("Leaving directory '%s'\n", s)
- if !std.chdir("..")
- std.fatal(1, "unable to leave directory %s\n", s)
- ;;
- ;;
-}
-
diff --git a/mbld/test.myr b/mbld/test.myr
index b6392d2..e1fa5ff 100644
--- a/mbld/test.myr
+++ b/mbld/test.myr
@@ -7,7 +7,6 @@ use "opts.use"
use "parse.use"
use "types.use"
use "util.use"
-use "subdir.use"
use "config.use"
@@ -68,7 +67,7 @@ const dotest = {b, targ, ok
var tt, bin ,path, tests
tests = [][:]
- pushdir(b, targ.dir)
+ setdir(b, targ.dir)
for s in targ.inputs
path = std.pathcat("./test", s)
if std.fexists(path)
@@ -80,7 +79,6 @@ const dotest = {b, targ, ok
.install = false,
.libdeps = targ.libdeps,
.incpath = targ.incpath,
- .built = false,
]
cleantest(b, path)
@@ -98,7 +96,6 @@ const dotest = {b, targ, ok
std.slfree(t)
;;
std.slfree(tests)
- popdir(b)
-> ok
}
diff --git a/mbld/types.myr b/mbld/types.myr
index a1e0f81..3dd95a4 100644
--- a/mbld/types.myr
+++ b/mbld/types.myr
@@ -2,14 +2,14 @@ use std
pkg bld =
type build = struct
- cmd : byte[:][:] /* command that we ran */
/* build state */
basedir : byte[:]
bldfile : byte[:]
- dirstk : byte[:][:]
curdir : byte[:]
+ built : std.htab(byte[:], bool)# /* set of targets built in this run */
+
/* build params */
- all : byte[:][:]
+ all : byte[:][:] /* all targets, in reverse topological order */
targs : std.htab(byte[:], targ)# /* dir => target mapping */
tdeps : std.htab(byte[:], byte[:][:]) /* targname => depname[:] mapping */
gensrc : std.htab(byte[:], gentarg#)# /* generated src => generating target mapping */
@@ -30,8 +30,7 @@ pkg bld =
dir : byte[:]
name : byte[:]
inputs : byte[:][:]
- libdeps : (byte[:], byte[:], byte[:])[:] /* dir, lib pairs */
- built : bool
+ libdeps : (byte[:], byte[:], byte[:])[:] /* dir, lib, targname */
install : bool
runtime : byte[:]
incpath : byte[:][:]
diff --git a/mbld/util.myr b/mbld/util.myr
index 383cdbd..29e325c 100644
--- a/mbld/util.myr
+++ b/mbld/util.myr
@@ -11,8 +11,7 @@ pkg bld =
const srcswapsuffix : (f : byte[:], newsuff : byte[:] -> byte[:])
const strlistfree : (sl : byte[:][:] -> void)
const gettarg : (tab : std.htab(byte[:], targ)#, n : byte[:] -> targ)
- const pushdir : (b : build#, dir : byte[:] -> void)
- const popdir : (b : build# -> void)
+ const setdir : (b : build#, dir : byte[:] -> void)
;;
const run = {cmd
@@ -104,16 +103,6 @@ const gettarg = {tab, n
;;
}
-const pushdir = {b, dir
- b.dirstk = std.slpush(b.dirstk, dir)
- setdir(b, dir)
-}
-
-const popdir = {b
- b.dirstk = b.dirstk[:b.dirstk.len-1]
- setdir(b, b.dirstk[b.dirstk.len-1])
-}
-
const setdir = {b, dir
var p