diff --git a/first/ackbuilder.lua b/first/ackbuilder.lua index 850e22875..33806b3be 100644 --- a/first/ackbuilder.lua +++ b/first/ackbuilder.lua @@ -15,14 +15,18 @@ local buildfiles = {} local globals local cwd = "." -local function subenv(old, cb) - if not old then - old = environment - end - local new = {} - setmetatable(new, {__index = old}) - cb(new, old) - return new +local function inherit(high, low) + local o = {} + setmetatable(o, { + __index = function(self, k) + local x = high[k] + if x then + return x + end + return low[k] + end + }) + return o end local function asstring(o) @@ -50,7 +54,7 @@ end local function concatpath(...) local p = table.concat({...}, "/") - return p:gsub("/+", "/"):gsub("^%./", "") + return p:gsub("/+", "/"):gsub("^%./", ""):gsub("/%./", "/") end local function basename(filename) @@ -144,6 +148,10 @@ local function uniquify(collection) return o end +local function startswith(needle, haystack) + return haystack:sub(1, #needle) == needle +end + local function emit(...) local n = select("#", ...) local args = {...} @@ -158,7 +166,7 @@ local function emit(...) end local function templateexpand(list, vars) - setmetatable(vars, { __index = globals }) + vars = inherit(vars, globals) local o = {} for _, s in ipairs(list) do @@ -210,8 +218,18 @@ local function loadtarget(targetname) local target if not targetname:find(":") then + local files + if targetname:find("[?*]") then + files = posix.glob(targetname) + if not files then + error(string.format("glob '%s' matches no files", targetname)) + end + else + files = {targetname} + end + target = { - outs = {targetname}, + outs = files, is = { __implicitfile = true } @@ -251,11 +269,9 @@ local typeconverters = { if (type(s) == "table") and s.is then o[#o+1] = s elseif (type(s) == "string") then - if s:find("^//") then - s = s:gsub("^//", "") - elseif s:find("^:") then + if s:find("^:") then s = cwd..s - elseif s:find("^[^/]") then + elseif s:find("^%./") then s = concatpath(cwd, s) end o[#o+1] = loadtarget(s) @@ -383,13 +399,10 @@ definerule("simplerule", e.environment:label(cwd..":"..e.name, " ", e.label or "") e.environment:mkdirs(dirnames(e.outs)) - local vars = { + local vars = inherit(e.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() @@ -416,7 +429,9 @@ globals = { emit = emit, environment = environment, filenamesof = filenamesof, + inherit = inherit, selectof = selectof, + startswith = startswith, uniquify = uniquify, } setmetatable(globals, diff --git a/first/build.lua b/first/build.lua index 95b6a64f6..6dc0e49cf 100644 --- a/first/build.lua +++ b/first/build.lua @@ -13,13 +13,17 @@ definerule("normalrule", realouts[k] = concatpath(objpath, v) end + local vars = inherit(e.vars, { + dir = objpath + }) + local result = simplerule { name = e.name, ins = e.ins, outs = realouts, label = e.label, commands = e.commands, - vars = e.vars, + vars = vars, } result.dir = objpath return result @@ -29,10 +33,11 @@ definerule("normalrule", definerule("cfile", { srcs = { type="targets" }, + deps = { type="targets", default={} }, commands = { type="strings", default={ - "$CC -c -o %{outs[1]} %{ins[1]} %{hdrpaths}" + "$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths}" }, } }, @@ -42,18 +47,23 @@ definerule("cfile", error("you must have exactly one .c file") end - local htargets = selectof(e.srcs, "%.h$") + local hsrcs = filenamesof(e.srcs, "%.h$") + local hdeps = selectof(e.deps, "%.h$") local hdrpaths = {} - for _, t in pairs(htargets) do + for _, t in pairs(hdeps) do hdrpaths[#hdrpaths+1] = "-I"..t.dir end hdrpaths = uniquify(hdrpaths) + for _, f in pairs(filenamesof(hdeps)) do + hsrcs[#hsrcs+1] = f + end + local outleaf = basename(csrcs[1]):gsub("%.c$", ".o") return normalrule { name = e.name, - ins = {csrcs[1], unpack(htargets)}, + ins = {csrcs[1], unpack(hsrcs)}, outleaves = {outleaf}, label = e.label, commands = e.commands, @@ -64,25 +74,85 @@ definerule("cfile", end ) -normalrule { - name = "mkheader", - ins = {}, - outleaves = {"foo.h"}, - commands = { - "echo 1 >> %{outs}" +definerule("bundle", + { + srcs = { type="targets" }, + commands = { + type="strings", + default={ + "tar cf - %{ins} | (cd %{dir} && tar xf -)" + } + } + }, + function (e) + local outleaves = {} + local commands = {} + for _, f in pairs(filenamesof(e.srcs)) do + local localf = basename(f) + outleaves[#outleaves+1] = localf + commands[#commands+1] = "cp "..f.." %{dir}/"..localf + end + + return normalrule { + name = e.name, + ins = e.srcs, + outleaves = outleaves, + label = e.label, + commands = commands + } + end +) + +definerule("clibrary", + { + srcs = { type="targets" }, + deps = { type="targets", default={} }, + commands = { + type="strings", + default={ + "rm -f %{outs}", + "$(AR) qs %{outs} %{ins}" + }, + } + }, + function (e) + local csrcs = filenamesof(e.srcs, "%.c$") + if (#csrcs < 1) then + error("you must supply at least one C source file") + end + + local hsrcs = filenamesof(e.srcs, "%.h$") + + local ins = {} + for _, csrc in pairs(csrcs) do + local n = basename(csrc):gsub("%.%w*$", "") + ins[#ins+1] = cfile { + name = e.name.."/"..n, + srcs = {csrc, unpack(hsrcs)}, + deps = e.deps, + } + end + + return normalrule { + name = e.name, + ins = ins, + outleaves = { e.name..".a" }, + label = e.label, + commands = e.commands + } + end +) + +clibrary { + name = "mylib", + srcs = { + "modules/src/string/*.c", + }, + deps = { + "modules:headers" } } -cfile { - name = "testfile-foo", - srcs = "foo.c", -} - -cfile { - name = "testfile-bar", - srcs = {"bar.c", ":mkheader"}, -} - --[[ -- -- Targets: diff --git a/modules/build.lua b/modules/build.lua new file mode 100644 index 000000000..4297f59d0 --- /dev/null +++ b/modules/build.lua @@ -0,0 +1,5 @@ +bundle { + name = "headers", + srcs = { "./h/*.h" } +} +