ref: a2ff9547b25b4c44d8e9095659bd282a2b4e160e
parent: cc99dfdb5dbb27ac3fed40c796a01a4269d307c2
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Jul 23 19:28:34 EDT 2017
New parallel mbld.
--- /dev/null
+++ b/lib/thread/ncpu.myr
@@ -1,0 +1,10 @@
+use std
+use sys
+
+pkg thread =
+ const ncpu : (-> int)
+;;
+
+const ncpu = {
+ -> 1
+}
--- a/mbld/bld.sub
+++ b/mbld/bld.sub
@@ -1,8 +1,8 @@
-# the mbld binary
bin mbld =
build.myr
clean.myr
deps.myr
+ libs.myr
install.myr
main.myr
opts.myr
--- a/mbld/build.myr
+++ b/mbld/build.myr
@@ -1,532 +1,134 @@
use std
use "config"
-use "deps"
use "opts"
-use "parse"
use "types"
use "util"
pkg bld =
- const buildall : (b : build# -> bool)
- const genall : (b : build# -> bool)
- const buildtarg : (b : build#, target : byte[:] -> bool)
- const buildbin : (b : build#, bt : myrtarg#, addsrc : bool -> bool)
- const buildlib : (b : build#, lt : myrtarg# -> bool)
+ const buildtarg : (b : build#, targ : byte[:] -> bool)
+ const clean : (b : build# -> bool)
;;
-const buildall = {b
- for tn : b.all
- if std.hthas(b.built, tn)
- continue
- ;;
- std.htput(b.built, tn, true)
- match gettarg(b.targs, tn)
- | `Bin bt:
- if !bt.istest
- buildbin(b, bt, false)
- ;;
- | `Lib lt: buildlib(b, lt)
- | `Gen gt: genfiles(b, gt)
- | `Data _: /* nothing needed */
- | `Man _: /* nothing needed */
- | `Cmd _: /* these are for manual commands or tests */
- ;;
+const buildtarg = {b, targ
+ var g
+
+ g = b.deps
+ var outs = std.htgetv(g.targs, targ, [][:])
+ for o : outs
+ mark(b, o)
;;
- setdir(b, "")
+ build(b, g)
-> true
}
-const buildtarg = {b, targ
- var depset
-
- depset = std.mkht(std.strhash, std.streq)
- addeps(b, targ, depset)
- for tn : b.all
- if std.hthas(b.built, tn) || !std.hthas(depset, tn)
+const clean = {b
+ for n : b.deps.nodes
+ if n.durable
continue
;;
- if std.sleq(tn, targ)
- break
- ;;
- std.htput(b.built, tn, true)
- match gettarg(b.targs, tn)
- | `Bin bt:
- if !bt.istest
- buildbin(b, bt, false)
+ for g : n.gen
+ if std.remove(g)
+ mbldput("\tclean {}\n", g)
;;
- | `Lib lt: buildlib(b, lt)
- | `Gen gt: genfiles(b, gt)
- | `Data _: /* nothing needed */
- | `Man _: /* nothing needed */
- | `Cmd _: /* these are for manual commands or tests */
;;
;;
- build(b, targ)
- std.htfree(depset)
-> true
}
-const addeps = {b, targ, depset
- if std.hthas(depset, targ)
+const mark = {b, o
+ if o.want
-> void
;;
- std.htput(depset, targ, true)
- match gettarg(b.targs, targ)
- | `Bin bt:
- for (dir, lib, targname) : bt.libdeps
- addeps(b, targname, depset)
- ;;
- | `Lib lt:
- for (dir, lib, targname) : lt.libdeps
- addeps(b, targname, depset)
- ;;
- | _:
+ o.want = true
+ for n : o.ndep
+ mark(b, n)
;;
}
-const genall = {b
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Gen gt: runin(b, gt.cmd, gt.dir)
- | _: /* skip */
+const build = {b, g
+ for n : g.leaves
+ if n.want
+ stale(b, n)
+ unblock(b, n)
;;
;;
- /* genfiles will exit if the build fails; always return true */
- -> true
-}
-const build = {b, targ
- match std.htget(b.targs, targ)
- | `std.Some (`Bin bt): buildbin(b, bt, false)
- | `std.Some (`Lib lt): buildlib(b, lt)
- | `std.Some (`Gen gt): runin(b, gt.cmd, gt.dir)
- | `std.Some (`Cmd ct): runin(b, ct.cmd, ct.dir)
- | `std.Some (`Data _): /* nothing needed */
- | `std.Some (`Man _): /* nothing needed */
- | `std.None: std.fatal("invalid target {}\n", targ)
- ;;
- -> true
-}
-
-const runin = {b, cmd, dir
- setdir(b, dir)
- run(cmd)
-}
-
-const buildbin = {b, targ, addsrc
- var dg, src, path
- var libpath, incs
-
- setdir(b, targ.dir)
- addincludes(b, targ)
- path = std.pathcat(b.curdir, targ.name)
- mbldput("{}...\n", path)
- std.slfree(path)
- dg = myrdeps(b, targ, false, addsrc)
- if !std.hthas(dg.deps, targ.name)
- std.fatal("no input files for {}\n", targ.name)
- ;;
- if builddep(b, dg, targ.name, targ.incpath) || !freshlibs(targ, targ.name, dg.libs)
- src = std.htkeys(dg.sources)
-
- incs = std.sldup(targ.incpath)
- if opt_instbase.len > 0 && !std.sleq(opt_instbase, "none")
- libpath = std.pathcat(bld.opt_instbase, config.Libpath)
- std.slpush(&incs, libpath)
+ while std.htcount(b.proc) != 0 || b.queue.len != 0
+ while std.htcount(b.proc) < opt_maxproc && b.queue.len > 0
+ launch(b, std.slpop(&b.queue))
;;
- linkbin(dg, targ.name, src, targ.ldscript, targ.runtime, incs, targ.libdeps)
- std.slfree(incs)
- std.slfree(src)
+ wait(b)
;;
- -> true
}
-const buildlib = {b, targ
- var archive, usefile
- var u, l
- var dg
- var lib, src
+const launch = {b, n
+ var pid
- setdir(b, targ.dir)
- addincludes(b, targ)
- lib = targ.name
- mbldput("{}/lib{}.a...\n", b.curdir, lib)
- archive = std.fmt("lib{}.a", lib)
- usefile = std.fmt("lib{}.use", lib)
- dg = myrdeps(b, targ, false, false)
- if !std.hthas(dg.deps, lib)
- std.fatal("no target declared for {}\n", lib)
- ;;
- u = builddep(b, dg, usefile, targ.incpath)
- l = builddep(b, dg, archive, targ.incpath)
- if u || l || !freshlibs(targ, usefile, dg.libs)
- src = std.htkeys(dg.sources)
- mergeuse(dg, lib, src, targ.incpath)
- archivelib(dg, lib, src, targ.incpath)
- std.slfree(src)
- ;;
- std.slfree(archive)
- -> true
-}
-
-const genfiles = {b, gt
- setdir(b, gt.dir)
- for out : gt.out
- if !std.fexists(out) || !allfresh(gt.deps, out)
- run(gt.cmd)
- break
- ;;
- ;;
-}
-
-const addincludes = {b, targ
- for (inc, lib, subtarg) : targ.libdeps
- if !hasinc(targ.incpath, inc)
- std.slput(&targ.incpath, 0, inc)
- ;;
- ;;
-}
-
-const hasinc = {path, t
- for e : path
- if std.sleq(e, t)
- -> true
- ;;
- ;;
- -> false
-}
-
-
-const builddep = {b, dg, out, incs
- var stale
-
- stale = false
- /* short circuit walking the dep tree if we've already built this. */
- if std.htgetv(dg.updated, out, false)
- -> false
- ;;
-
- match std.htget(dg.deps, out)
- | `std.Some deps:
- for d : deps
- if std.sleq(out, d)
- /*
- if an input generates itself (eg, object files), we
- shouldn't recurse here, because that would be infinite.
-
- The generation rule will be invoked from the target that
- consumes this file.
- */
- continue
- ;;
- if std.sleq(out, d) || builddep(b, dg, d, incs)
- stale = true
- ;;
- match std.htget(b.gensrc, d)
- | `std.Some gt:
- if !std.fexists(d) || !allfresh(gt.deps, d)
- run(gt.cmd)
- ;;
- | `std.None:
- if !std.fexists(d)
- std.fatal("no input file {}\n", d)
- ;;
- ;;
- if !isfresh(d, out)
- stale = true
- ;;
- ;;
- | `std.None:
- ;;
-
- match std.htget(dg.input, out)
- | `std.Some src:
- if stale
- compile(dg, src, incs)
- ;;
- std.htput(dg.updated, out, true)
- | `std.None:
- ;;
- -> stale
-}
-
-const compile = {dg, src, incs
- var o
- var cmd
-
- cmd = [][:]
- if std.hassuffix(src, ".myr")
- std.slpush(&cmd, opt_mc)
- for inc : incs
- std.slpush(&cmd, "-I")
- std.slpush(&cmd, inc)
- ;;
- if opt_genasm
- std.slpush(&cmd, "-S")
- ;;
- std.slpush(&cmd, src)
- run(cmd)
- std.slfree(cmd)
- elif std.hassuffix(src, ".s")
- o = srcswapsuffix(src, config.Objsuffix)
- for c : config.Ascmd
- std.slpush(&cmd, c)
- ;;
- std.slpush(&cmd,"-o")
- std.slpush(&cmd, o)
- std.slpush(&cmd, src)
- run(cmd)
- std.slfree(o)
- elif std.hassuffix(src, ".glue.c")
- o = srcswapsuffix(src, config.Objsuffix)
- std.slpush(&cmd, "cc")
- std.slpush(&cmd,"-c")
- std.slpush(&cmd,"-o")
- std.slpush(&cmd, o)
- std.slpush(&cmd, src)
- for flg : std.htgetv(dg.cflags, src, [][:])
- std.slpush(&cmd, flg)
- ;;
- run(cmd)
- elif std.hassuffix(src, ".o") || std.hassuffix(src, ".6")
- /* nothing to do with object files*/
+ if stale(b, n)
+ pid = run(n.cmd, "")
+ std.htput(b.proc, pid, n)
else
- std.fatal("Unknown file type for {}\n", src)
+ unblock(b, n)
;;
}
-const linkbin = {dg, bin, srcfiles, ldscript, rt, incs, extlibs
- var cmd
+const wait = {b
+ var pp : std.pid
- cmd = [][:]
-
- /* ld -o bin */
- for c : config.Linkcmd
- std.slpush(&cmd, std.sldup(c))
+ if std.htcount(b.proc) == 0
+ -> void
;;
- std.slpush(&cmd, std.sldup(bin))
-
- /* [-T script] */
- if ldscript.len > 0
- std.slpush(&cmd, std.sldup("-T"))
- std.slpush(&cmd, std.sldup(ldscript))
- ;;
-
- if rt.len != 0
- if !std.sleq(rt, "none")
- std.slpush(&cmd, std.sldup(rt))
+ match std.waitany()
+ | (p, `std.Wfailure): std.fatal("FAIL: {j= }\n", proclbl(b, p))
+ | (p, `std.Wsignalled): std.fatal("CRASH: {j= }\n", proclbl(b, p))
+ | (p, `std.Waiterror): std.fatal("WAT: {j= }\n", proclbl(b, p))
+ | (p, `std.Wsuccess):
+ pp = p
+ match std.htget(b.proc, p)
+ | `std.None:
+ std.fatal("followed home by stray pid {}\n", p)
+ | `std.Some n:
+ n.mtime = std.now()
+ std.htdel(b.proc, p)
+ unblock(b, n)
;;
- else
- std.slpush(&cmd, std.sldup(opt_runtime))
;;
-
- /* input.o list.o... */
- for f : srcfiles
- std.slpush(&cmd, srcswapsuffix(f, config.Objsuffix))
- ;;
-
- /* -L path -l lib... */
- cmd = addlibs(cmd, dg.libs, incs)
-
-
- /* add extra libs */
- for l : dg.extlibs
- std.slpush(&cmd, std.fmt("-l{}", l))
- ;;
-
- /* special for OSX: it warns if we don't add this */
- if std.sleq(opt_sys, "osx")
- std.slpush(&cmd, std.sldup("-macosx_version_min"))
- std.slpush(&cmd, std.sldup("10.6"))
- elif std.sleq(opt_sys, "linux") && dg.dynamic
- std.slpush(&cmd, std.sldup("-dynamic-linker"))
- std.slpush(&cmd, std.sldup("/lib64/ld-linux-x86-64.so.2"))
- ;;
-
- run(cmd)
- strlistfree(cmd)
}
-const archivelib = {dg, lib, files, incs
- var cmd
- var obj
-
- cmd = [][:]
- for c : config.Arcmd
- std.slpush(&cmd, std.sldup(c))
+const proclbl = {b, pid
+ match std.htget(b.proc, pid)
+ | `std.Some n: -> n.cmd
+ | `std.None: -> std.sldup(["?unknown?"][:])
;;
- std.slpush(&cmd, std.fmt("lib{}.a", lib))
- for f : files
- obj = srcswapsuffix(f, config.Objsuffix)
- std.slpush(&cmd, obj)
- ;;
- run(cmd)
- strlistfree(cmd)
}
-const mergeuse = {dg, lib, files, incs
- var cmd
-
- cmd = [][:]
- std.slpush(&cmd, std.sldup(opt_muse))
- std.slpush(&cmd, std.sldup("-o"))
- std.slpush(&cmd, std.fmt("lib{}.use", lib))
- std.slpush(&cmd, std.sldup("-p"))
- std.slpush(&cmd, std.sldup(lib))
- for f : files
- if std.hassuffix(f, ".myr")
- std.slpush(&cmd, srcswapsuffix(f, ".use"))
- elif !std.hassuffix(f, ".s") && !std.hassuffix(f, ".glue.c")
- std.fatal("unknown file type for {}\n", f)
+const unblock = {b, n
+ for g : n.ngen
+ std.assert(g.nblock != 0, "bogus unblock {} from {}\n", g.lbl, n.lbl)
+ g.nblock--
+ if g.nblock == 0 && g.want
+ std.slpush(&b.queue, g)
;;
;;
- for l : dg.extlibs
- std.slpush(&cmd, std.fmt("-l{}", l))
- ;;
- run(cmd)
- strlistfree(cmd)
-}
-const addlibs = {cmd, libgraph, incs
- var looped : std.htab(byte[:], bool)#
- var marked : std.htab(byte[:], bool)#
- var libs
- var head
-
- /* -L incpath... */
- if !config.Directlib
- for inc : incs
- std.slpush(&cmd, std.fmt("-L{}", inc))
- ;;
- ;;
-
- libs = std.htkeys(libgraph)
- looped = std.mkht(std.strhash, std.streq)
- marked = std.mkht(std.strhash, std.streq)
- head = cmd.len
-
- for lib : libs
- cmd = visit(cmd, head, libgraph, lib, looped, marked, incs)
- ;;
-
- -> cmd
}
-const visit = {cmd, head, g, lib, looped, marked, incs
- if std.hthas(looped, lib)
- std.fatal("cycle in library graph involving \"{}\"\n", lib)
- elif std.hthas(marked, lib)
- -> cmd
- ;;
+const stale = {b, n
+ var staletime
- std.htput(looped, lib, true)
- for dep : std.htgetv(g, lib, [][:])
- cmd = visit(cmd, head, g, dep, looped, marked, incs)
+ staletime = 0
+ for d : n.ndep
+ staletime = std.max(staletime, d.mtime)
;;
- std.htdel(looped, lib)
- std.htput(marked, lib, true)
- -> putlib(cmd, head, lib, incs)
-}
-const putlib = {cmd, head, lib, incs
- var sep
-
- if !config.Directlib
- -> std.slput(&cmd, head, std.fmt("-l{}", lib))
- else
- match findlib(lib, incs)
- | `std.None:
- mbldput("in path: ")
- sep = ""
- for inc : incs
- mbldput("\t{}{}\n", sep, inc)
- sep = ", "
- ;;
- std.fatal("could not find library lib{}.a.\n", lib)
- | `std.Some p:
- -> std.slput(&cmd, head, p)
+ n.mtime = std.now()
+ for g : n.gen
+ match std.fmtime(g)
+ | `std.Ok tm: n.mtime = std.min(n.mtime, tm)
+ | `std.Err e: n.mtime = 0
;;
;;
+ -> staletime > n.mtime
}
-
-const findlib = {lib, incs
- var buf : byte[512]
- var sl, p
-
- sl = std.bfmt(buf[:], "lib{}.a", lib)
- for i : incs
- p = std.pathcat(i, sl)
- if std.fexists(p)
- -> `std.Some p
- ;;
- std.slfree(p)
- ;;
-
- p = std.pathjoin([opt_instbase, config.Libpath, sl][:])
- if std.fexists(p)
- -> `std.Some p
- ;;
- std.slfree(p)
- -> `std.None
-}
-
-const freshlibs = {targ, output, libgraph
- var libs
-
- libs = std.htkeys(libgraph)
- for l : libs
- match findlib(l, targ.incpath)
- | `std.Some lib:
- if !isfresh(lib, output)
- std.slfree(lib)
- -> false
- ;;
- std.slfree(lib)
- | `std.None:
- std.fput(1, "{}: could not find library lib{}.a\n", targ.name, l)
- std.fput(1, "searched:\n")
- for inc : targ.incpath
- std.fput(1, "\t{}\n", inc)
- ;;
- std.fput(1, "\t{}/{}\n", opt_instbase, config.Libpath)
- std.exit(1)
- ;;
- ;;
- std.slfree(libs)
- -> true
-}
-
-const allfresh = {deps, out
- for d : deps
- if !isfresh(d, out)
- -> false
- ;;
- ;;
- -> true
-}
-
-const isfresh = {src, dst
- var srcmt, dstmt
-
- /*
- OSX only has single second resolution on modification
- times. Since most builds happen within one second of each
- other, if we treat equal times as outdated, we do a lot of
- spurious rebuilding.
-
- So, we treat times where both secs and nsecs are equal as
- up to date.
- */
- match std.fmtime(src)
- | `std.Ok mt: srcmt = mt
- | `std.Err e: std.fatal("could not stat {}: {}\n", src, e)
- ;;
- match std.fmtime(dst)
- | `std.Ok mt: dstmt = mt
- | `std.Err e: -> false
- ;;
- -> srcmt <= dstmt
-}
-
--- a/mbld/clean.myr
+++ b/mbld/clean.myr
@@ -1,93 +1,8 @@
use std
-use "config"
-use "deps"
use "opts"
-use "parse"
use "types"
use "util"
pkg bld =
- const cleanall : (b : build# -> bool)
- const clean : (b : build#, targ : byte[:] -> bool)
- const cleanmyr : (b : build#, mt : myrtarg# -> void)
;;
-
-const cleanall = {b
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Bin bt:
- cleanup(b, bt, bt.inputs)
- | `Lib lt:
- cleanup(b, lt, lt.inputs)
- | `Gen gt:
- for f : gt.out
- if !gt.durable && std.remove(f)
- mbldput("\tclean {}\n", f)
- ;;
- ;;
- | `Data _: /* nothing to do */
- | `Cmd _: /* nothing to do */
- | `Man _: /* nothing to do */
- ;;
- ;;
- -> true
-}
-
-const clean = {b, targ
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Bin bt:
- if std.sleq(bt.name, targ)
- cleanup(b, bt, bt.inputs)
- ;;
- | `Lib lt:
- if std.sleq(lt.name, targ)
- cleanup(b, lt, lt.inputs)
- ;;
- | `Gen gt:
- for f : gt.out
- if !gt.durable && std.remove(f)
- mbldput("\tclean {}\n", f)
- ;;
- ;;
- | `Data _: /* nothing to do */
- | `Cmd _: /* nothing to do */
- | `Man _: /* nothing to do */
- ;;
- ;;
- -> true
-}
-
-const cleanmyr = {b, targ
- cleanup(b, targ, targ.inputs)
-}
-
-const cleanup = {b, targ, leaves
- var mchammer_files /* cant touch this */
- var keys, dg, test
-
- /*
- we want to automatically add 'clean' sources since otherwise,
- mbld won't be able to clean code after changing a build file.
- */
- setdir(b, targ.dir)
- dg = myrdeps(b, targ, true, true)
- mchammer_files = std.mkht(std.strhash, std.streq)
- for l : leaves
- std.htput(mchammer_files, l, true)
- ;;
-
- keys = std.htkeys(dg.deps)
- for k : keys
- if !std.htgetv(mchammer_files, k, false) && std.remove(k)
- mbldput("\tclean {}\n", k)
- ;;
- test = std.pathcat("test", k)
- if std.remove(test)
- mbldput("\tclean {}\n", test)
- ;;
- std.slfree(test)
- ;;
-}
-
--- a/mbld/deps.myr
+++ b/mbld/deps.myr
@@ -6,11 +6,19 @@
use "opts"
use "types"
use "util"
+use "libs"
pkg bld =
- const myrdeps : (b : build#, mt : myrtarg#, doclean : bool, addsrc : bool -> depgraph#)
+ const deps : (b : build# -> void)
+ const testdeps : (b : build# -> void)
+ const resolve : (b : build# -> void)
;;
+type dep = union
+ `Xdep byte[:]
+ `Ldep byte[:]
+;;
+
const Abiversion = 13
var usepat : regex.regex#
@@ -23,413 +31,568 @@
clibpat = std.try(regex.compile("/\\*\\s*LIBS:\\s*(.*)\\s*\\*/"))
}
+const deps = {b
+ for (name, `Gen gt) : std.byhtkeyvals(b.targs)
+ cmddeps(b, name, gt)
+ ;;
+ for name : b.all
+ match gettarg(b.targs, name)
+ | `Bin bt: myrdeps(b, name, bt)
+ | `Lib lt: myrdeps(b, name, lt)
+ | `Cmd ct: cmddeps(b, name, ct)
+ | `Man mt: mandeps(b, name, mt)
+ | `Data dt: datdeps(b, name, dt)
+ | `Gen gt: /* gen was dealt with earlier */
+ ;;
+ ;;
+}
-type dep = union
- `Local (byte[:], int)
- `Lib (byte[:], int)
-;;
+const testdeps = {b
+ for name : b.all
+ match gettarg(b.targs, name)
+ | `Bin bt: addtests(b, name, bt)
+ | `Lib lt: addtests(b, name, lt)
+ | _: /* skip */
+ ;;
+ ;;
+}
-type depscan = struct
- doclean : bool
- addsrc : bool
- tagsel : std.htab(byte[:], byte[:])#
- targ : myrtarg#
- incs : byte[:][:]
- depstk : byte[:][:]
-;;
+const myrdeps = {b, name, mt
+ var p, o, u, n, to, tu
+ var libs, dynlibs
+ var cflags, ll
+ var g, a, deps
+ var gu, go
-const myrdeps = {b, mt, doclean, addsrc
- var objs, uses, srcs
- var cflags, libs
- var out, useout
- var dg : depgraph#
- var ds : depscan
- var i
+ g = b.deps
+ if mt.islib
+ u = std.fmt("lib{}.use", mt.name)
+ o = std.fmt("lib{}.a", mt.name)
+ tu = std.pathcat(mt.dir, u)
+ to = std.pathcat(mt.dir, o)
- dg = std.mk([
- .deps = std.mkht(std.strhash, std.streq),
- .libs = std.mkht(std.strhash, std.streq),
- .input = std.mkht(std.strhash, std.streq),
- .sources = std.mkht(std.strhash, std.streq),
- .updated = std.mkht(std.strhash, std.streq),
- .seen = std.mkht(std.strhash, std.streq),
- .done = std.mkht(std.strhash, std.streq),
- .cflags = std.mkht(std.strhash, std.streq),
- .extlibs = [][:],
- .dynamic = false,
- ])
+ gu = node(g, tu)
+ go = node(g, to)
+ go.instdir = config.Libpath
+ gu.instdir = config.Libpath
+ go.instmod = 0o644
+ gu.instmod = 0o644
+ generates(g, gu, tu)
+ generates(g, go, to)
- /* direct dependencies of binary */
- if mt.islib
- out = std.fmt("lib{}.a", mt.name)
- useout = std.sldup(mt.name)
+ a = std.htgetv(g.targs, "all", [][:])
+ std.slpush(&a, gu)
+ std.slpush(&a, go)
+ std.htput(g.targs, to, std.sldup([gu, go][:]))
+ std.htput(g.targs, "all", a)
+
+ std.slfree(o)
+ std.slfree(u)
else
- out = std.sldup(mt.name)
- useout = ""
- ;;
+ u = std.fmt("{}.use", mt.name)
+ tu = std.pathcat(mt.dir, u)
+ to = std.pathcat(mt.dir, mt.name)
- ds = [
- .doclean = doclean,
- .addsrc = addsrc,
- .incs = mt.incpath,
- .targ = mt,
- .depstk = [][:],
- ]
- srcs = mt.inputs
- 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])
- elif std.hassuffix(srcs[i], ".glue.c")
- (cflags, libs) = scrapecflags(b, dg, srcs[i])
- std.htput(dg.cflags, srcs[i], cflags)
- std.sljoin(&dg.extlibs, libs)
- dg.dynamic = true
+ go = node(g, to)
+ gu = node(g, tu)
+
+ generates(g, go, to)
+ std.htput(g.targs, to, std.sldup([go][:]))
+ if mt.istest
+ n = node(g, mt.name)
+ depends(g, n, to)
+ addnode(g, "test", n)
+
+ n.wdir = std.sldup(mt.dir)
+ std.slpush(&n.cmd, std.fmt("./{}", mt.name))
+ else
+ addnode(g, "all", go)
+ go.instdir = config.Binpath
+ go.instmod = 0o755
;;
+
+ std.slfree(u)
;;
- for i = 0; i < srcs.len; i++
- pushdep(dg, objs[i], out)
- if !std.hassuffix(srcs[i], ".myr")
- continue
+ libs = [][:]
+ dynlibs = [][:]
+ for f : mt.inputs
+ p = std.pathcat(mt.dir, f)
+ leaf(g, p)
+ if std.hassuffix(f, ".myr")
+ o = changesuffix(p, config.Objsuffix)
+ u = changesuffix(p, ".use")
+ depends(g, go, o)
+ depends(g, gu, u)
+
+ n = node(g, o)
+ generates(g, n, o)
+ generates(g, n, u)
+ depends(g, n, p)
+
+ deps = scrapedeps(b, mt, p)
+ for `Ldep d : deps
+ depends(g, n, d)
+ ;;
+ for `Xdep d : deps
+ scrapelib(b, d, mt.incpath)
+ xdepends(b, g, n, d)
+ std.slpush(&libs, d)
+ ;;
+ myrcmd(b, n, mt, p, false)
+ std.slfree(deps)
+ elif std.hassuffix(f, ".s")
+ o = changesuffix(p, config.Objsuffix)
+ depends(g, go, o)
+ n = node(g, o)
+ generates(g, n, o)
+ depends(g, n, p)
+ ascmd(b, n, mt, o, p)
+ elif std.hassuffix(f, ".glue.c")
+ (cflags, ll) = scrapecflags(b, mt, p)
+ std.put("cflags: {}, ll: {}\n", cflags, ll)
+ o = changesuffix(p, config.Objsuffix)
+ depends(g, go, o)
+ n = node(g, o)
+ generates(g, n, o)
+ depends(g, n, p)
+ ccmd(b, n, mt, o, p, cflags)
+ for l : ll
+ std.slpush(&dynlibs, l)
+ ;;
+ elif std.hassuffix(f, config.Objsuffix)
+ /* handled by leaf */
+ else
+ std.fatal("don't know how to build {}/{}\n", mt.dir, f)
;;
- if mt.islib
- pushdep(dg, uses[i], useout)
- ;;
- srcdeps(b, &ds, dg, srcs[i], objs[i], uses[i])
;;
- dumpgraph(dg)
- -> dg
+ if mt.islib
+ arcmd(b, go, mt, to)
+ musecmd(b, gu, mt, tu)
+ builtlib(b, mt, libs, dynlibs)
+ else
+ linkcmd(b, go, mt, to, libs, dynlibs, false)
+ std.slfree(libs)
+ ;;
}
-const swapall = {srcs, suff
- var sl
+const cmddeps = {b, name, ct
+ var n, a, p, gen, pid
- sl = [][:]
- for s : srcs
- std.slpush(&sl, srcswapsuffix(s, suff))
+ n = node(b.deps, std.strjoin(ct.cmd, " "))
+ n.wdir = std.sldup(ct.dir)
+ n.durable = ct.durable
+
+ for c : ct.cmd
+ std.slpush(&n.cmd, std.sldup(c))
;;
- -> sl
-}
-const dumpgraph = {dg
- var keys
+ if ct.deps.len == 0
+ std.slpush(&b.deps.leaves, n)
+ else
+ for d : ct.deps
+ leaf(b.deps, d)
+ depends(b.deps, n, d)
+ ;;
+ ;;
- if !opt_debug
- -> void
+ gen = false
+ for g : ct.gen
+ p = std.pathcat(ct.dir, g)
+ gen = gen || !std.fexists(p)
+ generates(b.deps, n, p)
;;
- keys = std.htkeys(dg.deps)
- mbldput("digraph dg {{\n")
- for k : keys
- for v : std.htgetv(dg.deps, k, ["WTFUNKNOWN!"][:])
- mbldput("\t\"{}\" -> \"{}\";\n", k, v)
+
+ if ct.istest
+ a = std.htgetv(b.deps.targs, "test", [][:])
+ std.slpush(&a, n)
+ std.htput(b.deps.targs, "test", a)
+ elif gen
+ pid = run(ct.cmd, ct.dir)
+ match std.wait(pid)
+ | `std.Wfailure: std.fatal("FAIL: {j= }\n", ct.cmd)
+ | `std.Wsignalled: std.fatal("CRASH: {j= }\n", ct.cmd)
+ | `std.Waiterror: std.fatal("WAT: {j= }\n", ct.cmd)
+ | `std.Wsuccess: /* ok */
;;
;;
- mbldput("}\n")
}
-const srcdeps = {b, ds, g, path, obj, usefile
- var deps
+const mandeps = {b, name, mt
+ var p, r, n
- if std.hthas(g.done, path)
- -> void
- ;;
-
- std.slpush(&ds.depstk, path)
- if std.htgetv(g.seen, path, false)
- std.fput(1, "dependency loop involving {}:\n", path)
- for d : ds.depstk
- std.fput(1, "\t{}\n", d)
+ for pg : mt.pages
+ p = std.pathcat(mt.dir, pg)
+ n = leaf(b.deps, p)
+ match std.strfind(pg, ".")
+ | `std.None: std.fatal("manpage {} missing section\n", pg)
+ | `std.Some i: r = std.pathcat(config.Manpath, pg[i + 1:])
;;
- std.exit(1)
+ n.instdir = r
+ n.instmod = 0o644
+ addnode(b.deps, "all", n)
;;
- deps = getdeps(b, ds, path, std.dirname(path))
- std.htput(g.seen, path, true)
- for d : deps
- match d
- | `Lib (lib, lnum):
- /*
- 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 !ds.doclean
- scrapelibs(g, lib, ds.incs)
- ;;
- | `Local (l, lnum):
- if !std.hassuffix(l, ".use")
- std.sljoin(&l, ".use")
- ;;
- if obj.len != 0
- pushdep(g, l, obj)
- ;;
- if usefile.len != 0
- pushdep(g, l, usefile)
- ;;
- addusedep(b, ds, g, path, l, lnum)
- ;;
- ;;
- std.slgrow(&ds.depstk, ds.depstk.len - 1)
- std.htput(g.seen, path, false)
- std.htput(g.done, path, true)
}
-const addusedep = {b, ds, g, f, usefile, line
- var src
+const datdeps = {b, name, dt
+ var p, n
- if std.hthas(g.done, usefile)
- if opt_debug
- mbldput("already loaded deps for {}\n", usefile)
+ for db : dt.blobs
+ p = std.pathcat(dt.dir, db)
+ n = leaf(b.deps, p)
+ if dt.path.len == 0
+ n.instdir = config.Sharepath
+ else
+ n.instdir = dt.path
;;
- -> void
+ n.instmod = 0o644
+ addnode(b.deps, "all", n)
;;
- match std.htget(g.input, usefile)
- | `std.Some path:
- src = std.sldup(path)
- | `std.None:
- src = swapsuffix(usefile, ".use", ".myr")
- if ds.addsrc
- std.htput(g.sources, src, true)
- elif !std.hthas(g.input, usefile)
- std.fatal("{}:{}: source file {} not listed in bldfile\n", f, line, src)
- ;;
+}
+
+const addtests = {b, name, mt
+ for f : mt.inputs
+ addtest(b, mt, f)
;;
- pushdep(g, src, usefile)
- std.htput(g.input, usefile, src)
- srcdeps(b, ds, g, src, "", usefile)
- std.htput(g.done, usefile, true)
}
-const scrapecflags = {b, ds, path
- var cflags, libs, lnum
- var f
+const addtest = {b, mt, f
+ var libs, deps
+ var sp, tp, op
+ var s, t, o
+ var g, n
+ var testinc
- lnum = 0
- cflags = [][:]
+ /*
+ change of suffix is to support testing assembly,
+ C glue, and foo+sys.myr forms.
+ */
+ g = b.deps
+ s = changesuffix(f, ".myr")
+ sp = std.pathjoin([mt.dir, "test", s][:])
+ std.slfree(s)
+ if !std.fexists(sp)
+ std.slfree(sp)
+ -> void
+ ;;
+
libs = [][:]
- f = opensrc(b, path)
- while true
- lnum++
- match bio.readln(f)
- | `bio.Err e: std.fatal("unable to read {}: {}\n", path, e)
- | `bio.Eof: break
- | `bio.Ok ln:
- (cflags, libs) = getcflags(ln, cflags, libs)
- std.slfree(ln)
- ;;
+ leaf(g, sp)
+
+ t = changesuffix(f, "")
+ tp = std.pathjoin([mt.dir, "test", t][:])
+ std.slfree(t)
+
+ o = changesuffix(f, config.Objsuffix)
+ op = std.pathjoin([mt.dir, "test", o][:])
+ std.slfree(o)
+
+ n = node(g, sp)
+ generates(g, n, op)
+ depends(g, n, sp)
+ testinc = [][:]
+ std.slpush(&testinc, mt.dir)
+ std.sljoin(&testinc, mt.incpath)
+ deps = scrapedeps(b, mt, sp)
+ for `Ldep d : deps
+ depends(g, n, d)
;;
- bio.close(f)
- -> (cflags, libs)
+ for `Xdep d : deps
+ scrapelib(b, d, mt.incpath)
+ xdepends(b, g, n, d)
+ std.slpush(&libs, d)
+ ;;
+ myrcmd(b, n, mt, sp, true)
+ std.slfree(mt.incpath)
+
+ n = node(g, tp)
+ generates(g, n, tp)
+ depends(g, n, op)
+ linkcmd(b, n, mt, tp, libs, [][:], true)
+ std.slfree(libs)
+
+ n = node(g, tp)
+ depends(g, n, tp)
+ n.wdir = std.sldup(std.dirname(std.dirname(tp)))
+ std.slpush(&n.cmd, std.fmt("./test/{}", std.basename(tp)))
+
+ addnode(g, "test", n)
}
-const getcflags = {ln, cflags, libs
- var flags
+const resolve = {b
+ var visited, looped, stk
+ var g
- match regex.exec(cflagpat, ln)
- | `std.None:
- | `std.Some m:
- flags = std.strtok(m[1])
- for fl : flags
- std.slpush(&cflags, std.sldup(fl))
+ g = b.deps
+ for n : g.nodes
+ for e : n.dep
+ edge(g, n, e)
;;
- std.slfree(flags)
- regex.matchfree(m)
;;
- match regex.exec(clibpat, ln)
+ stk = [][:]
+ visited = std.mkht(std.ptrhash, std.ptreq)
+ looped = std.mkht(std.ptrhash, std.ptreq)
+ for n : g.nodes
+ checkloop(g, n, visited, looped, &stk)
+ ;;
+ std.htfree(visited)
+ std.htfree(looped)
+}
+
+const edge = {g, n, e
+ match std.htget(g.gen, e)
| `std.None:
- | `std.Some m:
- flags = std.strtok(m[1])
- for fl : flags
- std.slpush(&libs, std.sldup(fl))
- ;;
- std.slfree(flags)
- regex.matchfree(m)
+ std.fatal("nothing satisfies {} for {}\n", e, n.lbl)
+ | `std.Some d:
+ std.slpush(&n.ndep, d)
+ std.slpush(&d.ngen, n)
+ n.nblock++
;;
- -> (cflags, libs)
}
-const getdeps = {b, ds, path, dir
- var deps, lnum
- var f
-
- lnum = 0
- deps = [][:]
- f = opensrc(b, path)
- while true
- lnum++
- match bio.readln(f)
- | `bio.Err e: std.fatal("unable to read {}: {}\n", path, e)
- | `bio.Eof: break
- | `bio.Ok ln:
- deps = depname(deps, ln, lnum, dir)
- std.slfree(ln)
- ;;
+const checkloop = {g, n, visited, looped, stk
+ if std.hthas(looped, n)
+ std.slpush(stk, n.lbl)
+ std.fatal("dependency loop: {j= -> }\n", stk#)
;;
- bio.close(f)
- -> deps
+ if std.hthas(visited, n)
+ -> void
+ ;;
+ std.slpush(stk, n.lbl)
+ std.htput(visited, n, void)
+ std.htput(looped, n, void)
+ for d : n.ndep
+ checkloop(g, d, visited, looped, stk)
+ ;;
+ std.slpop(stk)
+ std.htdel(looped, n)
}
-const opensrc = {b, path
- if !std.fexists(path)
- match std.htget(b.gensrc, path)
- | `std.Some gt: run(gt.cmd)
- | `std.None: std.fatal("no input file {}\n", path)
- ;;
+const musecmd = {b, n, mt, mu
+ std.slpush(&n.cmd, std.sldup(opt_muse))
+ std.slpush(&n.cmd, std.sldup("-o"))
+ std.slpush(&n.cmd, std.sldup(mu))
+ std.slpush(&n.cmd, std.sldup("-p"))
+ std.slpush(&n.cmd, std.sldup(mt.name))
+ for u : n.dep
+ std.slpush(&n.cmd, std.sldup(u))
;;
+}
- match bio.open(path, bio.Rd)
- | `std.Err m: std.fatal("could not open {}: {}\n", path, m)
- | `std.Ok f: -> f
+const arcmd = {b, n, mt, ar
+ for c : config.Arcmd
+ std.slpush(&n.cmd, std.sldup(c))
;;
+ std.slpush(&n.cmd, std.sldup(ar))
+ for obj : n.dep
+ std.slpush(&n.cmd, std.sldup(obj))
+ ;;
}
-const depname = {deps, ln, lnum, dir
- var p
+const linkcmd = {b, n, mt, bin, libs, dynlibs, istest
+ for c : config.Linkcmd
+ std.slpush(&n.cmd, std.sldup(c))
+ ;;
+ std.slpush(&n.cmd, std.sldup(bin))
+ if mt.ldscript.len > 0
+ std.slpush(&n.cmd, std.sldup("-T"))
+ std.slpush(&n.cmd, std.sldup(mt.ldscript))
+ ;;
- /*
- 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
- std.slpush(&deps, `Lib (std.sldup(uses[2]), lnum))
- else
- p = std.pathcat(dir, std.sldup(uses[3]))
- std.slpush(&deps, `Local (p, lnum))
- ;;
- regex.matchfree(uses)
- | `std.None:
- /* nothing to do */
+ if mt.runtime.len == 0 || std.sleq(mt.runtime, "none")
+ std.slpush(&n.cmd, std.sldup(opt_runtime))
+ else
+ std.slpush(&n.cmd, std.sldup(mt.runtime))
;;
- -> deps
-}
-const scrapelibs = {dg, lib, incs
- var deps, d
- var f
- var done
+ for o : n.dep
+ std.slpush(&n.cmd, std.sldup(o))
+ ;;
- if std.hthas(dg.libs, lib)
- -> void
+ addlibs(b, &n.cmd, libs, mt.incpath)
+ for l : dynlibs
+ std.slpush(&n.cmd, std.fmt("-l{}", l))
;;
- f = openlib(lib, incs)
- match bio.getc(f)
- | `bio.Ok 'U': /* nothing */
- | `bio.Ok _: std.fatal("library {}: corrupt or invalid usefile\n", lib)
- | `bio.Err e: std.fatal("library {}: could not read usefile: {}\n", lib, e)
- | `bio.Eof: std.fatal("library {}: could not read usefile\n", lib)
+ /* OSX warns if we don't add a version */
+ if std.sleq(opt_sys, "osx")
+ std.slpush(&n.cmd, std.sldup("-macosx_version_min"))
+ std.slpush(&n.cmd, std.sldup("10.6"))
+ elif std.sleq(opt_sys, "linux") && dynlibs.len != 0
+ std.slpush(&n.cmd, std.sldup("-dynamic-linker"))
+ std.slpush(&n.cmd, std.sldup("/lib64/ld-linux-x86-64.so.2"))
;;
- match bio.getbe32(f)
- | `bio.Ok Abiversion: /* nothing: version matches. */
- | `bio.Ok v:
- if v < Abiversion
- std.fput(1, "library {}: warning: old abi version {}\n", lib, v)
- else
- std.fput(1, "library {}: usefile version {} unknown\n", lib, v)
+
+}
+
+const myrcmd = {b, n, mt, src, istest
+ std.slpush(&n.cmd, opt_mc)
+ for inc : mt.incpath[:mt.incpath.len - 1]
+ pushinc(&n.cmd, "-I", inc)
+ ;;
+ if istest
+ for (dir, _, _) : mt.tstdeps
+ pushinc(&n.cmd, "-I", dir)
;;
- | `bio.Err e: std.fatal("library {}: error reading usefile: {}\n", lib, e)
- | `bio.Eof: std.fatal("library {}: corrupt or truncated usefile\n", lib)
+ pushinc(&n.cmd, "-I", mt.dir)
;;
- std.slfree(rdstr(f))
+ for (dir, _, _) : mt.libdeps
+ pushinc(&n.cmd, "-I", dir)
+ ;;
+ if opt_genasm
+ std.slpush(&n.cmd, "-S")
+ ;;
+ std.slpush(&n.cmd, src)
+}
- done = false
- deps = [][:]
- while !done
- match bio.getc(f)
- | `bio.Ok 'L':
- d = rdstr(f)
- std.slpush(&deps, d)
- | `bio.Ok 'X':
- d = rdstr(f)
- std.slpush(&dg.extlibs, d)
- dg.dynamic = true
- | `bio.Ok _: done = true
- | `bio.Eof: done = true
- | `bio.Err e: std.fatal("io error reading {}: {}", lib, e)
- ;;
+const ascmd = {b, n, mt, out, src
+ for c : config.Ascmd
+ std.slpush(&n.cmd, c)
;;
- bio.close(f)
- std.htput(dg.libs, lib, deps)
- for dep : deps
- scrapelibs(dg, dep, incs)
+ std.slpush(&n.cmd,"-o")
+ std.slpush(&n.cmd, out)
+ std.slpush(&n.cmd, src)
+}
+
+const ccmd = {b, n, mt, out, src, cflags
+ std.slpush(&n.cmd, "cc")
+ std.slpush(&n.cmd,"-c")
+ std.slpush(&n.cmd,"-o")
+ std.slpush(&n.cmd, out)
+ std.slpush(&n.cmd, src)
+ for flg : cflags
+ std.slpush(&n.cmd, flg)
;;
}
-const openlib = {lib, incs
- var path, libname
+const scrapedeps = {b : build#, mt, path
+ var p, f, l
- for p : incs
- libname = std.fmt("lib{}.use", lib)
- path = std.pathjoin([p, libname][:])
- std.slfree(libname)
- if std.fisreg(path)
- goto found
- ;;
- std.slfree(path)
+ match bio.open(path, bio.Rd)
+ | `std.Ok fd: f = fd
+ | `std.Err e: std.fatal("error opening {}: {}\n", path, e)
+ ;;
- path = std.pathjoin([p, lib][:])
- if std.fisreg(path)
- goto found
+ l = [][:]
+ for ln : bio.byline(f)
+ match regex.exec(usepat, ln)
+ | `std.None:
+ | `std.Some uses:
+ if uses[2].len > 0
+ /* external library */
+ p = std.sldup(uses[2])
+ std.slpush(&l, `Xdep p)
+ else
+ /* internal library */
+ p = std.pathcat(mt.dir, uses[3])
+ std.sljoin(&p, ".use")
+ std.slpush(&l, `Ldep p)
+ ;;
+ regex.matchfree(uses)
;;
- std.slfree(path)
;;
+ bio.close(f)
+ -> l
+}
- libname = std.fmt("lib{}.use", lib)
- path = std.pathjoin([opt_instbase, config.Libpath, libname][:])
- if !std.fisreg(path)
- std.slfree(path)
- path = std.pathjoin([opt_instbase, config.Libpath, lib][:])
+const scrapecflags = {b, mt, path
+ var f, fl, cflags, libs
+
+ match bio.open(path, bio.Rd)
+ | `std.Ok fd: f = fd
+ | `std.Err e: std.fatal("error opening {}: {}\n", path, e)
;;
- std.slfree(libname)
-:found
- match bio.open(path, bio.Rd)
- | `std.Ok file:
- std.slfree(path)
- -> file
- | `std.Err m:
+ cflags = [][:]
+ libs = [][:]
+ for ln : bio.byline(f)
+ match regex.exec(cflagpat, ln)
+ | `std.None: /* skip */
+ | `std.Some m:
+ fl = std.strtok(m[1])
+ for s : fl
+ std.slpush(&cflags, std.sldup(s))
+ ;;
+ std.slfree(fl)
+ ;;
+ match regex.exec(clibpat, ln)
+ | `std.None: /* skip */
+ | `std.Some m:
+ fl = std.strtok(m[1])
+ for s : fl
+ std.slpush(&libs, std.sldup(s))
+ ;;
+ std.slfree(fl)
+ ;;
;;
- std.fput(std.Err, "could not find library {}\n", lib)
- std.fput(std.Err, "search path is:\n")
- for p : incs
- std.fput(std.Err, "\t{}\n", p)
- ;;
- std.fput(std.Err, "\t{}\n", config.Libpath)
- std.exit(1)
+ -> (cflags, libs)
}
-/* pushes a dep into the dependency list */
-const pushdep = {dg, src, dst
- var sl
+const generates = {g, n, dep
+ std.slpush(&n.gen, dep)
+ std.htput(g.gen, dep, n)
+}
- if opt_debug
- mbldput("{} <= {}\n", dst, src)
+const depends = {g, n, dep
+ std.slpush(&n.dep, dep)
+}
+
+const xdepends = {b, g, n, dep
+ match std.htget(b.libs, dep)
+ | `std.Some ldep:
+ if ldep.genuse.len != 0
+ depends(g, n, ldep.genuse)
+ depends(g, n, ldep.genar)
+ ;;
+ std.slpush(&n.xdep, dep)
+ | `std.None:
+ std.fatal("unknown xdep {} (known: {})\n", dep, std.htkeys(b.libs))
;;
- sl = std.htgetv(dg.deps, dst, [][:])
- std.slpush(&sl, src)
- std.htput(dg.deps, dst, sl)
}
-const rdstr = {f
- var len
- var sl
+const leaf = {g, f
+ var nod
- match bio.getbe32(f)
- | `bio.Ok l:
- len = l
- sl = std.slalloc(len)
- | `bio.Eof: std.fatal("end of file while reading string")
- | `bio.Err e: std.fatal("error while reading string: {}", e)
+ match std.htget(g.gen, f)
+ | `std.Some n:
+ -> n
+ | `std.None:
+ nod = node(g, f)
+ nod.durable = true
+ generates(g, nod, f)
+ std.slpush(&g.leaves, nod)
+ -> nod
;;
- bio.read(f, sl)
- -> sl
+}
+
+const addnode = {g, targ, n
+ var nl
+
+ nl = std.htgetv(g.targs, targ, [][:])
+ std.slpush(&nl, n)
+ std.htput(g.targs, targ, nl)
+}
+
+const pushinc = {lst, pfx, dir
+ std.slpush(lst, std.sldup(pfx))
+ std.slpush(lst, std.pathnorm(dir))
+}
+
+const node = {g, lbl
+ var nod
+
+ nod = std.mk([
+ .lbl=lbl,
+ .cmd=[][:],
+ .gen=[][:],
+ .dep=[][:],
+ .xdep=[][:],
+
+ .nblock=0,
+ .mtime=0,
+ ])
+ std.slpush(&g.nodes, nod)
+ -> nod
}
--- a/mbld/install.myr
+++ b/mbld/install.myr
@@ -1,9 +1,7 @@
use std
use "config"
-use "deps"
use "opts"
-use "parse"
use "types"
use "util"
use "build"
@@ -14,7 +12,7 @@
;;
const install = {b
- buildall(b)
+ buildtarg(b, "all")
-> movetargs(b, false)
}
@@ -23,54 +21,28 @@
}
const movetargs = {b, rm
- var libarchive, libuse
- var pfx
+ var inst
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Bin bt:
- if bt.install && !bt.istest
- movefile(b, rm, bt.dir, bt.name, config.Binpath, 0o755)
+ inst = std.htgetv(b.deps.targs, "all", [][:])
+ for n : inst
+ if n.instdir.len == 0
+ continue
+ ;;
+ for g : n.gen
+ if !movefile(b, rm, g, n.instdir, n.instmod)
+ -> false
;;
- | `Lib lt:
- if lt.install && !lt.istest
- libuse = std.fmt("lib{}.use", lt.name)
- movefile(b, rm, lt.dir, libuse, config.Libpath, 0o644)
- libarchive = std.fmt("lib{}.a", lt.name)
- movefile(b, rm, lt.dir, libarchive, config.Libpath, 0o644)
- std.slfree(libarchive)
- std.slfree(libuse)
- ;;
- | `Data dt:
- for blob : dt.blobs
- if dt.path.len == 0
- pfx = std.pathcat(config.Sharepath, dt.name)
- movefile(b, rm, dt.dir, blob, pfx, 0o644)
- std.slfree(pfx)
- else
- movefile(b, rm, dt.dir, blob, dt.path, 0o644)
- ;;
- ;;
- | `Gen gt:
- /* nothing to do */
- | `Cmd ct:
- /* nothing to do */
- | `Man mt:
- /* FIXME: figure out man section by number */
- for m : mt.pages
- moveman(b, rm, mt.dir, m)
- ;;
;;
;;
-> true
+
}
-const movefile = {b, rm, dir, file, prefix, perm
- var path
+const movefile = {b, rm, file, prefix, perm
+ var path, ok
- setdir(b, dir)
- makepath(prefix)
- path = std.pathjoin([opt_destdir, opt_instbase, prefix, file][:])
+ ok = true
+ path = std.pathjoin([opt_destdir, opt_instbase, prefix, std.basename(file)][:])
if rm
mbldput("\trm {}\n", path)
if !std.remove(path)
@@ -78,42 +50,18 @@
;;
else
std.remove(path)
+ std.mkpath(std.dirname(path))
match std.slurp(file)
| `std.Err m: std.fatal("could not open {} for reading\n", file)
| `std.Ok buf:
- if std.blat(path, buf, perm)
- mbldput("\t{} => {}\n", file, path)
- else
+ mbldput("\t{} => {}\n", file, path)
+ if !std.blat(path, buf, perm)
mbldput("could not write {}\n", file)
+ ok = false
;;
;;
;;
std.slfree(path)
+ -> ok
}
-const moveman = {b, rm, dir, man
- var sect, manrel
-
- match std.strrfind(man, ".")
- | `std.None:
- std.fatal("manpage {} has no section\n", man)
- | `std.Some s:
- sect = s + 1
- if s + 1 == man.len
- std.fatal("manpage {} missing suffix\n", man)
- ;;
- ;;
-
- manrel = std.fmt("{}{}", config.Manpath, man[sect:])
- makepath(manrel)
- movefile(b, rm, dir, man, manrel, 0o644)
- std.slfree(manrel)
-}
-
-const makepath = {prefix
- var p
-
- p = std.pathjoin([opt_destdir, opt_instbase, prefix][:])
- std.mkpath(p)
- std.slfree(p)
-}
--- /dev/null
+++ b/mbld/libs.myr
@@ -1,0 +1,187 @@
+use std
+use bio
+
+use "config"
+use "opts"
+use "types"
+
+pkg bld =
+ const addlibs : (b : build#, \
+ sl : byte[:][:]#, \
+ libs : byte[:][:], \
+ incs : byte[:][:] -> void)
+
+ const builtlib : (b : build#, \
+ lt : myrtarg#, \
+ dep : byte[:][:], \
+ dyndep : byte[:][:] -> void)
+
+ const scrapelib : (b : build#, libs : byte[:], incs : byte[:][:] -> void)
+;;
+
+const Abiversion = 13
+
+const builtlib = {b, mt, dep, dyndep
+ var ldep, l, u
+
+ l = std.fmt("lib{}.a", mt.name)
+ u = std.fmt("lib{}.use", mt.name)
+ ldep = std.mk([
+ .name=mt.name,
+ .dir=mt.dir,
+ .dep=dep,
+ .dyndep=dyndep,
+ .genuse=std.pathjoin([b.objdir, mt.dir, u][:]),
+ .genar=std.pathjoin([b.objdir, mt.dir, l][:]),
+ ])
+ std.slfree(l)
+ std.slfree(u)
+ for d : dep
+ scrapelib(b, d, mt.incpath)
+ ;;
+ std.htput(b.libs, mt.name, ldep)
+}
+
+const scrapelib = {b, lib, incs
+ var dep, dyndep, ldep
+ var f, dir
+
+ if std.hthas(b.libs, lib)
+ -> void
+ ;;
+
+ (f, dir) = openlib(lib, incs)
+ match bio.getc(f)
+ | `bio.Ok 'U': /* ok */
+ | `bio.Ok _: std.fput(1, "{}: not a usefile\n", lib)
+ | `bio.Err e: std.fatal("{}: error reading: {}\n", lib, e)
+ | `bio.Eof: std.fatal("{}: truncated\n", lib)
+ ;;
+ match bio.getbe32(f)
+ | `bio.Ok Abiversion: /* nothing: version matches. */
+ | `bio.Ok v: std.fput(1, "{}: mismatched abi {}\n", lib, v)
+ | `bio.Err e: std.fatal("{}: error reading: {}\n", lib, e)
+ | `bio.Eof: std.fatal("{}: truncated\n", lib)
+ ;;
+ std.slfree(rdstr(f))
+
+ dep = [][:]
+ dyndep = [][:]
+ while true
+ match bio.getc(f)
+ | `bio.Ok 'L': std.slpush(&dep, rdstr(f))
+ | `bio.Ok 'X': std.slpush(&dyndep, rdstr(f))
+ | `bio.Err e: std.fatal("{}: error reading {}", lib, e)
+ | _: break;
+ ;;
+ ;;
+ bio.close(f)
+ ldep = std.mk([
+ .name=lib,
+ .dir=dir,
+ .dep=dep,
+ .dyndep=dyndep,
+ .genuse="",
+ .genar="",
+ ])
+ std.htput(b.libs, lib, ldep)
+
+ for d : dep
+ scrapelib(b, d, incs)
+ ;;
+}
+
+const openlib = {lib, incs : byte[:][:]
+ var path, libname
+
+ path = ""
+ libname = ""
+ for p : incs
+ libname = std.fmt("lib{}.use", lib)
+ path = std.pathjoin([p, libname][:])
+ std.slfree(libname)
+ if std.fisreg(path)
+ match bio.open(path, bio.Rd)
+ | `std.Ok file:
+ std.slfree(path)
+ -> (file, p)
+ | `std.Err m:
+ ;;
+ std.fatal("{} does not exist in {j=, }\n", lib, incs)
+ ;;
+ std.slfree(path)
+ ;;
+ std.fatal("{} does not exist in {j= }\n", lib, incs)
+}
+
+const addlibs = {b, sl, libs, incs
+ var added, diradded, looped
+ var lo
+
+ added = std.mkht(std.strhash, std.streq)
+ looped = std.mkht(std.strhash, std.streq)
+ diradded = std.mkht(std.strhash, std.streq)
+
+ lo = sl#.len
+ for l : libs
+ addlib(b, sl, l, added, diradded, looped)
+ ;;
+ for var i = 0; i < sl#[lo:].len/2; i++
+ std.swap(&sl#[lo+i], &sl#[sl#.len - i - 1])
+ ;;
+
+ std.htfree(diradded)
+ std.htfree(looped)
+ std.htfree(added)
+}
+
+const addlib = {b, sl, lib, added, diradded, looped
+ var ar
+
+ if std.hthas(looped, lib)
+ std.fatal("{}: loop in deps\n", lib)
+ ;;
+ std.htput(looped, lib, void)
+ match std.htget(b.libs, lib)
+ | `std.None:
+ std.slpush(sl, std.fmt("-l{}", lib))
+ | `std.Some ld:
+ for l : ld.dep
+ addlib(b, sl, l, added, diradded, looped)
+ ;;
+ for l : ld.dyndep
+ addlib(b, sl, l, added, diradded, looped)
+ ;;
+ if !std.hthas(added, lib)
+ if config.Directlib
+ ar = std.fmt("lib{}.a", lib)
+ std.slpush(sl, std.pathcat(ld.dir, ar))
+ std.slfree(ar)
+ else
+ std.slpush(sl, std.fmt("-l{}", lib))
+ ;;
+ std.htput(added, lib, void)
+ ;;
+ if !config.Directlib && !std.hthas(diradded, ld.dir)
+ std.htput(diradded, ld.dir, void)
+ std.slpush(sl, std.fmt("-L{}", ld.dir))
+ ;;
+ ;;
+ std.htdel(looped, lib)
+}
+
+
+const rdstr = {f -> byte[:]
+ var len
+ var sl
+
+ match bio.getbe32(f)
+ | `bio.Ok l:
+ len = l
+ sl = std.slalloc(len)
+ | `bio.Eof: std.fatal("end of file while reading string")
+ | `bio.Err e: std.fatal("error while reading string: {}", e)
+ ;;
+ bio.read(f, sl)
+ -> sl
+}
--- a/mbld/main.myr
+++ b/mbld/main.myr
@@ -1,8 +1,8 @@
use std
use regex
+use thread
use "build"
-use "clean"
use "config"
use "deps"
use "install"
@@ -18,9 +18,11 @@
var bintarg
var targname
var runsrc
+ var path
var tmp
var cmd
var tags
+ var pid
var ok, r
cmd = std.optparse(args, &[
@@ -35,8 +37,6 @@
[.opt='b', .arg="bin", .desc="compile binary named 'bin' from inputs"],
[.opt='l', .arg="lib", .desc="compile lib named 'lib' from inputs"],
[.opt='r', .arg="rt", .desc="link against runtime 'rt' instead of default"],
- [.opt='C', .arg="mc", .desc="compile with 'mc' instead of the default compiler"],
- [.opt='M', .arg="mu", .desc="merge uses with 'mu' instead of the default muse"],
][:]
])
@@ -46,7 +46,7 @@
ok = true
bld.initopts()
- for opt : cmd.opts
+ for opt in cmd.opts
match opt
| ('S', ""): bld.opt_genasm = true
| ('I', arg): std.slpush(&bld.opt_incpaths, arg)
@@ -70,41 +70,46 @@
building with an uninstalled compiler.
*/
| ('d', arg): bld.opt_debug = true
- | ('C', arg): bld.opt_mc = arg
- | ('M', arg): bld.opt_muse = arg
| _: std.die("unreachable\n")
;;
;;
+ path = std.pathcat(bld.opt_instbase, config.Libpath)
+ std.slpush(&bld.opt_incpaths, path)
- for (e, v) : config.Env
+ for (e, v) in config.Env
std.setenv(e, v)
;;
b = mkbuild(tags)
if targname.len != 0
- buildimm(b, targname, cmd.args, bintarg)
+ buildimm(b, targname, cmd.args)
elif runsrc.len != 0
bld.opt_silent = true
tmp = std.mktemppath("runmyr")
- ok = buildimm(b, tmp, [runsrc][:], true)
+ ok = buildimm(b, tmp, [runsrc][:])
if ok
- ok = runcmd(tmp, cmd.args)
+ pid = runcmd(tmp, cmd.args)
+ match std.wait(pid)
+ | `std.Wsuccess: ok = true
+ | _: ok = false
+ ;;
;;
std.remove(tmp)
else
- findproj(b, "bld.proj")
+ findproj(b)
bld.load(b)
+ bld.deps(b)
+ bld.testdeps(b)
+ bld.resolve(b)
/*bld.configure()*/
/* default: buildall */
if cmd.args.len == 0
- bld.buildall(b)
+ bld.buildtarg(b, "all")
else
- for c : cmd.args
+ for c in cmd.args
match c
- | "all": r = bld.buildall(b)
- | "gen": r = bld.genall(b)
- | "clean": r = bld.cleanall(b)
+ | "clean": r = bld.clean(b)
| "install": r = bld.install(b)
| "uninstall": r = bld.uninstall(b)
| "test": r = bld.test(b)
@@ -119,7 +124,7 @@
;;
}
-const buildimm = {b, targ, inputs, bintarg -> bool
+const buildimm = {b, targ, inputs
var mt : bld.myrtarg
mt = [
@@ -129,11 +134,11 @@
.incpath=bld.opt_incpaths,
.libdeps=[][:]
]
- if bintarg
- -> bld.buildbin(b, &mt, true)
- else
- -> bld.buildlib(b, &mt)
- ;;
+ std.slpush(&b.all, "__out__")
+ std.htput(b.targs, "__out__", `bld.Bin &mt)
+ bld.deps(b)
+ bld.resolve(b)
+ -> bld.buildtarg(b, "all")
}
const runcmd = {bin, args
@@ -140,7 +145,7 @@
var sl
sl = std.sldup([bin][:])
- -> bld.run(std.sljoin(&sl, args))
+ -> bld.run(std.sljoin(&sl, args), "")
}
const mkbuild = {tags
@@ -147,37 +152,33 @@
var b
b = std.zalloc()
+ b.libs = std.mkht(std.strhash, std.streq)
+ b.proc = std.mkht(std.inthash, std.inteq)
b.targs = std.mkht(std.strhash, std.streq)
- b.gensrc = std.mkht(std.strhash, std.streq)
- b.built = std.mkht(std.strhash, std.streq)
b.tags = std.mkht(std.strhash, std.streq)
+ b.deps = std.mk([
+ .targs = std.mkht(std.strhash, std.streq),
+ .gen = std.mkht(std.strhash, std.streq),
+ .leaves = [][:],
+ .nodes = [][:],
+ ])
bld.addsysattrs(b, tags)
-> b
}
-const findproj = {b, bldfile
- if !findbase(b, bldfile) || !std.chdir(b.basedir)
- std.fatal("could not find {}\n", bldfile)
- ;;
- bld.setdir(b, "")
-}
+const findproj = {b
+ var dir
-const findbase = {b, file
- var p, bld, dir
-
dir = std.getcwd()
- while !std.sleq(dir, "/")
- bld = std.pathcat(dir, file)
- if std.fexists(bld)
- bld.mbldput("project base {}:\n", dir)
+ while dir.len > 0 && !std.sleq(dir, "/")
+ if std.chdir(dir) && std.fexists("bld.proj")
b.basedir = dir
- b.bldfile = bld
- -> true
+ break
;;
- p = std.pathcat(dir, "..")
- std.slfree(dir)
- dir = p
+ dir = std.dirname(dir)
;;
- -> false
+ if dir.len > 0 && std.sleq(b.basedir, "/")
+ std.fatal("could not find bld.proj\n")
+ ;;
}
--- a/mbld/opts.myr
+++ b/mbld/opts.myr
@@ -1,4 +1,5 @@
use std
+use thread
use "config"
@@ -12,6 +13,7 @@
var opt_instbase : byte[:]
var opt_destdir : byte[:]
var opt_outdir : byte[:]
+ var opt_maxproc : std.size
var opt_debug : bool
var opt_silent : bool
@@ -44,6 +46,7 @@
var opt_ar = "ar"
var opt_genasm = false
var opt_silent = false
+var opt_maxproc = 1
const initopts = {
var si
@@ -67,6 +70,7 @@
| unknown: std.fatal("unknown architecture \"{}\"\n", unknown)
;;
+ opt_maxproc = 2*(thread.ncpu() : std.size)
opt_incpaths = [][:]
opt_instbase = config.Instroot
opt_destdir = std.getenvv("DESTDIR", "")
@@ -84,7 +88,7 @@
i = 0
a = [0, 0, 0]
- for e : std.bysplit(v, ".")
+ for e in std.bysplit(v, ".")
match std.intparse(e)
| `std.Some n: a[i++] = n
| `std.None: continue
--- a/mbld/parse.myr
+++ b/mbld/parse.myr
@@ -40,7 +40,7 @@
var targs
sel = mksyssel(b, "mbld", 0, "mbld")
- ok = loadall(b, b.bldfile, "", sel)
+ ok = loadall(b, "bld.proj", "", sel)
targs = sysselfin(sel)
for (name, targ) : targs
@@ -55,6 +55,56 @@
-> 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 : b.all
+ match gettarg(b.targs, dep)
+ | `Bin _: all = visit(all, b, "all", dep, looped, marked)
+ | `Lib _: all = visit(all, b, "all", dep, looped, marked)
+ | targ: std.slpush(&all, dep)
+ ;;
+ ;;
+ std.slfree(b.all)
+ b.all = all
+ -> true
+}
+
+const visit = {all, b, parent, targ, looped, marked
+ if std.hthas(looped, targ)
+ std.fatal("cycle in build depgraph involving {}\n", targ)
+ elif std.hthas(marked, targ)
+ -> all
+ ;;
+
+ std.htput(looped, targ, true)
+ for (dir, lib, dep) : getdeps(b, parent, targ)
+ all = visit(all, b, targ, dep, looped, marked)
+ ;;
+ std.htdel(looped, targ)
+ std.htput(marked, targ, true)
+ -> std.slpush(&all, targ)
+}
+
+const getdeps = {b, parent, targname
+ match std.htget(b.targs, targname)
+ | `std.Some targ:
+ match targ
+ | `Bin t: -> t.libdeps
+ | `Lib t: -> t.libdeps
+ | _: std.fatal("{} depends on non-library target", parent)
+ ;;
+ | `std.None:
+ std.fatal("{}: could not find dependency {}\n", parent, targname)
+ ;;
+}
+
+/* recursively load all bld.{proj,sub} files in project */
const loadall = {b, path, dir, sel
var p : parser#
var subbld, subproj, ok
@@ -62,8 +112,12 @@
p = mkparser(path, dir, b.basedir, sel)
ok = bld.parse(b, p, "")
- for t : p.targs
- setopts(p, t)
+ for targ : p.targs
+ match targ
+ | `Bin t: setmyropt(p, t)
+ | `Lib t: setmyropt(p, t)
+ | _: /* only myr targets have settable defaults so far */
+ ;;
;;
for sub : p.subdirs
@@ -95,14 +149,6 @@
-> ok
}
-const setopts = {p, targ
- match targ
- | `Bin t: setmyropt(p, t)
- | `Lib t: setmyropt(p, t)
- | _: /* only myr targets have settable defaults so far */
- ;;
-}
-
const setmyropt = {p, t
var libdep, tstdep
@@ -127,7 +173,6 @@
const parse = {b, p, path
while true
- skipspace(p)
if !target(b, p)
break
;;
@@ -198,55 +243,6 @@
std.free(p)
}
-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 : b.all
- match gettarg(b.targs, dep)
- | `Bin _: all = visit(all, b, "all", dep, looped, marked)
- | `Lib _: all = visit(all, b, "all", dep, looped, marked)
- | targ: std.slpush(&all, dep)
- ;;
- ;;
- std.slfree(b.all)
- b.all = all
- -> true
-}
-
-const visit = {all, b, parent, targ, looped, marked
- if std.hthas(looped, targ)
- std.fatal("cycle in build depgraph involving {}\n", targ)
- elif std.hthas(marked, targ)
- -> all
- ;;
-
- std.htput(looped, targ, true)
- for (dir, lib, dep) : getdeps(b, parent, targ)
- all = visit(all, b, targ, dep, looped, marked)
- ;;
- std.htdel(looped, targ)
- std.htput(marked, targ, true)
- -> std.slpush(&all, targ)
-}
-
-const getdeps = {b, parent, targname
- match std.htget(b.targs, targname)
- | `std.Some targ:
- match targ
- | `Bin t: -> t.libdeps
- | `Lib t: -> t.libdeps
- | _: std.fatal("{} depends on non-library target", parent)
- ;;
- | `std.None:
- std.fatal("{}: could not find dependency {}\n", parent, targname)
- ;;
-}
-
/* <name>: '=' wordlist ';;' */
const incpath = {b, p, words, name
skipspace(p)
@@ -332,14 +328,9 @@
outlist = out
;;
- skipspace(p)
- if matchc(p, '{')
- match attrlist(p)
- | `std.Some al: attrs = al
- | `std.None: failparse(p, "invalid attr list for {}\n", outlist[0])
- ;;
- else
- attrs = [][:]
+ match attrlist(p)
+ | `std.Some al: attrs = al
+ | `std.None: failparse(p, "invalid attr list for {}\n", outlist[0])
;;
skipspace(p)
@@ -377,7 +368,7 @@
gt = std.mk([
.dir=std.sldup(p.fdir),
- .out=outlist,
+ .gen=outlist,
.durable=durable,
.istest=istest,
.deps=deplist,
@@ -388,7 +379,6 @@
if iscmd
addtarg(p, b, o, gt.tags, `Cmd gt)
else
- std.htput(b.gensrc, o, gt)
addtarg(p, b, o, gt.tags, `Gen gt)
;;
;;
@@ -400,8 +390,7 @@
*/
const myrtarget = {b, p, targ
var ldscript, runtime, install, incpath, tags
- var libdeps, tstdeps
- var name, inputs, attrs
+ var libdeps, name, inputs, attrs
var istest
var fsel
@@ -410,14 +399,9 @@
| `std.None: failparse(p, "expected target name after '{}'\n", targ)
;;
- skipspace(p)
- if matchc(p, '{')
- match attrlist(p)
- | `std.Some al: attrs = al
- | `std.None: failparse(p, "invalid attr list for {} {}\n", targ, name)
- ;;
- else
- attrs = [][:]
+ match attrlist(p)
+ | `std.Some al: attrs = al
+ | `std.None: failparse(p, "invalid attr list for {} {}\n", targ, name)
;;
skipspace(p)
@@ -448,7 +432,6 @@
incpath = [][:]
tags = [][:]
istest = false
- tstdeps = [][:]
for elt : attrs
match elt
| ("ldscript", lds): ldscript = std.sldup(lds)
@@ -459,12 +442,12 @@
| ("noinst", ""): install = false
| ("test", ""): istest = true
| ("notest", ""): istest = false
- | (invalid, ""): std.fatal("{}: got invalid attr '{}'\n", targ, invalid)
- | (invalid, attr): std.fatal("{}: got invalid attr '{} = {}'\n", targ, invalid, attr)
+ | (invalid, ""): std.fatal("{}: invalid attr '{}'\n", targ, invalid)
+ | (invalid, attr): std.fatal("{}: invalid attr '{} = {}'\n", targ, invalid, attr)
;;
;;
+
std.sljoin(&incpath, bld.opt_incpaths)
- std.sljoin(&incpath, bld.opt_incpaths)
-> std.mk([
/* target */
.dir=std.sldup(p.fdir),
@@ -471,7 +454,6 @@
.name=name,
.inputs=inputs,
.libdeps=libdeps,
- .tstdeps=tstdeps,
.islib=false,
.istest=istest,
/* attrs */
@@ -493,13 +475,11 @@
;;
skipspace(p)
- if matchc(p, '{')
- match attrlist(p)
- | `std.Some al: attrs = al
- | `std.None: failparse(p, "invalid attr list for {} {}\n", targ, name)
- ;;
- else
- attrs = [][:]
+ attrs = [][:]
+
+ match attrlist(p)
+ | `std.Some al: attrs = al
+ | `std.None: failparse(p, "invalid attr list for {} {}\n", targ, name)
;;
skipspace(p)
@@ -508,14 +488,13 @@
;;
match wordlist(p)
- | `std.Some wl:
- blobs = wl
- | `std.None: failparse(p, "expected list of file names after '{} {}'\n", targ, name)
+ | `std.Some wl: blobs = wl
+ | `std.None: failparse(p, "expected file list after '{} {}'\n", targ, name)
;;
skipspace(p)
if !matchc(p, ';') || !matchc(p, ';')
- failparse(p, "expected ';;' terminating input list, got {}\n", peekc(p))
+ failparse(p, "expected ';;' after input list, got {}\n", peekc(p))
;;
tags = [][:]
@@ -523,10 +502,10 @@
match elt
| ("tag", tag): std.slpush(&tags, tag)
| ("path", pathdir): path = pathdir
- | (invalid, ""):
- std.fatal("{}: got invalid attr '{}'\n", targ, invalid)
- | (invalid, attr):
- std.fatal("{}: got invalid attr '{} = {}'\n", targ, invalid, attr)
+ | (tag, ""):
+ std.fatal("{}: invalid attr '{}'\n", targ, tag)
+ | (tag, attr):
+ std.fatal("{}: invalid attr '{}={}'\n", targ, tag, attr)
;;
;;
@@ -550,8 +529,8 @@
;;
match wordlist(p)
- | `std.None: failparse(p, "expected list of file names after '{}' target\n", targ)
| `std.Some wl: inputs = wl
+ | `std.None: failparse(p, "expected file list after '{}' target\n", targ)
;;
skipspace(p)
if !matchc(p, ';') || !matchc(p, ';')
@@ -561,7 +540,7 @@
}
/*
-attrlist: attrs '}'
+attrlist: EMPTY |'{' attrs '}'
attrs : EMPTY
| attrs attr
@@ -573,10 +552,13 @@
var al
al = [][:]
+ skipspace(p)
+ if !matchc(p, '{')
+ -> `std.Some al
+ ;;
while true
match word(p)
| `std.Some k:
- skipspace(p)
if matchc(p, '=')
match word(p)
| `std.Some v:
@@ -661,38 +643,21 @@
var start
skipspace(p)
-
c = peekc(p)
- if c == '"'
- n = 0
- getc(p)
- start = p.rest
- while p.rest.len > 0
- c = peekc(p)
- if c == '"'
- getc(p)
- goto done
- elif c == '\\'
- c = getc(p)
- ;;
+ n = 0
+ start = p.rest
+ while p.rest.len > 0
+ c = peekc(p)
+ if c == '\\'
+ c = getc(p)
+ ;;
+ if wordchar(c)
getc(p)
n += std.charlen(c)
+ else
+ break
;;
- failparse(p, "input ended within quoted word\n")
- else
- n = 0
- start = p.rest
- while p.rest.len > 0
- c = peekc(p)
- if wordchar(c)
- getc(p)
- n += std.charlen(c)
- else
- break
- ;;
- ;;
;;
-:done
if n > 0
-> `std.Some std.sldup(start[:n])
else
@@ -733,9 +698,7 @@
const matchc = {p, c
var chr, s
- if p.rest.len == 0
- -> false
- ;;
+ /* safe to use at eof: strstep returns (-1, "") */
(chr, s) = std.strstep(p.rest)
if c == chr
p.rest = s
@@ -770,7 +733,7 @@
match std.strrfind(libpath, ":")
| `std.None:
- dir = std.sldup(".")
+ dir = std.sldup(p.fdir)
lib = std.sldup(libpath)
targ = std.fmt("{}:{}", p.fdir, lib)
| `std.Some idx:
@@ -779,12 +742,12 @@
;;
/* absolute path */
if std.hasprefix(libpath, "@/") || std.hasprefix(libpath, "@:")
- dir = std.pathcat(p.basedir, libpath[2:idx])
+ dir = std.sldup(libpath[2:idx])
lib = std.sldup(libpath[idx+1:])
targ = std.sldup(libpath[2:])
/* relative path */
else
- dir = std.sldup(libpath[:idx])
+ dir = std.pathcat(p.fdir, libpath[:idx])
lib = std.sldup(libpath[idx+1:])
targ = std.pathcat(p.fdir, libpath)
if std.hasprefix(targ, "../")
--- a/mbld/subtest.myr
+++ b/mbld/subtest.myr
@@ -75,7 +75,7 @@
curtest = ""
nresults = 0
mbldput("\n")
- for ln : bio.byline(f)
+ for ln in bio.byline(f)
ln = std.strstrip(ln)
match testhead(ln)
| `std.None:
@@ -127,7 +127,7 @@
const starttest = {curtest, t
if curtest#.len != 0
- std.fatal("malformed input in test {} nested : {}\n", t, curtest)
+ std.fatal("malformed input: test {} nested in {}\n", t, curtest)
;;
mbldput("\trun {}:\t", std.strstrip(t))
curtest# = t
@@ -148,7 +148,7 @@
else
mbldput("FAIL\n")
;;
- p = std.pathjoin([b.curdir, cmd, curtest#][:])
+ p = std.pathcat(cmd, curtest#)
std.slpush(failed, p)
;;
--- a/mbld/syssel.myr
+++ b/mbld/syssel.myr
@@ -120,83 +120,46 @@
}
const addsysattrs = {b, tags
- var tagfile
-
std.htput(b.tags, opt_sys, opt_sysvers)
+
match opt_sys
- | "freebsd": std.htput(b.tags, "posixy", (-1, -1, -1))
- | "netbsd": std.htput(b.tags, "posixy", (-1, -1, -1))
- | "openbsd": std.htput(b.tags, "posixy", (-1, -1, -1))
- | "osx": std.htput(b.tags, "posixy", (-1, -1, -1))
- | "linux": std.htput(b.tags, "posixy", (-1, -1, -1))
+ | "freebsd": tag(b, "posixy")
+ | "netbsd": tag(b, "posixy")
+ | "openbsd": tag(b, "posixy")
+ | "osx": tag(b, "posixy")
+ | "linux": tag(b, "posixy")
| "plan9":
| unknown: std.fatal("unknown system \"{}\"\n", unknown)
;;
match opt_arch
- | "x64": tag(b.tags, ["x64"][:])
+ | "x64": tag(b, "x64")
| unknown: std.fatal("unknown architecture {}\n", unknown)
;;
- tag(b.tags, tags)
-
- tagfile = std.pathcat(b.basedir, " bld.tag")
- if std.fexists(tagfile)
- loadtagfile(b, tagfile)
+ for t : tags
+ tag(b, t)
;;
- std.slfree(tagfile)
+
+ loadtagfile(b, "bld.tag")
}
const loadtagfile = {b, tagfile
- var data, tag
+ var data, sp
+ if !std.fexists(tagfile)
+ -> void
+ ;;
data = std.try(std.slurp(tagfile))
while true
- data = skipspace(data)
- (tag, data) = word(data)
- match tag
- | `std.Some w:
- std.htput(b.tags, w, (-1, -1, -1))
- | `std.None:
- if data.len > 0
- std.fatal("junk character near '{}'\n", trailing(data, 10))
- else
- break
- ;;
+ sp = std.strtok(data)
+ for t : sp
+ tag(b, t)
;;
+ std.slfree(sp)
;;
+ std.slfree(data)
}
-const skipspace = {data
- var c
-
- c = std.decode(data)
- while std.isspace(c)
- data = data[std.charlen(c):]
- ;;
- -> data
-}
-
-const word = {data
- var c, split
-
- split = 0
- c = std.decode(data[:])
- while std.isalnum(c) || c == '.' || c == '_' || c == '$'
- split += std.charlen(c)
- ;;
- if split > 0
- -> (`std.Some data[:split], data[split:])
- else
- -> (`std.None, data)
- ;;
-}
-
-const tag = {sa, tags
- for t : tags
- std.htput(sa, t, (-1, -1, -1))
- ;;
-}
-
-const trailing = {str, len
- -> str[:std.min(len, str.len)]
+const tag = {b, tag
+ std.htput(b.tags, std.sldup(tag), (-1, -1, -1))
}
--- a/mbld/test.myr
+++ b/mbld/test.myr
@@ -1,13 +1,9 @@
use std
use "build"
-use "clean"
-use "deps"
use "opts"
-use "parse"
use "types"
use "util"
-use "syssel"
use "subtest"
use "config"
@@ -17,66 +13,26 @@
;;
const test = {b
- var tests : (byte[:][:], byte[:])[:]
var failed, ok
- var bincmd
+ var tests
- /* build with the test tag */
- addsysattrs(b, ["test"][:])
- /* no implicit tests to run */
- tests = [][:]
- buildall(b)
- setdir(b, "")
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Bin bt: std.sljoin(&tests, buildtests(b, bt))
- | `Lib lt: std.sljoin(&tests, buildtests(b, lt))
- | _: /* nothing */
- ;;
- ;;
- for tn : b.all
- match gettarg(b.targs, tn)
- | `Bin t:
- if !t.istest
- continue
- ;;
- if t.incpath.len == 0 || !std.sleq(t.incpath[0], ".")
- std.slput(&t.incpath, 0, std.sldup("."))
- ;;
- buildbin(b, t, false)
- bincmd = std.sldup([std.strcat("./", t.name)][:])
- std.slpush(&tests, (bincmd, std.sldup(t.dir)))
- | `Cmd t:
- if !t.istest
- continue
- ;;
- std.slpush(&tests, (dupcmd(t.cmd), std.sldup(t.dir)))
- | _:
- /* skip */
- ;;
- ;;
+ buildtarg(b, "test")
+ tests = std.htgetv(b.deps.targs, "test", [][:])
ok = true
failed = [][:]
- for (c, dir) : tests
- setdir(b, dir)
- if !runtest(b, c, &failed)
+ for t in tests
+ if !runtest(b, t, &failed)
ok = false
;;
-
;;
- for (bin, dir) : tests
- freecmd(bin)
- std.slfree(dir)
- ;;
+ std.chdir(b.basedir)
+
if tests.len == 0
-> true
;;
printfailed(failed)
- for f : failed
- std.slfree(f)
- ;;
if ok
mbldput("TESTS PASSED\n")
else
@@ -83,7 +39,6 @@
mbldput("TESTS FAILED\n")
;;
std.slfree(failed)
- std.slfree(tests)
-> ok
}
@@ -90,81 +45,26 @@
const printfailed = {failed
if failed.len > 0
mbldput("FAILURES: {}\n", failed.len)
- for t : failed
+ for t in failed
mbldput("\t{}\n", t)
;;
;;
}
-const dupcmd = {cmd
- var ret
-
- ret = [][:]
- for c : cmd
- std.slpush(&ret, std.sldup(c))
- ;;
- -> ret
-}
-
-const freecmd = {cmd
- for c : cmd
- std.slfree(c)
- ;;
- std.slfree(cmd)
-}
-
-const buildtests = {b, targ
- var tt, bin, tests, incpath, libdeps
- var cmd
-
- tests = [][:]
- setdir(b, targ.dir)
- for s : targ.inputs
- match testpath(s)
- | `std.None: /* nothing to do */
- | `std.Some path:
- bin = srcswapsuffix(path, "")
- incpath = std.sldup(targ.incpath)
- libdeps = std.sldup(targ.libdeps)
- std.sljoin(&libdeps, targ.tstdeps)
- tt = [
- .name = bin,
- .dir = targ.dir,
- .inputs = [path][:],
- .install = false,
- .libdeps = libdeps,
- .incpath = std.slput(&incpath, 0, "."),
- ]
-
- buildbin(b, &tt, true)
- cmd = std.sldup([std.strcat("./", bin)][:])
- std.slpush(&tests, (cmd, std.sldup(targ.dir)))
- std.slfree(tt.libdeps)
- std.slfree(tt.incpath)
- std.slfree(path)
- ;;
- ;;
- -> tests
-}
-
-const runtest = {b, cmd, failed
- var res, log, logfd, p
+const runtest = {b, n, failed
+ var dir, res, log, logfd
var sub
- mbldput("run")
- for c : cmd
- p = std.pathcat(b.curdir, c)
- mbldput(" {}", p)
- std.slfree(p)
- ;;
- mbldput(":\t")
- match std.spork(cmd)
+ dir = std.pathcat(b.basedir, n.wdir)
+ mbldput("run {}:\t", n.lbl)
+ std.chdir(dir)
+ match std.spork(n.cmd)
| `std.Err m:
std.fatal("\nunable to run test: {}\n", m)
| `std.Ok (pid, infd, outfd):
- log = std.strcat(cmd[0], ".log")
+ log = std.strcat(std.basename(n.lbl), ".log")
logfd = std.try(std.openmode(log, std.Owronly | std.Ocreat, 0o644))
- sub = showsub(b, cmd[0], outfd, logfd, failed)
+ sub = showsub(b, n.lbl, outfd, logfd, failed)
std.slfree(log)
std.close(infd)
std.close(outfd)
@@ -171,6 +71,7 @@
res = false
match std.wait(pid)
+ | `std.Waiterror: mbldput("FUCK pid {}\n", pid)
| `std.Wfailure: mbldput("FAIL\n")
| `std.Wsignalled: mbldput("CRASH\n")
| `std.Wsuccess:
@@ -180,33 +81,12 @@
| `std.Some r: res = r
| `std.None: mbldput("PASS\n")
;;
- | `std.Waiterror: mbldput("failed waiting for pid {}\n", pid)
;;
if !res
- p = std.pathcat(b.curdir, cmd[0])
- std.slpush(failed, p)
+ std.slpush(failed, n.lbl)
;;
;;
+ std.slfree(dir)
-> res
-}
-
-const testpath = {s
- var path, file
-
- path = std.pathcat("./test", s)
- if std.fexists(path)
- -> `std.Some path
- ;;
- match std.strfind(s, "+")
- | `std.None:
- | `std.Some idx:
- file = std.strcat(s[:idx], ".myr")
- path = std.pathcat("./test", file)
- std.slfree(file)
- if std.fexists(path)
- -> `std.Some path
- ;;
- ;;
- -> `std.None
}
--- a/mbld/types.myr
+++ b/mbld/types.myr
@@ -4,19 +4,21 @@
type build = struct
/* build state */
basedir : byte[:]
- bldfile : byte[:]
- curdir : byte[:]
- built : std.htab(byte[:], bool)# /* set of targets built in this run */
tags : std.htab(byte[:], (int, int, int))#
+ libs : std.htab(byte[:], libdep#)#
+ deps : depgraph#
+ /* in flight builds */
+ queue : node#[:]
+ proc : std.htab(std.pid, node#)#
+
/* build params */
- all : byte[:][:] /* targets in reverse topological order */
- targs : std.htab(byte[:], targ)# /* name => target mapping */
- tdeps : std.htab(byte[:], byte[:][:]) /* targname => depname[:][:] */
- gensrc : std.htab(byte[:], cmdtarg#)# /* generated => generator mapping */
+ all : byte[:][:]
+ targs : std.htab(byte[:], targ)#
prefix : byte[:]
system : byte[:]
arch : byte[:]
+
;;
type targ = union
@@ -29,32 +31,30 @@
;;
type myrtarg = struct
- file : byte[:]
- line : int
-
- islib : bool
- istest : bool
- dir : byte[:]
name : byte[:]
+ dir : byte[:]
+
inputs : byte[:][:]
libdeps : (byte[:], byte[:], byte[:])[:] /* dir, lib, targname */
tstdeps : (byte[:], byte[:], byte[:])[:] /* dir, lib, targname */
- install : bool
runtime : byte[:]
incpath : byte[:][:]
tags : byte[:][:]
ldscript : byte[:]
+
+ islib : bool
+ istest : bool
+ install : bool
+
;;
type cmdtarg = struct
dir : byte[:]
- out : byte[:][:]
+ gen : byte[:][:]
cmd : byte[:][:]
deps : byte[:][:]
tags : byte[:][:]
durable : bool
- /* we can have multiple outputs, but we only want to run once for each */
- done : bool
istest : bool
;;
@@ -72,18 +72,49 @@
blobs : byte[:][:]
;;
+ type libdep = struct
+ dir : byte[:]
+ name : byte[:]
+ dep : byte[:][:]
+ dyndep : byte[:][:]
+ genuse : byte[:]
+ genar : byte[:]
+ ;;
+
type depgraph = struct
- deps : std.htab(byte[:], byte[:][:])#
- libs : std.htab(byte[:], byte[:][:])#
- input : std.htab(byte[:], byte[:])#
- sources : std.htab(byte[:], bool)#
- updated : std.htab(byte[:], bool)#
- seen : std.htab(byte[:], bool)#
- done : std.htab(byte[:], bool)#
+ /* the edges of the graph from both ends */
+ targs : std.htab(byte[:], node#[:])#
+ gen : std.htab(byte[:], node#)#
- /* used for linking C */
- extlibs : byte[:][:]
- cflags : std.htab(byte[:], byte[:][:])#
- dynamic : bool
+ nodes : node#[:]
+ leaves : node#[:]
+ ;;
+
+ type node = struct
+ /* for debugging, "primary output" */
+ lbl : byte[:]
+
+ /* run this command in this dir to 'execute' the node */
+ cmd : byte[:][:]
+ wdir : byte[:]
+
+ /* install info */
+ instdir : byte[:]
+ instmod : int64
+
+ /* dependency names */
+ gen : byte[:][:]
+ dep : byte[:][:]
+ xdep : byte[:][:]
+
+ /* resolved dependency nodes */
+ ndep : node#[:]
+ ngen : node#[:]
+
+ /* build state */
+ nblock : int32
+ mtime : std.time
+ durable : bool /* keep outputs when cleaning */
+ want : bool
;;
;;
--- a/mbld/util.myr
+++ b/mbld/util.myr
@@ -4,38 +4,30 @@
use "types"
pkg bld =
- const run : (cmd : byte[:][:] -> bool)
- const printcmd : (cmd : byte[:][:] -> void)
+ const run : (cmd : byte[:][:], dir : byte[:] -> std.pid)
const mbldput : (fmt : byte[:], args : ... -> void)
const srcsplit : (src : byte[:] -> (byte[:], byte[:], byte[:]))
- const swapsuffix : (f : byte[:], suff : byte[:], newsuff : byte[:] -> byte[:])
- const srcswapsuffix : (f : byte[:], newsuff : byte[:] -> byte[:])
- const strlistfree : (sl : byte[:][:] -> void)
+ const changesuffix : (f : byte[:], newsuff : byte[:] -> byte[:])
const gettarg : (tab : std.htab(byte[:], targ)#, n : byte[:] -> targ)
- const setdir : (b : build#, dir : byte[:] -> void)
;;
-const run = {cmd
+const run = {cmd, dir
var pid
- printcmd(cmd)
+ std.assert(cmd.len != 0, "empty command\n")
+ mbldput("\t{j= }\n", cmd);
pid = std.fork()
if pid == -1
std.fatal("could not fork command\n")
- -> false
elif pid == 0
+ if dir.len != 0
+ std.chdir(dir)
+ ;;
if std.execvp(cmd[0], cmd) < 0
std.fatal("failed to exec {}\n", cmd[0])
;;
- -> false
- else
- match std.wait(pid)
- | `std.Wsuccess: -> true
- | `std.Wfailure: std.fatal("FAIL: \"{}\"\n", std.strjoin(cmd, " "))
- | `std.Wsignalled: std.fatal("CRASH: \"{}\"\n", std.strjoin(cmd, " "))
- | `std.Waiterror: std.fatal("WAT: \"{}\"\n", std.strjoin(cmd, " "))
- ;;
;;
+ -> pid
}
const mbldput = {fmt, args
@@ -47,17 +39,6 @@
;;
}
-const printcmd = {lst
- if lst.len > 0
- mbldput("\t")
- mbldput("{}\t", lst[0])
- for l : lst[1:]
- mbldput("{} ", l)
- ;;
- ;;
- mbldput("\n")
-}
-
const srcsplit = {src
var platf, fbase, suff
@@ -69,31 +50,22 @@
| `std.None: fbase = 0
;;
match std.strfind(src[fbase:], ".")
+ | `std.None: /* no suffix to trim */
| `std.Some i:
suff = src[fbase+i:]
src = src[:fbase+i]
- | `std.None:
- /* no suffix to trim */
;;
match std.strrfind(src[fbase:], "+")
+ | `std.None: /* no platform to trim */
| `std.Some i:
platf = src[fbase+i:]
src = src[:fbase+i]
- | `std.None:
- /* no platform to trim */
;;
-> (src, platf, suff)
}
-const swapsuffix = {f, suff, newsuff
- if std.hassuffix(f, suff)
- f = f[:f.len - suff.len]
- ;;
- -> std.fmt("{}{}", f, newsuff)
-}
-
-const srcswapsuffix = {src, new
+const changesuffix = {src, new
var base, platf, suff
(base, platf, suff) = srcsplit(src)
@@ -110,30 +82,10 @@
;;
}
-const strlistfree = {sl
- for s : sl
- std.slfree(s)
- ;;
- std.slfree(sl)
-}
-
const gettarg = {tab, n
match std.htget(tab, n)
| `std.None: std.fatal("unknown target '{}'\n", n)
| `std.Some t: -> t
- ;;
-}
-
-const setdir = {b, dir
- var p
-
- if !std.sleq(b.curdir, dir)
- p = std.pathcat(b.basedir, dir)
- if !std.chdir(p)
- std.fatal("could not cd into {}\n", p)
- ;;
- b.curdir = dir
- std.slfree(p)
;;
}