Really basic skeleton of Ackbuilder mark 2.
This commit is contained in:
parent
d0bfee142b
commit
df1372ab35
1 changed files with 63 additions and 232 deletions
|
@ -1,254 +1,85 @@
|
||||||
local M = {}
|
-- Targets:
|
||||||
|
--
|
||||||
|
-- {
|
||||||
|
-- dir = target's build directory
|
||||||
|
-- outs = target's object files
|
||||||
|
-- is = { set of rule types which made the target }
|
||||||
|
-- }
|
||||||
|
|
||||||
function M.subenv(p)
|
local environment = {}
|
||||||
local e = p[1]
|
local rules = {}
|
||||||
setmetable(p, {__index = e})
|
|
||||||
return p
|
local function subenv(old, cb)
|
||||||
|
if not old then
|
||||||
|
old = environment
|
||||||
|
end
|
||||||
|
local new = {}
|
||||||
|
setmetatable(new, {__index = old})
|
||||||
|
cb(new, old)
|
||||||
|
return new
|
||||||
end
|
end
|
||||||
|
|
||||||
local function check_filename(fn)
|
local function asstring(o)
|
||||||
if type(fn) == "table" then
|
local t = type(o)
|
||||||
for _, f in ipairs(fn) do
|
if (t == "string") then
|
||||||
check_filename(f)
|
return o
|
||||||
|
elseif (t == "number") then
|
||||||
|
return o
|
||||||
|
elseif (t == "table") then
|
||||||
|
local s = {}
|
||||||
|
for _, v in pairs(o) do
|
||||||
|
s[#s+1] = asstring(v)
|
||||||
end
|
end
|
||||||
|
return table.concat(s, " ")
|
||||||
else
|
else
|
||||||
if fn:find("%s") then
|
error(string.format("can't turn values of type '%s' into strings", t))
|
||||||
error("Filename '"+fn+"' contains spaces. This will make the build system sad.")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function M.basename(fn)
|
|
||||||
if type(fn) == "table" then
|
|
||||||
local nfn = {}
|
|
||||||
for _, f in ipairs(fn) do
|
|
||||||
nfn[#nfn+1] = M.basename(f)
|
|
||||||
end
|
|
||||||
return nfn
|
|
||||||
else
|
|
||||||
local _, _, base = fn:find("([^/]*)$")
|
|
||||||
return base
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.flatten(t)
|
|
||||||
if t == nil then
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local tt = {}
|
|
||||||
for _, subt in ipairs(t) do
|
|
||||||
if type(subt) == "table" then
|
|
||||||
for _, subt in ipairs(M.flatten(subt)) do
|
|
||||||
tt[#tt+1] = subt
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tt[#tt+1] = subt
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return tt
|
|
||||||
end
|
|
||||||
|
|
||||||
local function append(...)
|
|
||||||
local ts = {}
|
|
||||||
for _, t in ipairs({...}) do
|
|
||||||
for _, v in ipairs(t) do
|
|
||||||
ts[#ts+1] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ts
|
|
||||||
end
|
|
||||||
|
|
||||||
local function settotable(s)
|
|
||||||
local t = {}
|
|
||||||
for k in pairs(s) do
|
|
||||||
t[#t+1] = k
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
local function asstring(t)
|
|
||||||
return table.concat(M.flatten(t), " ")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function emit(...)
|
local function emit(...)
|
||||||
for _, s in ipairs({...}) do
|
local n = select("#", ...)
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
for i=1, n do
|
||||||
|
local s = asstring(args[i])
|
||||||
io.stdout:write(s)
|
io.stdout:write(s)
|
||||||
|
if not s:find("\n$") then
|
||||||
|
io.stdout:write(" ")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.rawtarget(p)
|
local function definerule(name, cb)
|
||||||
local description = p.description or error("no description supplied")
|
if rules[name] then
|
||||||
local ins = M.flatten(p.ins)
|
error(string.format("rule '%s' is already defined", name))
|
||||||
local outs = M.flatten(p.outs)
|
end
|
||||||
|
|
||||||
local cmd = p.command
|
|
||||||
if type(cmd) ~= "table" then
|
|
||||||
cmd = {cmd}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, s in ipairs(ins) do
|
-----------------------------------------------------------------------------
|
||||||
check_filename(s)
|
-- MAIN PROGRAM --
|
||||||
end
|
-----------------------------------------------------------------------------
|
||||||
for _, s in ipairs(outs) do
|
|
||||||
check_filename(s)
|
|
||||||
end
|
|
||||||
|
|
||||||
emit(outs[1], ":")
|
local globals = {
|
||||||
for _, s in ipairs(ins) do
|
asstring = asstring,
|
||||||
emit(" ", s)
|
definerule = definerule,
|
||||||
end
|
emit = emit,
|
||||||
emit("\n")
|
environment = environment,
|
||||||
|
|
||||||
emit("\t@echo ", p.description, "\n")
|
|
||||||
|
|
||||||
emit("\t$(hide) ", table.concat(cmd, " && "), "\n")
|
|
||||||
|
|
||||||
for i = 2, #outs do
|
|
||||||
emit(outs[i], ": ", outs[1], "\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
emit("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.export(p)
|
|
||||||
local e = p[1]
|
|
||||||
local dest = p.dest or error("no export destination provided")
|
|
||||||
local deps = p.deps or error("nothing to export")
|
|
||||||
|
|
||||||
local fdeps = M.flatten(deps)
|
|
||||||
|
|
||||||
if #fdeps ~= 1 then
|
|
||||||
error("you can only export one thing at a time")
|
|
||||||
end
|
|
||||||
|
|
||||||
return M.rawtarget {e,
|
|
||||||
ins=deps,
|
|
||||||
outs={dest},
|
|
||||||
command="cp "..fdeps[1].." "..dest,
|
|
||||||
description="EXPORT "..dest
|
|
||||||
}
|
}
|
||||||
end
|
setmetatable(globals, {__index = _G})
|
||||||
|
|
||||||
function M.hermetic(p)
|
|
||||||
local e = p[1]
|
|
||||||
local ins = M.flatten(p.ins)
|
|
||||||
local deps = M.flatten(p.deps)
|
|
||||||
local baseouts = p.baseouts or error("you must specify some baseouts")
|
|
||||||
local description = p.description
|
|
||||||
|
|
||||||
local absouts = {}
|
|
||||||
local path = e.PATH .. "/" .. p.baseouts[1] .. ".env"
|
|
||||||
|
|
||||||
for _, s in ipairs(M.flatten(p.baseouts)) do
|
|
||||||
absouts[#absouts+1] = path .. "/" .. s
|
|
||||||
end
|
|
||||||
|
|
||||||
local dirset = {}
|
|
||||||
for _, s in ipairs(absouts) do
|
|
||||||
local d = s:gsub("^(.*/).*$", "%1")
|
|
||||||
if d then
|
|
||||||
dirset[d] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local newcmd = {
|
|
||||||
"rm -rf "..path,
|
|
||||||
"mkdir -p "..asstring(settotable(dirset)),
|
|
||||||
"ln -srf "..asstring(append(ins, deps)).." "..path,
|
|
||||||
"cd "..path
|
|
||||||
}
|
|
||||||
for _, s in ipairs(p.command) do
|
|
||||||
newcmd[#newcmd+1] = "(" .. s .. ")"
|
|
||||||
end
|
|
||||||
|
|
||||||
M.rawtarget {e,
|
|
||||||
ins={ins, unpack(deps)},
|
|
||||||
outs=absouts,
|
|
||||||
command=newcmd,
|
|
||||||
description=description
|
|
||||||
}
|
|
||||||
|
|
||||||
return absouts
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.cfile(p)
|
|
||||||
local e = p[1]
|
|
||||||
local src = p.src
|
|
||||||
local deps = p.deps or {}
|
|
||||||
|
|
||||||
local outfile = p.src:gsub("%.c$", ".o")
|
|
||||||
local basesrc = M.basename(p.src)
|
|
||||||
|
|
||||||
return M.hermetic {e,
|
|
||||||
ins={src},
|
|
||||||
deps=deps,
|
|
||||||
baseouts={outfile},
|
|
||||||
command={e.CC.." "..e.CFLAGS.." -c -o "..outfile.." "..basesrc},
|
|
||||||
description="CC "..src
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.cprogram(p)
|
|
||||||
local e = p[1]
|
|
||||||
local name = p.name or error("cprogram must have a name specified")
|
|
||||||
local deps = p.deps or {}
|
|
||||||
local libs = p.libraries or {}
|
|
||||||
local headers = p.headers or {}
|
|
||||||
|
|
||||||
if p.srcs then
|
|
||||||
local mainlib = M.clibrary {e,
|
|
||||||
name=name..".a",
|
|
||||||
deps=deps,
|
|
||||||
srcs=p.srcs,
|
|
||||||
headers=headers
|
|
||||||
}
|
|
||||||
|
|
||||||
deps = append(deps, {mainlib})
|
|
||||||
end
|
|
||||||
|
|
||||||
local libflags = {}
|
|
||||||
for _, s in ipairs(libs) do
|
|
||||||
libflags[#libflags+1] = "-l"..s
|
|
||||||
end
|
|
||||||
|
|
||||||
return M.hermetic {e,
|
|
||||||
ins=deps,
|
|
||||||
baseouts={name},
|
|
||||||
command={e.CC.." "..e.CFLAGS.." -o "..name.." "..asstring(M.basename(deps)).." "..asstring(libflags)},
|
|
||||||
description="CLINK "..name
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.clibrary(p)
|
|
||||||
local e = p[1]
|
|
||||||
local name = p.name or error("clibrary must have a name specified")
|
|
||||||
local deps = M.flatten(p.deps)
|
|
||||||
local srcs = M.flatten(p.srcs)
|
|
||||||
local headers = M.flatten(p.headers)
|
|
||||||
|
|
||||||
local baseouts = {name}
|
|
||||||
|
|
||||||
local objs = deps
|
|
||||||
for _, f in ipairs(srcs) do
|
|
||||||
objs[#objs+1] = M.cfile {e,
|
|
||||||
src=f,
|
|
||||||
deps=headers
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return M.hermetic {e,
|
|
||||||
ins=append(objs, headers),
|
|
||||||
baseouts=baseouts,
|
|
||||||
command={
|
|
||||||
e.AR.." q "..name.." "..asstring(M.basename(objs)),
|
|
||||||
e.RANLIB.." "..name,
|
|
||||||
},
|
|
||||||
description="CLIBRARY "..name
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
emit("hide=@\n")
|
emit("hide=@\n")
|
||||||
|
for _, file in ipairs({...}) do
|
||||||
|
local data, chunk, e
|
||||||
|
data = io.open(file):read("*a")
|
||||||
|
if not e then
|
||||||
|
local thisglobals = {_G = thisglobals}
|
||||||
|
setmetatable(thisglobals, {__index = globals})
|
||||||
|
chunk, e = loadstring(data, file, "text", thisglobals)
|
||||||
|
end
|
||||||
|
if e then
|
||||||
|
error(string.format("couldn't load '%s': %s", file, e))
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
local _, e = pcall(chunk)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue