ref: ece21cac74e30ff4c2f1265e11d642d136d8b287
dir: /mbld/syssel.myr/
use std use "opts" use "types" pkg bld = type syssel(@a) = struct file : byte[:] line : int targ : byte[:] sysattrs : std.htab(byte[:], (int, int, int))# _match : std.htab(byte[:], (int, int))# _best : std.htab(byte[:], @a)# ;; generic mksyssel : (b : build#, f : byte[:], line : int, targ : byte[:] -> syssel(@a)#) generic sysseladd : (syssel : syssel(byte[:])#, file : byte[:] -> void) generic sysseladdlist : (syssel : syssel(@a)#, base : byte[:], attrs : byte[:][:], val : @a -> void) generic sysselfin : (syssel : syssel(@a)# -> @a[:]) const addsysattrs : (sa : build#, tags : byte[:][:] -> void) ;; generic mksyssel = {b, file, line, targ var syssel syssel = std.mk([ .file = file, .line = line, .targ = targ, ._match = std.mkht(), ._best = std.mkht(), .sysattrs = b.tags ]) -> syssel } generic sysseladd = {syssel, f var basename, attrs var attrlist match std.strfind(f, "+") | `std.Some i: basename = f[:i] match std.strrfind(f[i+1:], ".") | `std.Some j: attrs = f[i+1:][:j] | `std.None: std.fatal("unrecognized type for file {}\n", f) ;; | `std.None: match std.strrfind(f, ".") | `std.None: std.fatal("unrecognized type for file {}\n", f) | `std.Some i: basename = f[:i] attrs = "" ;; ;; attrlist = std.strsplit(attrs, "-") sysseladdlist(syssel, basename, attrlist, f) std.slfree(attrlist) } generic sysseladdlist = {syssel, base, attrs, val var nmatch, vscore, n, v, s nmatch = 0 vscore = 0 for a : attrs match std.strfind(a, ":") | `std.Some i: n = a[:i] v = parseversion(a[i+1:]) | `std.None: n = a v = (-1, -1, -1) ;; match std.htget(syssel.sysattrs, n) | `std.None: nmatch = -1 break | `std.Some have: s = versionscore(syssel, have, v) if s < 0 nmatch = -1 break ;; vscore += s nmatch++ ;; ;; match std.htgetv(syssel._match, base, (-1, -1)) | (curbest, curscore): if curbest < nmatch || (nmatch >= 0 && curbest == nmatch && curscore < vscore) std.htput(syssel._match, base, (nmatch, vscore)) std.htput(syssel._best, base, val) ;; ;; } const versionscore = {syssel, have, want var s s = 0 match (have, want) | ((a0, a1, a2), (v0, v1, v2)): if a0 == -1 && a1 == -1 && a2 == -1 -> s elif v0 == -1 && v1 == -1 && v2 == -1 -> s else s = 1_000_000 * (a0 - v0) if s == 0 s += 1_000 * (a1 - v1) ;; if s == 0 s += (a2 - v2) ;; if s >= 0 s = 100_000_000 - s ;; -> s ;; ;; } generic sysselfin = {syssel var keys, nmatch, ret keys = std.htkeys(syssel._match) ret = [][:] for k : keys (nmatch, _) = std.htgetv(syssel._match, k, (-1, -1)) if nmatch == -1 std.fatal("{}:{}: target {}, no applicable file for '{}'\n", \ syssel.file, syssel.line, syssel.targ, k) ;; std.slpush(&ret, std.get(std.htget(syssel._best, k))) ;; std.htfree(syssel._match) std.htfree(syssel._best) -> ret } const addsysattrs = {b, tags std.htput(b.tags, opt_sys, opt_sysvers) match opt_sys | "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, "x64") | unknown: std.fatal("unknown architecture {}\n", unknown) ;; for t : tags tag(b, t) ;; loadtagfile(b, "bld.tag") } const loadtagfile = {b, tagfile var data, sp if !std.fexists(tagfile) -> void ;; data = std.try(std.slurp(tagfile)) while true sp = std.strtok(data) for t : sp tag(b, t) ;; std.slfree(sp) ;; std.slfree(data) } const tag = {b, tag std.htput(b.tags, std.sldup(tag), (-1, -1, -1)) }