diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index 3a85c1e2c..72b4392a3 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -53,6 +53,25 @@ local function concatpath(...) return p:gsub("/+", "/"):gsub("^%./", "") end +local function basename(filename) + local _, _, b = filename:find("^.*/([^/]*)$") + if not b then + return "" + end + return b +end + +local function basenames(collection) + local o = {} + for _, s in pairs(collection) do + local b = basename(s) + if (b ~= "") then + o[#o+1] = b + end + end + return o +end + local function dirname(filename) local _, _, b = filename:find("^(.*)/[^/]*$") if not b then @@ -74,13 +93,15 @@ end local function filenamesof(results) local f = {} - for _, r in pairs(results) do - if (type(r) == "string") then - f[#f+1] = r - elseif (type(r) == "table") then - if r.is and r.outs then - for _, o in pairs(r.outs) do - f[#f+1] = o + if results then + for _, r in pairs(results) do + if (type(r) == "string") then + f[#f+1] = r + elseif (type(r) == "table") then + if r.is and r.outs then + for _, o in pairs(r.outs) do + f[#f+1] = o + end end end end @@ -88,6 +109,27 @@ local function filenamesof(results) return f end +local function selectof(pattern, targets) + local o = {} + for k, v in pairs(targets) do + if v.is and v.outs then + local targetmatches = nil + for _, f in pairs(v.outs) do + local matches = not not f:find(pattern) + if (targetmatches == nil) then + targetmatches = matches + elseif (targetmatches ~= matches) then + error("selectof() is matching only part of a target") + end + end + if targetmatches then + o[#o+1] = v + end + end + end + return o +end + local function uniquify(collection) local s = {} local o = {} @@ -238,6 +280,13 @@ local typeconverters = { end return i end, + + table = function(propname, i) + if (type(i) ~= "table") then + error(string.format("property '%s' must be a table", propname)) + end + return i + end, } local function definerule(rulename, types, cb) @@ -258,7 +307,7 @@ local function definerule(rulename, types, cb) local args = {} for propname, typespec in pairs(types) do if not e[propname] then - if not typespec.optional then + if not typespec.optional and not typespec.default then error(string.format("missing mandatory property '%s'", propname)) end @@ -325,19 +374,22 @@ definerule("simplerule", outs = { type="strings" }, label = { type="string", optional=true }, commands = { type="strings" }, + vars = { type="table", default={} }, }, function (e) e.environment:rule(filenamesof(e.ins), e.outs) e.environment:label(cwd..":"..e.name, " ", e.label or "") e.environment:mkdirs(dirnames(filenamesof(e.outs))) - e.environment:exec( - templateexpand(e.commands, - { - ins = e.ins, - outs = e.outs - } - ) - ) + + local vars = { + ins = e.ins, + outs = e.outs + } + for k, v in pairs(e.vars) do + vars[k] = v + end + + e.environment:exec(templateexpand(e.commands, vars)) e.environment:endrule() return { @@ -352,11 +404,17 @@ definerule("simplerule", globals = { asstring = asstring, + basename = basename, + basenames = basenames, concatpath = concatpath, cwd = cwd, definerule = definerule, + dirname = dirname, + dirnames = dirnames, emit = emit, environment = environment, + filenamesof = filenamesof, + selectof = selectof, } setmetatable(globals, { diff --git a/first/build.lua b/first/build.lua index 2ab1b3cc4..03077a414 100644 --- a/first/build.lua +++ b/first/build.lua @@ -4,6 +4,7 @@ definerule("normalrule", outleaves = { type="strings" }, label = { type="string", optional=true }, commands = { type="strings" }, + vars = { type="table", default={} }, }, function (e) local objpath = "$(OBJDIR)/"..e.name @@ -12,76 +13,76 @@ definerule("normalrule", realouts[k] = concatpath(objpath, v) end - return simplerule { + local result = simplerule { name = e.name, ins = e.ins, outs = realouts, label = e.label, commands = e.commands, + vars = e.vars, + } + result.dir = objpath + return result + end +) + +definerule("cfile", + { + srcs = { type="targets" }, + hdrs = { type="targets", default={} }, + commands = { + type="strings", + default={ + "$CC -c -o %{outs[1]} %{ins[1]} %{hdrpaths}" + }, + } + }, + function (e) + if (#e.srcs ~= 1) then + error("you must have exactly one .c file") + end + + hdrpaths = {} + for _, t in pairs(e.hdrs) do + hdrpaths[#hdrpaths+1] = "-I"..t.dir + end + + local outleaf = basename(filenamesof(e.srcs)[1]):gsub("%.c$", ".o") + + return normalrule { + name = e.name, + ins = {e.srcs[1], unpack(e.hdrs)}, + outleaves = {outleaf}, + label = e.label, + commands = e.commands, + vars = { + hdrpaths = hdrpaths + } } end ) - normalrule { - name = "random", + name = "mkheader", ins = {}, - outleaves = {"out"}, + outleaves = {"foo.h"}, commands = { - "dd if=/dev/random of=%{outs} bs=1024 count=1" + "echo 1 >> %{outs}" } } -normalrule { - name = "onetwo", - ins = {}, - outleaves = {"one.txt", "two.txt"}, - commands = { - "echo 1 >> %{outs[1]}", - "echo 2 >> %{outs[2]}", - } +cfile { + name = "testfile-foo", + srcs = "foo.c", } -normalrule { - name = "concat", - ins = {":onetwo"}, - outleaves = {"result.txt"}, - commands = { - "cat %{ins} > %{outs}" - } -} - -simplerule { - name = "sorted", - ins = { ":random" }, - outs = { "sorted" }, - commands = { - "sort %{ins} > %{outs}" - } +cfile { + name = "testfile-bar", + srcs = "bar.c", + hdrs = ":mkheader", } --[[ -function environment:cfileflags() - emit("$CFLAGS") -end - -function environment:cfile(srcs, obj, includes) - emit("$CC -o", obj, srcs) - emit(ab.expand(includes, "-I%")) - self:cflags() - emit("\n") -end - -function environment:clinkflags() - emit("$LDFLAGS") -end - -function environment:clink(objs, exe, libraryFlags) - emit("$CC -o", exe, objs, libraryFlags) - self:clinkflags() - emit("\n") -end - -- -- Targets: --