ref: 82532ed187c6041e7dff5505de21e95d7fd380d9
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 test : (p : parser# -> bool) const build : (p : parser#, target : byte[:] -> bool) const buildbin : (bin : byte[:], inputs : byte[:][:], ldscript : byte[:], rt : byte[:] -> void) const buildlib : (lib : byte[:], inputs : byte[:][:] -> void) ;; const buildall = {p for t in p.targs match t | `Bin [.name=bin, .inputs=leaves, .ldscript=lds, .runtime=rt]: buildbin(bin, leaves, lds, rt) | `Lib [.name=lib, .inputs=leaves]: buildlib(lib, leaves) | `Sub subs: subdirs(p, subs, `std.None) | `Man m: /* nothing needed */ ;; ;; -> true } const test = {p std.fatal(1, "testing not yet supported\n") -> false } const build = {p, targ var built built = false for t in p.targs match t | `Bin [.name=bin, .inputs=leaves, .ldscript=lds, .runtime=rt]: if std.sleq(bin, targ) buildbin(bin, leaves, lds, rt) built = true ;; | `Lib [.name=lib, .inputs=leaves]: if std.sleq(lib, targ) buildlib(lib, leaves) built = true ;; | `Sub subs: subdirs(p, subs, `std.Some targ) | `Man m: /* nothing needed */ ;; ;; if !built std.fatal(1, "%s: no such target\n", targ) ;; -> built } const buildbin = {bin, inputs, ldscript, rt var dg if !myrdeps(&dg, bin, inputs, false) std.fatal(1, "Could not load dependencies for %s\n", bin) ;; if !std.hthas(dg.deps, bin) std.fatal(1, "no target declared for %s\n", bin) ;; if builddep(&dg, bin) linkbin(&dg, bin, inputs, ldscript, rt) ;; } const buildlib = {lib, inputs var archive var u, l var dg archive = std.fmt("lib%s.a", lib) if !myrdeps(&dg, lib, inputs, true) 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(&dg, lib) l = builddep(&dg, archive) if u || l mergeuse(&dg, lib, inputs) archivelib(&dg, lib, inputs) ;; std.slfree(archive) } const builddep = {dg, out 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(dg, d) stale = true ;; if !isfresh(d, out) if opt_debug std.put("Stale %s => %s\n", d, out); pmtime(d, out) ;; stale = true ;; ;; | `std.None: ;; match std.htget(dg.sources, out) | `std.Some src: if stale compile(src) ;; std.htput(dg.updated, out, true) | `std.None: ;; -> stale } const compile = {src var o if std.hassuffix(src, ".myr") run(["6m", src][:], "") elif std.hassuffix(src, ".s") o = srcswapsuffix(src, ".o") run(["as", src, "-o", o][:], "") std.slfree(o) else std.fatal(1, "Unknown file type for %s\n", src) ;; } const linkbin = {dg, bin, srcfiles, ldscript, rt var cmd cmd = [][:] /* ld -o bin */ cmd = std.slpush(cmd, std.sldup("ld")) cmd = std.slpush(cmd, std.sldup("-o")) 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, ".o")) ;; /* -l lib... */ cmd = addlibs(cmd, dg.libs) /* -L incpath... */ for inc in opt_incpaths cmd = std.slpush(cmd, std.fmt("-L%s", inc)) ;; cmd = std.slpush(cmd, std.fmt("-L%s%s", opt_instroot, "/lib/myr")) /* 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 var cmd var obj cmd = [][:] cmd = std.slpush(cmd, std.sldup(opt_ar)) cmd = std.slpush(cmd, std.sldup("-rcs")) cmd = std.slpush(cmd, std.fmt("lib%s.a", lib)) for f in files obj = srcswapsuffix(f, ".o") cmd = std.slpush(cmd, obj) ;; run(cmd, "") strlistfree(cmd) } const mergeuse = {dg, lib, files var cmd cmd = [][:] cmd = std.slpush(cmd, std.sldup(opt_muse)) cmd = std.slpush(cmd, std.sldup("-mo")) 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 var looped : std.htab(byte[:], bool)# var marked : std.htab(byte[:], bool)# var libs var head 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) ;; -> cmd } const visit = {cmd, head, g, lib, looped, marked -> byte[:][:] 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) ;; std.htdel(looped, lib) std.htput(marked, lib, true) -> std.slput(cmd, head, std.fmt("-l%s", lib)) } const isfresh = {src, dst var srcsb, dstsb if std.stat(src, &srcsb) != 0 std.fatal(1, "could not stat %s\n", src) ;; if std.stat(dst, &dstsb) != 0 -> false ;; /* 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. */ if srcsb.mtime.sec != dstsb.mtime.sec -> srcsb.mtime.sec < dstsb.mtime.sec else -> srcsb.mtime.nsec <= dstsb.mtime.nsec ;; } const pmtime = {src, dst var srcsb, dstsb if std.stat(src, &srcsb) != 0 std.put("\tno %s\n", src) -> ;; if std.stat(dst, &dstsb) != 0 std.put("\tno %s\n", dst) -> ;; if srcsb.mtime.sec != dstsb.mtime.sec std.put("\tsrc mtime=%ul, dst mtime=%ul\n", srcsb.mtime.sec, dstsb.mtime.sec) else std.put("\tsrc mtime.nsec=%ul, dst mtime.nsec=%ul\n", srcsb.mtime.nsec, dstsb.mtime.nsec) ;; }