ref: ae222f2157fa57dd27ff23bcb13c78adc08627b2
dir: /mbld/deps.myr/
use std
use regex
use bio
use "config.use"
use "opts.use"
use "types.use"
use "util.use"
pkg bld =
const myrdeps : (b : build#, mt : myrtarg#, islib : bool, isclean : bool, addsrc : bool, dg : depgraph# -> bool)
/* a bit ugly: initialized from main() */
var usepat : regex.regex#
;;
var usepat : regex.regex#
type dep = union
`Local byte[:]
`Lib byte[:]
;;
const myrdeps = {b, mt, islib, isclean, addsrc, dg
var objs, uses, srcs, incs
var out, useout, depstk
var i
dg.deps = std.mkht(std.strhash, std.streq)
dg.libs = std.mkht(std.strhash, std.streq)
dg.input = std.mkht(std.strhash, std.streq)
dg.sources = std.mkht(std.strhash, std.streq)
dg.updated = std.mkht(std.strhash, std.streq)
dg.seen = std.mkht(std.strhash, std.streq)
dg.done = std.mkht(std.strhash, std.streq)
/* direct dependencies of binary */
if islib
out = std.fmt("lib%s.a", mt.name)
useout = std.sldup(mt.name)
else
out = std.sldup(mt.name)
useout = ""
;;
srcs = mt.inputs
incs = mt.incpath
objs = swapall(srcs, config.Objsuffix)
uses = swapall(srcs, ".use")
for i = 0; i < srcs.len; i++
std.htput(dg.input, objs[i], srcs[i])
std.htput(dg.sources, srcs[i], true)
pushdep(dg, srcs[i], objs[i])
if std.hassuffix(srcs[i], ".myr")
std.htput(dg.input, uses[i], srcs[i])
pushdep(dg, srcs[i], uses[i])
;;
;;
for i = 0; i < srcs.len; i++
pushdep(dg, objs[i], out)
if islib && std.hassuffix(srcs[i], ".myr")
pushdep(dg, uses[i], useout)
;;
;;
for i = 0; i < srcs.len; i++
depstk = [][:]
srcdeps(b, dg, srcs[i], objs[i], uses[i], incs, &depstk, isclean, addsrc)
std.slfree(depstk)
;;
dumpgraph(dg)
-> true
}
const swapall = {srcs, suff
var sl
sl = [][:]
for s in srcs
sl = std.slpush(sl, srcswapsuffix(s, suff))
;;
-> sl
}
const dumpgraph = {dg
var keys
if !opt_debug
->
;;
keys = std.htkeys(dg.deps)
std.put("digraph dg {\n")
for k in keys
for v in std.htgetv(dg.deps, k, ["WTFUNKNOWN!"][:])
std.put("\t\"%s\" -> \"%s\";\n", k, v)
;;
;;
std.put("}\n")
}
const srcdeps = {b, g, path, obj, usefile, incs, depstk, isclean, addsrc
var deps
if std.hthas(g.done, path)
->
;;
depstk# = std.slpush(depstk#, path)
if std.htgetv(g.seen, path, false)
std.fput(1, "dependency loop involving %s:\n", path)
for d in depstk#
std.fput(1, "\t%s\n", d)
;;
std.exit(1)
;;
deps = getdeps(b, path)
std.htput(g.seen, path, true)
for d in deps
match d
| `Lib lib:
/*
If we're cleaning, we don't care about libraries; at best, this does nothing. At
worst, this will cause failure if the library is a local library that gets cleand.
*/
if !isclean
scrapelibs(g, lib, incs)
;;
| `Local l:
if !std.hassuffix(l, ".use")
std.fatal(1, "local dependency \"%s\" of \"%s\" should end with .use\n", l, path)
;;
if obj.len != 0
pushdep(g, l, obj)
;;
if usefile.len != 0
pushdep(g, l, usefile)
;;
addusedep(b, g, path, l, incs, depstk, isclean, addsrc)
;;
;;
depstk# = std.slgrow(depstk#, depstk#.len - 1)
std.htput(g.seen, path, false)
std.htput(g.done, path, true)
}
const addusedep = {b, g, f, usefile, incs, depstk, isclean, addsrc
var src
if std.hthas(g.done, usefile)
if opt_debug
std.put("already loaded deps for %s\n", usefile)
;;
->
;;
match std.htget(g.input, usefile)
| `std.Some path:
src = std.sldup(path)
| `std.None:
src = swapsuffix(usefile, ".use", ".myr")
if addsrc
std.htput(g.sources, src, true)
elif !std.hthas(g.input, usefile)
std.fatal(1, "%s: source file %s not listed in bldfile\n", f, src)
;;
;;
pushdep(g, src, usefile)
std.htput(g.input, usefile, src)
srcdeps(b, g, src, "", usefile, incs, depstk, isclean, addsrc)
std.htput(g.done, usefile, true)
}
const getdeps = {b, path
var f
var deps : dep[:]
deps = [][:]
if !std.fexists(path)
match std.htget(b.gensrc, path)
| `std.Some gt: run(gt.cmd)
| `std.None: std.fatal(1, "no input file %s\n", path)
;;
;;
match bio.open(path, bio.Rd)
| `std.Some fd: f = fd
| `std.None: std.fatal(1, "could not open %s\n", path)
;;
while true
match bio.readln(f)
| `std.Some ln:
deps = depname(deps, ln)
std.slfree(ln)
| `std.None:
bio.close(f)
-> deps
;;
;;
}
const scrapelibs = {dg, lib, incs
var deps, d
var f
var done
if std.hthas(dg.libs, lib)
->
;;
deps = [][:]
f = openlib(lib, incs)
match bio.getc(f)
| `std.Some 'U': /* nothing */
| `std.Some _: std.fatal(1, "library %s: corrupt or invalid usefile\n", lib)
| `std.None: std.fatal(1, "library %s: could not read usefile\n", lib)
;;
match bio.getbe32(f)
| `std.Some 1: /* nothing: version matches. */
| `std.Some 0: std.fput(1, "library %s: warning: old usefile version\n", lib)
| `std.Some _: std.fatal(1, "library %s: usefile version unknown\n", lib)
| `std.None: std.fatal(1, "library %s: corrutpt or invalid usefile\n", lib)
;;
std.slfree(rdstr(f))
done = false
while !done
match bio.getc(f)
| `std.Some 'L':
d = rdstr(f)
deps = std.slpush(deps, d)
| `std.Some _: done = true
| `std.None: done = true
;;
;;
bio.close(f)
std.htput(dg.libs, lib, deps)
for dep in deps
scrapelibs(dg, dep, incs)
;;
}
const openlib = {lib, incs
var path
for p in incs
path = std.pathjoin([p, lib][:])
match bio.open(path, bio.Rd)
| `std.Some file:
-> file
| `std.None:
/* nothing */
;;
;;
path = std.pathjoin([opt_instroot, "/lib/myr", lib][:])
match bio.open(path, bio.Rd)
| `std.Some file:
-> file
| `std.None:
/* nothing */
;;
std.fatal(1, "could not find library %s.\n", lib)
}
const depname = {deps, ln
/*
the regex pattern does some contortions to either grab
an unquoted path and put it into uses[4], or a quoted
path, and put it (minus the quotes) into uses[2]
*/
match regex.exec(usepat, ln)
| `std.Some uses:
if uses[2].len > 0
deps = std.slpush(deps, `Local std.sldup(uses[2]))
else
deps = std.slpush(deps, `Lib std.sldup(uses[4]))
;;
| `std.None:
/* nothing to do */
;;
-> deps
}
/* pushes a dep into the dependency list */
const pushdep = {dg, src, dst
var sl
if opt_debug
std.put("%s <= %s\n", dst, src)
;;
std.assert(dst.len < 200, "BUG!")
sl = std.htgetv(dg.deps, dst, [][:])
sl = std.slpush(sl, src)
std.htput(dg.deps, dst, sl)
}
const rdstr = {f
var len
var sl
match bio.getbe32(f)
| `std.Some l:
len = l
sl = std.slalloc(len)
| `std.None: std.die("string length not readable")
;;
bio.read(f, sl)
-> sl
}