ref: 5db1f939e095cb4ee58a9c24352bdad63f38d55b
dir: /build.myr/
use std
use "config.use"
use "deps.use"
use "opts.use"
use "parse.use"
use "types.use"
use "util.use"
use "subdir.use"
pkg bld =
const buildall : (p : parser# -> bool)
const genall : (p : parser# -> bool)
const test : (p : parser# -> bool)
const build : (p : parser#, target : byte[:] -> bool)
const buildbin : (p : parser#, bt : myrtarg# -> void)
const buildlib : (p : parser#, lt : myrtarg# -> void)
;;
const buildall = {p
for t in p.targs
match t
| `Bin bt:
buildbin(p, bt)
| `Lib lt:
buildlib(p, lt)
| `Gen gt:
genfiles(p, gt)
| `Sub subs:
subdirs(p, subs, `std.None)
| `Man m:
/* nothing needed */
;;
;;
-> true
}
const genall = {p
for t in p.targs
match t
| `Gen gt: run(gt.cmd, "")
| _: /* skip */
;;
;;
/* genfiles will exit if the build fails; always return true */
-> true
}
const test = {p
std.fatal(1, "testing not yet supported\n")
-> false
}
const build = {p, targ
var found
found = false
for t in p.targs
match t
| `Bin bt:
if std.sleq(bt.name, targ)
buildbin(p, bt)
;;
| `Lib lt:
if std.sleq(lt.name, targ)
buildlib(p, lt)
found = true
;;
| `Gen gt:
for n in gt.out
if std.sleq(n, targ)
run(gt.cmd, "")
;;
;;
| `Sub subs:
found = true
subdirs(p, subs, `std.Some targ)
| `Man m:
found = true
/* nothing needed */
;;
;;
if !found
std.fatal(1, "%s: no such target\n", targ)
;;
-> found
}
const buildbin = {p, targ
var dg
if targ.built
->
;;
if targ.libdeps.len > 0
if !hasinc(targ.incpath, ".")
targ.incpath = std.slpush(targ.incpath, ".")
;;
for l in targ.libdeps
build(p, l)
;;
;;
std.put("%s...\n", targ.name)
if !myrdeps(p, targ, false, false, &dg)
std.fatal(1, "Could not load dependencies for %s\n", targ.name)
;;
if !std.hthas(dg.deps, targ.name)
std.fatal(1, "no target declared for %s\n", targ.name)
;;
if builddep(p, &dg, targ.name, targ.incpath) || !freshlibs(targ, dg.libs)
linkbin(&dg, targ.name, targ.inputs, targ.ldscript, targ.runtime, targ.incpath, targ.libdeps)
;;
targ.built = true
}
const hasinc = {path, t
for e in path
if std.sleq(e, t)
-> true
;;
;;
-> false
}
const buildlib = {p, targ
var archive
var u, l
var dg
var lib
if targ.built
->
;;
lib = targ.name
std.put("lib%s.a...\n", lib)
archive = std.fmt("lib%s.a", lib)
if !myrdeps(p, targ, true, false, &dg)
std.fatal(1, "Could not load dependencies for %s\n", lib)
;;
if !std.hthas(dg.deps, lib)
std.fatal(1, "no target declared for %s\n", lib)
;;
u = builddep(p, &dg, targ.name, targ.incpath)
l = builddep(p, &dg, archive, targ.incpath)
if u || l || !freshlibs(targ, dg.libs)
mergeuse(&dg, lib, targ.inputs, targ.incpath)
archivelib(&dg, lib, targ.inputs, targ.incpath)
;;
std.slfree(archive)
targ.built = true
}
const genfiles = {p, gt
for f in gt.out
if !std.fexists(f)
run(gt.cmd, "")
->
;;
;;
}
const builddep = {p, 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 in deps
if builddep(p, dg, d, incs)
stale = true
;;
if !std.fexists(d)
match std.htget(p.gensrc, d)
| `std.Some gt: run(gt.cmd, "")
| `std.None: std.fatal(1, "no input file %s\n", d)
;;
;;
if !isfresh(d, out)
stale = true
;;
;;
| `std.None:
;;
match std.htget(dg.sources, out)
| `std.Some src:
if stale
compile(src, incs)
;;
std.htput(dg.updated, out, true)
| `std.None:
;;
-> stale
}
const compile = {src, incs
var o
var cmd
cmd = [][:]
if std.hassuffix(src, ".myr")
cmd = std.slpush(cmd, "6m")
for inc in incs
cmd = std.slpush(cmd, "-I")
cmd = std.slpush(cmd, inc)
;;
if opt_genasm
cmd = std.slpush(cmd, "-S")
;;
cmd = std.slpush(cmd, src)
run(cmd, "")
std.slfree(cmd)
elif std.hassuffix(src, ".s")
o = srcswapsuffix(src, config.Objsuffix)
for c in config.Ascmd
cmd = std.slpush(cmd, c)
;;
cmd = std.slpush(cmd,"-o")
cmd = std.slpush(cmd, o)
cmd = std.slpush(cmd, src)
run(cmd, "")
std.slfree(o)
else
std.fatal(1, "Unknown file type for %s\n", src)
;;
}
const linkbin = {dg, bin, srcfiles, ldscript, rt, incs, extralibs
var cmd
cmd = [][:]
/* ld -o bin */
for c in config.Linkcmd
cmd = std.slpush(cmd, std.sldup(c))
;;
cmd = std.slpush(cmd, std.sldup(bin))
/* [-T script] */
if ldscript.len > 0
cmd = std.slpush(cmd, std.sldup("-T"))
cmd = std.slpush(cmd, std.sldup(ldscript))
;;
if rt.len != 0
cmd = std.slpush(cmd, std.sldup(rt))
else
cmd = std.slpush(cmd, std.sldup(opt_runtime))
;;
/* input.o list.o... */
for f in srcfiles
cmd = std.slpush(cmd, srcswapsuffix(f, config.Objsuffix))
;;
/* -L path -l lib... */
cmd = addlibs(cmd, dg.libs, incs)
for l in extralibs
cmd = std.slpush(cmd, std.fmt("-l%s", l))
;;
/* special for OSX: it warns if we don't add this */
if std.sleq(opt_sys, "osx")
cmd = std.slpush(cmd, std.sldup("-macosx_version_min"))
cmd = std.slpush(cmd, std.sldup("10.6"))
;;
run(cmd, "")
strlistfree(cmd)
}
const archivelib = {dg, lib, files, incs
var cmd
var obj
cmd = [][:]
for c in config.Arcmd
cmd = std.slpush(cmd, std.sldup(c))
;;
cmd = std.slpush(cmd, std.fmt("lib%s.a", lib))
for f in files
obj = srcswapsuffix(f, config.Objsuffix)
cmd = std.slpush(cmd, obj)
;;
run(cmd, "")
strlistfree(cmd)
}
const mergeuse = {dg, lib, files, incs
var cmd
cmd = [][:]
cmd = std.slpush(cmd, std.sldup(opt_muse))
cmd = std.slpush(cmd, std.sldup("-o"))
cmd = std.slpush(cmd, std.sldup(lib))
for f in files
if std.hassuffix(f, ".myr")
cmd = std.slpush(cmd, srcswapsuffix(f, ".use"))
elif !std.hassuffix(f, ".s")
std.fatal(1, "unknown file type for %s\n", f)
;;
;;
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 in incs
cmd = std.slpush(cmd, std.fmt("-L%s", inc))
;;
cmd = std.slpush(cmd, std.fmt("-L%s%s", opt_instroot, "/lib/myr"))
;;
libs = std.htkeys(libgraph)
looped = std.mkht(std.strhash, std.streq)
marked = std.mkht(std.strhash, std.streq)
head = cmd.len
for lib in 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(1, "cycle in library graph involving \"%s\"\n", lib)
elif std.hthas(marked, lib)
-> cmd
;;
std.htput(looped, lib, true)
for dep in std.htgetv(g, lib, [][:])
cmd = visit(cmd, head, g, dep, looped, marked, incs)
;;
std.htdel(looped, lib)
std.htput(marked, lib, true)
-> putlib(cmd, head, lib, incs)
}
const putlib = {cmd, head, lib, incs
if !config.Directlib
-> std.slput(cmd, head, std.fmt("-l%s", lib))
else
match findlib(lib, incs)
| `std.None:
std.fatal(1, "could not find library lib%s.a", lib)
| `std.Some p:
-> std.slput(cmd, head, p)
;;
;;
}
const findlib = {lib, incs
var buf : byte[512]
var n, p
n = std.bfmt(buf[:], "lib%s.a", lib)
for i in incs
p = std.pathjoin([i, buf[:n]][:])
if std.fexists(p)
-> `std.Some p
;;
std.slfree(p)
;;
p = std.pathjoin([opt_instroot, "lib/myr", buf[:n]][:])
if std.fexists(p)
-> `std.Some p
;;
std.slfree(p)
-> `std.None
}
const freshlibs = {targ, libgraph
var libs
libs = std.htkeys(libgraph)
for l in libs
match findlib(l, targ.incpath)
| `std.Some lib:
if !isfresh(lib, targ.name)
std.slfree(lib)
-> false
;;
std.slfree(lib)
| `std.None:
std.fatal(1, "could not find library lib%s.a", l)
;;
;;
std.slfree(libs)
-> 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.Some mt: srcmt = mt
| `std.None: std.fatal(1, "could not stat %s\n", src)
;;
match std.fmtime(dst)
| `std.Some mt: dstmt = mt
| `std.None: -> false
;;
-> srcmt <= dstmt
}