Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
niaow committed Jan 14, 2018
0 parents commit bdb3dda
Show file tree
Hide file tree
Showing 11 changed files with 491 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.o
*.so
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
all: liblbuild_util.so

liblbuild_util.so: util.c
$(CC) $(CFLAGS) -fPIC -shared util.c -o liblbuild_util.so

$(DESTDIR)/usr/lib/liblbuild_util.so: liblbuild_util.so
install -D -m 0744 $< $@

$(DESTDIR)/usr/bin/lbuild: lbuild.lua
install -D -m 0755 $< $@

$(DESTDIR)/usr/share/lua/5.1/lbuild/%.lua: lbuild/%.lua
install -D -m 0744 $< $@

install: $(DESTDIR)/usr/lib/liblbuild_util.so $(DESTDIR)/usr/bin/lbuild \
$(foreach l,$(shell ls lbuild),$(DESTDIR)/usr/share/lua/5.1/lbuild/$(l))

clean:
rm -f *.so example/*.o
2 changes: 2 additions & 0 deletions example/build.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
addcmd("hello.o", {"hello.c"}, {"/usr/bin/cc", "hello.c", "-o", "hello.o"})
addcmd("hello", {}, {"/bin/echo", "hello", "world"})
5 changes: 5 additions & 0 deletions example/hello.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include<stdio.h>

int main(int argc, char **argv) {
printf("Hello world");
}
36 changes: 36 additions & 0 deletions lbuild.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/luajit

local ruletable = require("lbuild.ruletable")
local runner = require("lbuild.runner")

local f = assert(io.open("build.lua", "rb"))
loadstring([[
local runner = require("lbuild.runner")
local ruletable = require("lbuild.ruletable")
local add = function(...)
ruletable:add(...)
end
local addcmd = function(...)
ruletable:addcmd(...)
end
]] .. f:read("*all"))()

local targs = {...}

local n = #targs

for _, r in ipairs(targs) do
ruletable:run(r):prom(function()
print("Done building " .. r)
n = n - 1
if n == 0 then
os.exit()
end
end)
end

if n == 0 then
print("Nothing to do")
end

while true do runner:wait() end
81 changes: 81 additions & 0 deletions lbuild/cc.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
--util for compiling c/c++
--work in progress

local runner = require("lbuild.runner")
local path = require("lbuild.path")
--local os lib
local os = os

--the library table
local cc = {}

--find cc to use
cc.CC = (os.getenv("CC") or ""):gmatch("^[ \n]+")
--find cxx to use
cc.CXX = (os.getenv("CXX") or ""):gmatch("^[ \n]+")
--load CFLAGS
cc.CFLAGS = (os.getenv("CFLAGS") or ""):gmatch("^[ \n]+")
--load CXXFLAGS
cc.CXXFLAGS = (os.getenv("CXXFLAGS") or ""):gmatch("^[ \n]+")

--compiling a file with the -c option
--file, output file, extra args
function cc:ccc(file, outf, ...)
if outf == nil then
outf = path:stripext(file) .. ".o"
end
return runner:run(self.CC, "-c", table:unpack(self.CFLAGS), ..., "-o", outf)
end
function cc:cxxc(file, outf, ...)
if outf == nil then
outf = path:stripext(file) .. ".o"
end
return runner:run(self.CXX, "-c", table:unpack(self.CXXFLAGS), ..., "-o", outf)
end
--link objects together (mid-stage)
--syntax: output path, extra args (as a table), list of input objects (vararg)
function cc:partialld(outf, args, ...)
local inputs = {...}
return runner:run(self.CC, "-c", table:unpack(self.CFLAGS), ..., "-o", outf)
end
--link a finished output
--inputs: input file (multiple inputs possible as table), options table, output
--options:
--type: "executable", "shared" (default: executable)
--static: true, false (default: false)
--extraargs: string array (default: {})
function cc:ld(input, output, options)
--select default options if missing
options = options or {}
options.type = options.type or "executable"
options.static = options.static or false
options.extraargs = options.extraargs or {}
if options.type == "shared" then
output = output or path:stripext(file) .. ".so"
else
output = output or path:stripext(file) .. ".o"
end
--check validity
if options.type ~= "executable" and options.type ~= "shared" then
error("bad cc type")
end
--check types
if type(static) ~= "boolean" then
error("static is not boolean")
end
if type(extraargs) ~= "table" then
error("extraargs is not table")
end
--generate args
local args = {}
if options.type == "shared" then
args[#args + 1] = "-shared"
end
if options.static then
args[#args + 1] = "-static"
end
--run thing
return runner:run(self.CC, table:unpack(args), table:unpack(self.CFLAGS), table:unpack(options.extraargs), ..., "-o", output)
end

return cc
9 changes: 9 additions & 0 deletions lbuild/path.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--work in progress

local path = {}

function path:stripext(p)
return string.gsub(a, "%.+%a", "")
end

return path
16 changes: 16 additions & 0 deletions lbuild/promise.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
local p = {}

p.__index = p

function p:prom(success, fail)
if fail == nil then
fail = error
end
self.f(success, fail)
end

local function promise(func)
return setmetatable({f = func}, p)
end

return promise
166 changes: 166 additions & 0 deletions lbuild/ruletable.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
local path = require("lbuild.path")
local promise = require("lbuild.promise")
local runner = require("lbuild.runner")
local ffi = require("ffi")

ffi.cdef[[
int lbuild_util_isNewer(char *a, char *b);
char *strerror(int errnum);
bool exists(const char path[]);
]]

local lbuild_util = ffi.load("liblbuild_util.so")

local ruletbl = {}
local ruletable = ruletbl
ruletable.gen = {}
ruletable.rules = {}

--add a rule
--rule: table
--rule.deps: a list or a function which returns a promise to a list
--rule.run: a function which returns a promise
function ruletbl:add(rule)
self.rules[rule.name] = rule
end

--add a rule which executes a command
--name is the name of the rule
--deps are the dependencies of the command
--cmd is the command to run
--can be a table (argv) or a string
--if a string, is translated to sh -c cmd
function ruletbl:addcmd(name, deps, cmd)
local rule = {name = name}
function rule:deps()
return deps
end
if type(cmd) == "string" then
cmd = {"sh", "-c", cmd}
end
function rule:run()
return runner:run(unpack(cmd))
end
self:add(rule)
end

--add a rule generator
--genfunc is a func which takes one argument (a name) and returns a rule
--if the name does not match the generator pattern, genfunc should return nil
--unmatched names will be passed to the next generator
function ruletbl:addgenerator(genfunc)
self.gen[#self.gen + 1] = genfunc
end

--returns whether file a is newer than b
function ruletbl:cmptime(a, b)
local res = lbuild_util:lbuild_util_isNewer(a, b)
if res == 1 then
return true
else
return false
end
end

--run a dependency (as a promise)
--value of promise is a boolean indicating whether the dep is newer or not
function ruletbl:rundep(r, dep)
local rt = self
return promise(function(success, failure)
rt:run(dep):prom(function()
success(rt:cmptime(dep, r))
end, failure)
end)
end

--run a rule (returns a promise)
function ruletbl:run(name)
local rt = self
--get rule
local rule = self.rules[name]
if rule == nil then --rule not found - try to generate it
local n = #self.gen
while rule == nil and n ~= 0 do
rule = self.gen[n](name)
n = n - 1
end
if rule == nil then --it wasn't found and could not be generated
error("Rule " .. name .. " does not exist")
end
--add new rule to lookup table
self.rules[name] = rule
end
return promise(function(success)
if rule.state ~= nil then
--if rule is already running (or done) dont start it again
if rule.state == "done" then
success()
else
if rule.cb ~= nil then
rule.cb = {}
end
rule.cb[#rule.cb + 1] = success
end
else --otherwise start it
--get dependencies
rule.state = "deplookup"
rule.cb = {success}
local depcb = function(deps)
rule.state = "deps"
local runcb = function()
for _, cb in ipairs(rule.cb) do
cb()
end
end
local n = #deps + 1
local ischng = false
local startcb = function(chng)
if chng then
rule.state = "done"
runcb()
else
rule:run():prom(runcb)
end
end
local depfcb = function(chng)
n = n - 1
ischng = ischng or chng
if n == 0 then
startcb(ischng)
end
end
for _, dep in ipairs(deps) do
rt:run(dep):prom(depfcb)
end
depfcb(false)
end
local dps = rule:deps()
if dps == nil then
depcb({})
elseif dps.prom ~= nil then
dps:prom(depcb)
else
depcb(dps)
end
end
end)
end

--add generator for rules for files that already exist
ruletable:addgenerator(function(name)
if lbuild_util.exists(name) then
local rule = {}
function rule:deps()
return nil
end
function rule:run()
return promise(function(s, f)
s()
end)
end
return rule
end
return nil
end)

return ruletable
Loading

0 comments on commit bdb3dda

Please sign in to comment.