local function objdir(e) return concatpath("$(OBJDIR)", e.cwd, e.name) end definerule("normalrule", { ins = { type="targets" }, deps = { type="targets", default={} }, outleaves = { type="strings" }, label = { type="string", optional=true }, objdir = { type="string", optional=true }, commands = { type="strings" }, }, function (e) local dir = e.objdir or objdir(e) local realouts = {} for _, v in pairs(e.outleaves) do realouts[#realouts+1] = concatpath(dir, v) end local vars = inherit(e.vars, { dir = dir }) local result = simplerule { name = e.name, ins = e.ins, deps = e.deps, outs = realouts, label = e.label, commands = e.commands, vars = vars, } result.dir = dir return result end ) definerule("cfile", { srcs = { type="targets" }, deps = { type="targets", default={} }, suffix = { type="string", default=".o" }, commands = { type="strings", default={ "$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags}" }, } }, function (e) local hdrpaths = {} for _, t in pairs(e.deps) do if t.dir then hdrpaths[#hdrpaths+1] = "-I"..t.dir end end hdrpaths = uniquify(hdrpaths) local outleaf = basename(e.name)..e.suffix return normalrule { name = e.name, cwd = e.cwd, ins = e.srcs, deps = e.deps, outleaves = {outleaf}, label = e.label, commands = e.commands, vars = { hdrpaths = hdrpaths, } } end ) definerule("cppfile", { srcs = { type="targets" }, deps = { type="targets", default={} }, outleaf = { type="string" }, commands = { type="strings", default={ "$(CC) -E -P -o %{outs[1]} %{hdrpaths} %{cflags} -x c %{ins}" } }, }, function (e) if (#e.srcs ~= 1) then error("you must have exactly one input file") end local hdrpaths = {} for _, t in pairs(e.deps) do if t.dir then hdrpaths[#hdrpaths+1] = "-I"..t.dir end end hdrpaths = uniquify(hdrpaths) return normalrule { name = e.name, cwd = e.cwd, ins = e.srcs, deps = e.deps, outleaves = {e.outleaf}, label = e.label, commands = e.commands, vars = { hdrpaths = hdrpaths, } } end ) 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 fpairs(e.srcs) do local localf = basename(f) outleaves[#outleaves+1] = localf commands[#commands+1] = "cp "..f.." %{dir}/"..localf end return normalrule { name = e.name, cwd = e.cwd, ins = e.srcs, outleaves = outleaves, label = e.label, commands = commands } end ) definerule("clibrary", { srcs = { type="targets", default={} }, hdrs = { type="targets", default={} }, deps = { type="targets", default={} }, _cfile = { type="object", default=cfile }, suffix = { type="string", default=".o" }, commands = { type="strings", default={ "rm -f %{outs[1]}", "$(AR) cqs %{outs[1]} %{ins}", }, } }, function (e) local ins = {} for _, src in fpairs(e.srcs) do local n = basename(src):gsub("%.%w*$", "") ins[#ins+1] = e._cfile { name = e.name.."/"..n, cwd = e.cwd, srcs = {src}, deps = e.deps, suffix = e.suffix, vars = { ["+cflags"] = { "-I"..e.cwd, }, }, } end local commands = {} local outleaves = {} if (#e.srcs > 0) then for _, s in ipairs(e.commands) do commands[#commands+1] = s end outleaves[#outleaves+1] = e.name..".a" end local hdrsin = {} for dest, src in pairs(e.hdrs) do if (type(dest) == "number") then for _, f in ipairs(filenamesof(src)) do hdrsin[#hdrsin+1] = f outleaves[#outleaves+1] = basename(f) commands[#commands+1] = "cp "..asstring(f).." %{dir}" end else local fs = filenamesof(src) if (#fs ~= 1) then error(string.format("keyed header '%s' can only be a single file", dest)) end local f = fs[1] hdrsin[#hdrsin+1] = f outleaves[#outleaves+1] = dest commands[#commands+1] = "cp "..asstring(f).." %{dir}/"..dest end end return normalrule { name = e.name, cwd = e.cwd, ins = ins, deps = {hdrsin, e.deps}, outleaves = outleaves, label = e.label, commands = commands, } end ) definerule("cprogram", { srcs = { type="targets", default={} }, deps = { type="targets", default={} }, _clibrary = { type="object", default=clibrary }, commands = { type="strings", default={ "$(CC) $(LDFLAGS) -o %{outs[1]} %{ins} %{ins}" }, } }, function (e) local libs = matching(filenamesof(e.deps), "%.a$") local srcs = {} if (#e.srcs > 0) then for _, f in pairs( matching( filenamesof( e._clibrary { name = e.name .. "/main", cwd = e.cwd, srcs = e.srcs, deps = e.deps, } ), "%.a$" ) ) do srcs[#srcs+1] = f end end return normalrule { name = e.name, cwd = e.cwd, deps = e.deps, ins = { srcs, libs }, outleaves = { e.name }, commands = e.commands, } end )