ref: 3456a5b71887bb64aa8eac957a287a78b8ce9f28
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 build : (p : parser#, target : byte[:] -> bool) const buildbin : (p : parser#, bt : myrtarg#, addsrc : bool -> void) const buildlib : (p : parser#, lt : myrtarg# -> void) ;; const buildall = {p for t in p.targs match t | `Bin bt: buildbin(p, bt, false) | `Lib lt: buildlib(p, lt) | `Test tt: /* build on 'mbld test' by default */ | `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 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, false) ;; | `Lib lt: if std.sleq(lt.name, targ) buildlib(p, lt) found = true ;; | `Test tt: if std.sleq(tt.name, targ) buildbin(p, tt, false) 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, addsrc var dg, src 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, addsrc, &dg) std.fatal(1, "Could not load dependencies for %s\n", targ.name) ;; if !std.hthas(dg.deps, targ.name) std.fatal(1, "no input files for %s\n", targ.name) ;; if builddep(p, &dg, targ.name, targ.incpath) || !freshlibs(targ, dg.libs) src = std.htkeys(dg.sources) linkbin(&dg, targ.name, src, targ.ldscript, targ.runtime, targ.incpath, targ.libdeps) std.slfree(src) ;; 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, src 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, 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) src = std.htkeys(dg.sources) mergeuse(&dg, lib, src, targ.incpath) archivelib(&dg, lib, src, targ.incpath) std.slfree(src) ;; 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.input, 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, opt_mc) 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 sl, p sl = std.bfmt(buf[:], "lib%s.a", lib) for i in incs p = std.pathjoin([i, sl][:]) if std.fexists(p) -> `std.Some p ;; std.slfree(p) ;; p = std.pathjoin([opt_instroot, "lib/myr", sl][:]) 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, "%s: 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 }