shithub: mc

Download patch

ref: b612c54208eb92725f85f2521ba1a4be58fc7f44
parent: 66a103f6afd50eb45e9ba62f167688edeb10063a
author: Ori Bernstein <ori@eigenstate.org>
date: Sun Apr 12 20:42:30 EDT 2015

Mostly finish off the new single process world order.

    We no longer need to spawn subprocesses to do our building.
    We can handle library dependencies in the form of '../lib:foo',
    although we don't transitively link them in for binaries yet,
    or do loop detection.

--- a/build.myr
+++ b/build.myr
@@ -6,7 +6,6 @@
 use "parse.use"
 use "types.use"
 use "util.use"
-use "subdir.use"
 
 pkg bld =
 	const buildall	: (b : build# -> bool)
@@ -17,16 +16,12 @@
 ;;
 
 const buildall = {b
-	var targs
-
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
+	for tn in b.all
+		match gettarg(b._targs, tn)
 		| `Bin bt:	buildbin(b, bt, false)
 		| `Lib lt:	buildlib(b, lt)
 		| `Test tt:	/* build on 'mbld test' by default */
 		| `Gen gt:	genfiles(b, gt)
-		| `Sub subs:	subdirs(b, subs, `std.None)
 		| `Man m:	/* nothing needed */
 		;;
 	;;
@@ -34,11 +29,8 @@
 }
 
 const genall = {b
-	var targs
-
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
+	for tn in b.all
+		match gettarg(b._targs, tn)
 		| `Gen gt: run(gt.cmd)
 		| _:	/* skip */
 		;;
@@ -48,44 +40,15 @@
 }
 
 const build = {b, targ
-	var found, targs
-
-	found = false
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
-		| `Bin bt:
-			if std.sleq(bt.name, targ)
-				buildbin(b, bt, false)
-			;;
-		| `Lib lt:
-			if std.sleq(lt.name, targ)
-				buildlib(b, lt)
-				found = true
-			;;
-		| `Test tt:
-			if std.sleq(tt.name, targ)
-				buildbin(b, tt, false)
-				found = true
-			;;
-		| `Gen gt:
-			for n in gt.out
-				if std.sleq(n, targ)
-					run(gt.cmd)
-				;;
-			;;
-		| `Sub subs:
-			found = true
-			subdirs(b, subs, `std.Some targ)
-		| `Man m:
-			found = true
-			/* nothing needed */
-		;;
+	match std.htget(b._targs, targ)
+	| `std.Some (`Bin bt):	buildbin(b, bt, false)
+	| `std.Some (`Lib lt):	buildlib(b, lt)
+	| `std.Some (`Test tt):	buildbin(b, tt, false)
+	| `std.Some (`Gen gt):	run(gt.cmd)
+	| `std.Some (`Man m):	/* nothing needed */
+	| `std.None:	std.fatal(1, "invalid target %s\n", targ)
 	;;
-	if !found
-		std.fatal(1, "%s: no such target\n", targ)
-	;;
-	-> found
+	-> true
 }
 
 const buildbin = {b, targ, addsrc
@@ -94,13 +57,14 @@
 	if targ.built
 		->
 	;;
+	setdir(b, targ.dir)
 	if targ.libdeps.len > 0
-		if !hasinc(targ.incpath, ".")
-			targ.incpath = std.slpush(targ.incpath, ".")
+		for (inc, lib, subtarg) in targ.libdeps
+			if !hasinc(targ.incpath, inc)
+				targ.incpath = std.slpush(targ.incpath, inc)
+			;;
+			build(b, subtarg)
 		;;
-		for l in targ.libdeps
-			build(b, l)
-		;;
 	;;
 	std.put("%s...\n", targ.name)
 	if !myrdeps(b, targ, false, false, addsrc, &dg)
@@ -135,6 +99,7 @@
 	if targ.built
 		->
 	;;
+	setdir(b, targ.dir)
 	lib = targ.name
 	std.put("lib%s.a...\n", lib)
 	archive = std.fmt("lib%s.a", lib)
@@ -266,7 +231,7 @@
 
 	/* -L path -l lib... */
 	cmd = addlibs(cmd, dg.libs, incs)
-	for l in extralibs
+	for (d, l, t) in extralibs
 		cmd = std.slpush(cmd, std.fmt("-l%s", l))
 	;;
 
--- a/clean.myr
+++ b/clean.myr
@@ -6,6 +6,7 @@
 use "parse.use"
 use "subdir.use"
 use "types.use"
+use "util.use"
 
 pkg bld =
 	const cleanall	: (b : build# -> bool)
@@ -13,11 +14,8 @@
 ;;
 
 const cleanall = {b
-	var targs
-
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
+	for tn in b.all
+		match gettarg(b._targs, tn)
 		| `Bin bt:
 			cleanup(b, bt, bt.inputs, true)
 		| `Lib lt:
@@ -30,8 +28,6 @@
 					std.put("\tclean %s\n", f)
 				;;
 			;;
-		| `Sub subs:
-			subdirs(b, subs, `std.None)
 		| `Man m:
 		;;
 	;;
@@ -39,11 +35,8 @@
 }
 
 const clean = {b, targ
-	var targs
-
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
+	for tn in b.all
+		match gettarg(b._targs, tn)
 		| `Bin bt:
 			if std.sleq(bt.name, targ)
 				cleanup(b, bt, bt.inputs, true)
@@ -57,8 +50,11 @@
 				cleanup(b, tt, tt.inputs, true)
 			;;
 		| `Gen gt:
-		| `Sub subs:
-			subdirs(b, subs, `std.Some targ)
+			for f in gt.out
+				if !gt.durable && std.remove(f)
+					std.put("\tclean %s\n", f)
+				;;
+			;;
 		| `Man m:
 		;;
 	;;
@@ -65,7 +61,7 @@
 	-> true
 }
 
-const cleanup = {p, targ, leaves, islib
+const cleanup = {b, targ, leaves, islib
 	var mchammer_files /* cant touch this */
 	var keys
 	var dg
@@ -74,7 +70,8 @@
 	we want to automatically add 'clean' sources since otherwise,
 	mbld won't be able to clean code after changing a build file.
 	*/
-	if !myrdeps(p, targ, islib, true, true, &dg)
+	setdir(b, targ.dir)
+	if !myrdeps(b, targ, islib, true, true, &dg)
 		std.fatal(1, "Could not load dependencies for %s\n", targ.name)
 	;;
 	mchammer_files = std.mkht(std.strhash, std.streq)
--- a/install.myr
+++ b/install.myr
@@ -24,11 +24,10 @@
 }
 
 const movetargs = {b, delete
-	var libarchive, targs
+	var libarchive
 
-	targs = std.htgetv(b.targs, "", [][:])
-	for t in targs
-		match t
+	for tn in b.all
+		match gettarg(b._targs, tn)
 		| `Bin bt:
 			movefile(delete, bt.name, opt_instroot, opt_destdir, "bin", 0o755)
 		| `Lib lt:
@@ -38,8 +37,6 @@
 			std.slfree(libarchive)
 		| `Gen gt:
 			/* nothing to do (?) */
-		| `Sub subs:
-			subdirs(b, subs, `std.None)
 		| `Man mans:
 			/* FIXME: figure out man section by number */
 			for m in mans
--- a/main.myr
+++ b/main.myr
@@ -97,8 +97,10 @@
 	var b
 
 	b = std.zalloc()
-	b.targs = std.mkht(std.strhash, std.streq)
+	b._targs = std.mkht(std.strhash, std.streq)
 	b.gensrc = std.mkht(std.strhash, std.streq)
+	b.basedir = std.getcwd()
+	std.put("base dir = %s\n", b.basedir)
 	-> b
 }
 
--- a/parse.myr
+++ b/parse.myr
@@ -15,6 +15,7 @@
 	rest	: byte[:]
 	fname	: byte[:]
 	fdir	: byte[:]	/* directory relative to base */
+	basedir	: byte[:]
 	line	: int
 
 	/* extracted data for further parsing */
@@ -30,7 +31,7 @@
 	var p : parser#
 	var subpath, subbld, ok
 
-	p = mkparser(path, dir)
+	p = mkparser(path, dir, b.basedir)
 	ok = bld.parse(b, p, "")
 	for s in p.subdirs
 		subpath = std.pathcat(p.fdir, s)
@@ -43,7 +44,7 @@
 	-> ok
 }
 
-const mkparser = {path, dir
+const mkparser = {path, dir, basedir
 	var p
 
 	p = std.zalloc()
@@ -50,6 +51,7 @@
 	p.line = 1
 	p.fname = std.sldup(path)
 	p.fdir = std.sldup(dir)
+	p.basedir = std.sldup(basedir)
 	match std.slurp(path)
 	| `std.Ok d:	p.data = d
 	| `std.Fail _:	std.fatal(1, "could not open '%s'\n", path)
@@ -61,6 +63,7 @@
 const freeparser = {p
 	std.slfree(p.fname)
 	std.slfree(p.fdir)
+	std.slfree(p.basedir)
 	std.slfree(p.subdirs)
 	std.slfree(p.data)
 	std.free(p)
@@ -108,29 +111,41 @@
 
 /* bintarget: myrtarget */
 const bintarget = {b, p
-	addtarg(b, p.fdir, `Bin myrtarget(p, "bin"))
+	var t
+	t = myrtarget(p, "bin")
+	addtarg(p, b, t.name, `Bin t)
 }
 
+/* libtarget: myrtarget */
+const libtarget = {b, p
+	var t
+	t = myrtarget(p, "lib")
+	addtarg(p, b, t.name, `Lib t)
+}
+
 /* testtarget: myrtarget */
 const testtarget = {b, p
-	addtarg(b, p.fdir, `Test myrtarget(p, "test"))
+	var t
+	t = myrtarget(p, "test")
+	addtarg(p, b, t.name, `Test myrtarget(p, "test"))
 }
 
-/* libtarget: myrtarget */
-const libtarget = {b, p
-	addtarg(b, p.fdir, `Lib myrtarget(p, "lib"))
+/* mantarget: anontarget */
+const mantarget = {b, p
+	addtarg(p, b, "__man__", `Man anontarget(p, "man"))
 }
 
 /* subtarget : anontarget */
 const subtarget = {b, p
-	p.subdirs = std.sljoin(p.subdirs, anontarget(p, "sub"))
-}
+	var subs
 
-/* mantarget: anontarget */
-const mantarget = {b, p
-	addtarg(b, p.fdir, `Man anontarget(p, "man"))
+	subs = anontarget(p, "sub")
+	for s in subs
+		p.subdirs = std.slpush(p.subdirs, std.pathcat(p.fdir, s))
+	;;
 }
 
+
 /* gentarget: wordlist {attrs} = wordlist ;; */
 const gentarget = {b, p
 	var outlist, cmdlist
@@ -178,6 +193,7 @@
 	;;
 
 	gt = std.mk([
+		.dir=std.sldup(p.fdir),
 		.out=outlist,
 		.durable=durable,
 		.cmd=cmdlist
@@ -184,8 +200,8 @@
 	])
 	for o in outlist
 		std.htput(b.gensrc, o, gt)
+		addtarg(p, b, o, `Gen gt)
 	;;
-	addtarg(b, p.fdir, `Gen gt)
 }
 
 /*
@@ -251,6 +267,7 @@
 	;;
 	-> std.mk([
 		/* target */
+		.dir=std.sldup(p.fdir),
 		.name=name,
 		.inputs=inputs,
 		.libdeps=libdeps,
@@ -335,6 +352,7 @@
 	| "lib" word
 */
 const inputlist = {p
+	var dir, lib, targ
 	var wl, libs
 
 	wl = [][:]
@@ -343,8 +361,12 @@
 		match word(p)
 		| `std.Some "lib":
 			match word(p)
-			| `std.Some l:	libs = std.slpush(libs, l)
-			| `std.None:	failparse(p, "expected lib name after 'lib'\n")
+			| `std.Some l:
+				(dir, lib, targ) = libpath(p, l)
+				std.put("dir: %s, lib: %s, targ: %s\n", dir, lib, targ)
+				libs = std.slpush(libs, (dir, lib, targ))
+			| `std.None:
+				failparse(p, "expected lib name after 'lib'\n")
 			;;
 		| `std.Some w:	wl = std.slpush(wl, w)
 		| `std.None:	break
@@ -476,10 +498,43 @@
 	-> c
 }
 
-const addtarg = {b, d, t
-	var tl
+const addtarg = {p, b, name, targ
+	var tn
 
-	tl = std.htgetv(b.targs, d, [][:])
-	tl = std.slpush(tl, t)
-	std.htput(b.targs, d, tl)
+	tn = std.fmt("%s:%s", p.fdir, name)
+	if std.hthas(b._targs, tn)
+		failparse(p, "duplicate target %s\n", tn)
+	;;
+	b.all = std.slpush(b.all, tn)
+	std.htput(b._targs, tn, targ)
+}
+
+const libpath = {p, libpath
+	var dir, lib_, targ
+
+	match(std.strrfind(libpath, ":"))
+	| `std.None:
+		dir = std.sldup(".")
+		lib_ = std.sldup(libpath)
+		targ = std.fmt("%s:%s", p.fdir, lib_)
+	| `std.Some idx:
+		if idx == libpath.len
+			std.fatal(1, "libdep %s missing library after ':'\n")
+		;;
+		/* absolute path */
+		if std.hasprefix(libpath, "@/") || std.hasprefix(libpath, "@:")
+			dir = std.pathcat(p.basedir, libpath[2:idx])
+			lib_ = std.sldup(libpath[idx+1:])
+			targ = std.sldup(libpath[2:])
+		/* relative path */
+		else
+			dir = std.sldup(libpath[:idx])
+			lib_ = std.sldup(libpath[idx+1:])
+			targ = std.pathcat(p.fdir, libpath)
+			if std.hasprefix(targ, "../")
+				std.fatal(1, "library %s outside of project\n", libpath)
+			;;
+		;;
+	;;
+	-> (dir, lib_, targ)
 }
--- a/test.myr
+++ b/test.myr
@@ -16,15 +16,13 @@
 ;;
 
 const test = {b
-	var hasdir, ok, bin, targs
+	var ok/*, bin */
 
 	/* no implicit tests to run */
 	ok = true
-	hasdir = std.fexists("test")
-	targs = std.htgetv(b.targs, "", [][:])
-	if hasdir
-		for tt in targs
-			match tt
+	if std.fexists("test")
+		for tn in b.all
+			match gettarg(b._targs, tn)
 			| `Bin bt:
 				if !dotest(b, bt, ok)
 					ok = false
@@ -37,6 +35,8 @@
 			;;
 		;;
 	;;
+	/*
+	FIXME: reenable test binaries
 	for `Test t in targs
 		for s in t.incpath
 			if std.sleq(".", s)
@@ -53,6 +53,7 @@
 		;;
 		std.slfree(bin)
 	;;
+	*/
 	if ok
 		std.put("TESTS PASSED\n")
 	else
@@ -61,10 +62,11 @@
 	;;
 }
 
-const dotest = {p, targ, ok
+const dotest = {b, targ, ok
 	var tt, bin ,path, tests
 
 	tests = [][:]
+	setdir(b, targ.dir)
 	for s in targ.inputs
 		path = std.pathcat("./test", s)
 		if std.fexists(path)
@@ -71,6 +73,7 @@
 			bin = srcswapsuffix(path, "")
 			tt = [
 				.name = bin,
+				.dir = targ.dir,
 				.inputs = [path, s][:],
 				.install = false,
 				.libdeps = targ.libdeps,
@@ -78,8 +81,8 @@
 				.built = false,
 			]
 
-			cleantest(p, path)
-			buildbin(p, &tt, true)
+			cleantest(b, path)
+			buildbin(b, &tt, true)
 			tests = std.slpush(tests, bin)
 		;;
 		std.slfree(path)
@@ -96,7 +99,7 @@
 	-> ok
 }
 
-const cleantest = {p, src
+const cleantest = {b, src
 	var obj, bin, log, usef
 
 	obj = srcswapsuffix(src, config.Objsuffix)
--- a/types.myr
+++ b/types.myr
@@ -2,10 +2,14 @@
 
 pkg bld =
 	type build = struct
-		cmd	: byte[:][:]
+		cmd	: byte[:][:]	/* command that we ran */
+		/* build state */
+		basedir	: byte[:]
 		/* build params */
-		targs	: std.htab(byte[:], targ[:])#	/* dir => target mapping */
-		gensrc	: std.htab(byte[:], gentarg#)#
+		all	: byte[:][:]
+		_targs	: std.htab(byte[:], targ)#	/* dir => target mapping */
+		tdeps	: std.htab(byte[:], byte[:][:])	/* targname => depname[:] mapping */
+		gensrc	: std.htab(byte[:], gentarg#)#	/* generated src => generating target mapping */
 		prefix	: byte[:]
 		system	: byte[:]
 		arch	: byte[:]
@@ -24,9 +28,10 @@
 	;;
 
 	type myrtarg = struct
+		dir	: byte[:]
 		name	: byte[:]
 		inputs	: byte[:][:]
-		libdeps	: byte[:][:]
+		libdeps	: (byte[:], byte[:], byte[:])[:]	/* dir, lib pairs */
 		built	: bool
 		install	: bool
 		runtime	: byte[:]
@@ -35,9 +40,12 @@
 	;;
 
 	type gentarg = struct
+		dir	: byte[:]
 		out	: byte[:][:]
 		cmd	: byte[:][:] 
 		durable	: bool
+		/* we can have multiple outputs, but we only want to run once for each */
+		done	: bool
 	;;
 
 	type targ = union
@@ -45,7 +53,6 @@
 		`Lib	myrtarg#
 		`Test	myrtarg#
 		`Gen	gentarg#
-		`Sub	byte[:][:]
 		`Man	byte[:][:]
 	;;
 ;;
--- a/util.myr
+++ b/util.myr
@@ -1,6 +1,7 @@
 use std
 
 use "opts.use"
+use "types.use"
 
 pkg bld =
 	const run	: (cmd : byte[:][:] -> void)
@@ -9,6 +10,8 @@
 	const swapsuffix	: (f : byte[:], suff : byte[:], newsuff : byte[:] -> byte[:])
 	const srcswapsuffix	: (f : byte[:], newsuff : byte[:] -> byte[:])
 	const strlistfree	: (sl : byte[:][:] -> void)
+	const gettarg	: (tab : std.htab(byte[:], targ)#, n : byte[:] -> targ)
+	const setdir	: (b : build#, dir : byte[:] -> void)
 ;;
 
 const run = {cmd
@@ -91,5 +94,23 @@
 		std.slfree(s)
 	;;
 	std.slfree(sl)
+}
+
+const gettarg = {tab, n
+	match std.htget(tab, n)
+	| `std.None:	std.fatal(1, "internal: nonexistent %s\n", n)
+	| `std.Some t:	-> t
+	;;
+}
+
+const setdir = {b, dir
+	var p
+
+	p = std.pathcat(b.basedir, dir)
+	std.put("changing into '%s'\n", p)
+	if !std.chdir(p)
+		std.fatal(1, "could not cd into %s\n")
+	;;
+	std.slfree(p)
 }