Multiple build files work. Use deps intelligently. clibraries.
authorDavid Given <dg@cowlark.com>
Thu, 9 Jun 2016 04:55:44 +0000 (06:55 +0200)
committerDavid Given <dg@cowlark.com>
Thu, 9 Jun 2016 04:55:44 +0000 (06:55 +0200)
first/ackbuilder.lua
first/build.lua
modules/build.lua [new file with mode: 0644]

index 850e228..33806b3 100644 (file)
@@ -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,
index 95b6a64..6dc0e49 100644 (file)
@@ -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,23 +74,83 @@ 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
 
-cfile {
-       name = "testfile-foo",
-       srcs = "foo.c",
-}
+               return normalrule {
+                       name = e.name,
+                       ins = e.srcs,
+                       outleaves = outleaves,
+                       label = e.label,
+                       commands = commands
+               }
+       end
+)
 
-cfile {
-       name = "testfile-bar",
-       srcs = {"bar.c", ":mkheader"},
+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"
+       }
 }
 
 --[[
diff --git a/modules/build.lua b/modules/build.lua
new file mode 100644 (file)
index 0000000..4297f59
--- /dev/null
@@ -0,0 +1,5 @@
+bundle {
+       name = "headers",
+       srcs = { "./h/*.h" }
+}
+