190 lines
3.5 KiB
Lua
190 lines
3.5 KiB
Lua
local lfs = require(jit and 'lfs_ffi' or 'lfs')
|
|
local inspect
|
|
function inspect(t,s)
|
|
s = s or ""
|
|
r = ""
|
|
for k,v in pairs(t) do
|
|
r = r..(s..k..": "..(type(v) == "table" and "\n"..inspect(v,s.." ") or tostring(v).."\n"))
|
|
end
|
|
return r
|
|
end
|
|
|
|
local path = lfs.currentdir() .. "/build.lua"
|
|
|
|
local buildf = loadfile(path)
|
|
if not buildf then
|
|
error "no build file"
|
|
end
|
|
|
|
local function initvar(name, default)
|
|
_G[name] = os.getenv(name) or default or ""
|
|
end
|
|
|
|
initvar("CC", "gcc")
|
|
initvar("CFLAGS")
|
|
initvar("LINK")
|
|
initvar("SRC", "*.c")
|
|
|
|
opt = {}
|
|
|
|
for _,arg in ipairs(arg) do
|
|
opt[arg] = true
|
|
end
|
|
|
|
function buildobj(o)
|
|
local cmd = ("%s %s %s -c -o %s %s"):format(CC, CFLAGS, LINK, o.out, o.src)
|
|
print("BUILDING OBJECT:\n"..cmd)
|
|
return os.execute(cmd)
|
|
end
|
|
|
|
function buildprog()
|
|
local objs = ""
|
|
for _,o in ipairs(OBJ) do
|
|
objs = objs..o.path.." "
|
|
end
|
|
local cmd = ("%s %s %s -o %s %s"):format(CC, CFLAGS, LINK, PROG, objs)
|
|
print("BUILDING PROGRAM:\n"..cmd)
|
|
return os.execute(cmd)
|
|
end
|
|
|
|
buildf()
|
|
|
|
if not PROG then
|
|
error "must provide 'PROG'"
|
|
end
|
|
|
|
function issourcefile(f)
|
|
return f:sub(#f-1,#f) == ".c" or f:sub(#f-3,#f) == ".cpp"
|
|
end
|
|
|
|
local function concat(dir,file) --concats directory name + filename
|
|
if not dir or dir == lfs.currentdir() then
|
|
return file
|
|
else
|
|
|
|
return ({(dir .. "/" .. file)
|
|
:gsub("[^/]*/../", "") --remove redundant expressions as in "foo/../bar" -> "bar"
|
|
})[1]
|
|
end
|
|
end
|
|
|
|
if SRC =="*.c" then
|
|
SRC = {}
|
|
local find
|
|
function find(dir)
|
|
--print("searching in "..dir)
|
|
for f,_ in lfs.dir(dir) do
|
|
local attr = lfs.attributes(concat(dir,f))
|
|
if attr and (attr.mode == "file" or attr.mode == "link") and issourcefile(f) then
|
|
table.insert(SRC, concat(dir,f))
|
|
elseif attr and attr.mode == "directory" and f ~= "." and f ~= ".." and f ~= ".git" then
|
|
find(concat(dir,f)) --recursive
|
|
end
|
|
end
|
|
end
|
|
find(lfs.currentdir())
|
|
end
|
|
|
|
if _SHOWSRC then
|
|
print(inspect(SRC))
|
|
end
|
|
|
|
function getdeps(p, exclude)
|
|
--print(p)
|
|
local f = io.open(p)
|
|
if not f then
|
|
return nil
|
|
end
|
|
|
|
exclude = exclude or {}
|
|
for k,v in ipairs(exclude) do exclude[v] = true end
|
|
local deps = {}
|
|
|
|
local _,_,dir = p:find("(.*)/.*$")
|
|
|
|
for l in f:lines() do
|
|
local _,_,s = l:find('%s*#include%s*\"(.*)\"')
|
|
if s then
|
|
s = concat(dir,s)
|
|
--print(s)
|
|
local dep2 = getdeps(s, deps)
|
|
if not exclude[s] then
|
|
for k,v in ipairs(dep2) do
|
|
table.insert(deps, v)
|
|
end
|
|
table.insert(deps,s)
|
|
end
|
|
end
|
|
end
|
|
|
|
for k,v in pairs(deps) do
|
|
if type(k) == "string" then
|
|
deps[k] = nil
|
|
end
|
|
end
|
|
return deps
|
|
end
|
|
|
|
OBJ = {}
|
|
|
|
for k,v in ipairs(SRC) do
|
|
OBJ[k] = {
|
|
path = v:gsub("%.cp?p?$", ".o"),
|
|
deps = getdeps(v),
|
|
src = v
|
|
}
|
|
table.insert(OBJ[k].deps, v)
|
|
end
|
|
|
|
if _SHOWOBJ then
|
|
print(inspect(OBJ))
|
|
end
|
|
|
|
if opt.clean then
|
|
local objs = ""
|
|
for _,o in ipairs(OBJ) do
|
|
objs = objs..o.path.." "
|
|
end
|
|
|
|
local cmd = ("rm %s %s"):format(objs, PROG)
|
|
print("CLEANING: "..cmd)
|
|
return os.execute(cmd)
|
|
end
|
|
|
|
local tobuild = {}
|
|
|
|
for _,o in ipairs(OBJ) do
|
|
local attr = lfs.attributes(o.path)
|
|
if not attr then
|
|
table.insert(tobuild, {src = o.src, out = o.path})
|
|
else
|
|
local o_mod = attr.modification
|
|
for _,dep in ipairs(o.deps) do
|
|
local d_mod = lfs.attributes(dep).modification
|
|
--print(o_mod-d_mod)
|
|
if d_mod > o_mod then
|
|
--dependency is newer: rebuild
|
|
table.insert(tobuild, {src = o.src, out = o.path})
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if #tobuild < 1 then
|
|
print "nothing to do"
|
|
return 0
|
|
end
|
|
|
|
if _SHOWBUILD then
|
|
print(inspect(tobuild))
|
|
end
|
|
|
|
for _,o in ipairs(tobuild) do
|
|
if not buildobj(o) then
|
|
print("ERROR")
|
|
os.exit(1)
|
|
end
|
|
end
|
|
|
|
return buildprog()
|