commit f4e3930

Emilia Smólska  ·  2026-08-08 10:45:20 +0000 UTC
parent fce7485
implement deps
6 files changed,  +60, -28
A lib.c
A lib.h
M main.c
+2, -0
1@@ -0,0 +1,2 @@
2+obj/*
3+build.ninja
+3, -1
1@@ -1,3 +1,5 @@
2 local neu = require("neutrino")(arg)
3 
4-neu.bin("main", { "main.c" })
5+local lib = neu.lib("lib", { "lib.c" })
6+
7+neu.bin("main", { "main.c" }, { deps = { lib } })
A lib.c
+6, -0
1@@ -0,0 +1,6 @@
2+#include <stdio.h>
3+#include "lib.h"
4+
5+void meow(void) {
6+   printf("meow\n");
7+}
A lib.h
+6, -0
1@@ -0,0 +1,6 @@
2+#ifndef __lib_h
3+#define __lib_h
4+
5+extern void meow(void);
6+
7+#endif // __lib_h
M main.c
+2, -2
1@@ -1,6 +1,6 @@
2-#include <stdio.h>
3+#include "lib.h"
4 
5 int main(void) {
6-   printf("hello, shrub\n");
7+   meow();
8    return 0;
9 }
+41, -25
  1@@ -3,9 +3,7 @@
  2 local neu = {}
  3 
  4 local function check(s)
  5-   if not s:match("^[%u_]+$") then
  6-      error(("name '%s' invalid"):format(s))
  7-   end
  8+   assert(s:match("^[%u_]+$"), ("name '%s' invalid"):format(s))
  9 end
 10 
 11 local function memq(elt, tbl)
 12@@ -16,9 +14,7 @@ end
 13 local bools = {}
 14 function neu.bool(name)
 15    check(name)
 16-   if bools[name] then
 17-      error(("option '%s' redeclared"):format(name))
 18-   end
 19+   assert(not bools[name], ("option '%s' redeclared"):format(name))
 20    bools[name] = #(os.getenv(name) or "") > 0
 21    return bools[name]
 22 end
 23@@ -26,24 +22,21 @@ end
 24 local enums = {}
 25 function neu.enum(name, set)
 26    check(name)
 27-   if enums[name] then
 28-      error(("option '%s' redeclared"):format(name))
 29-   end
 30+   assert(not enums[name], ("option '%s' redeclared"):format(name))
 31    local val = os.getenv(name)
 32    if not val then enums[name] = set[1]
 33-   elseif not memq(val, set) then
 34-      local s = table.concat(set, "', '")
 35-      error(("value '%s' not in { '%s' }"):format(val, s))
 36-   else enums[name] = val end
 37+   else
 38+      assert(memq(val, set), ("value '%s' not in { '%s' }")
 39+         :format(val, table.concat(set, " ")))
 40+      enums[name] = val
 41+   end
 42    return enums[name]
 43 end
 44 
 45 local strs = {}
 46 function neu.str(name, dfl)
 47    check(name)
 48-   if strs[name] then
 49-      error(("option '%s' redeclared"):format(name))
 50-   end
 51+   assert(not strs[name], ("option '%s' redeclared"):format(name))
 52    strs[name] = os.getenv(name) or dfl
 53    return strs[name]
 54 end
 55@@ -66,24 +59,32 @@ local function writerule(name, tbl)
 56    for k, v in pairs(tbl) do writevar(" " .. k, v, "\n") end
 57 end
 58 
 59-local function writebuild(tgt, rule, prereq, impl)
 60+local function writebuild(tgt, rule, prereq, ideps)
 61    if type(prereq) == "table" then
 62       prereq = table.concat(prereq, " ")
 63    end
 64-   if type(impl) == "table" then
 65-      impl = table.concat(impl, " ")
 66+   if type(ideps) == "table" then
 67+      ideps = table.concat(ideps, " ")
 68    end
 69-   impl = impl and "|" .. impl or ""
 70-   bn:write("build ", tgt, ":", rule, " ", prereq, impl, "\n")
 71+   ideps = ideps and "|" .. ideps or ""
 72+   bn:write("build ", tgt, ":", rule, " ", prereq, ideps, "\n")
 73 end
 74 
 75-local function aggr(name, rule, srcs, opts)
 76+local depmeta = {}
 77+local function blessdep(tbl) return setmetatable(tbl, depmeta) end
 78+local function isdep(tbl) return getmetatable(tbl) == depmeta end
 79+
 80+local function aggr(name, rule, srcs, opts, ideps, vars)
 81    opts = opts or {}
 82    opts.std = opts.std or "c17"
 83    local stds = { c17 = true, c23 = true }
 84    local objs = {}
 85+   local lf = {}
 86    for i, x in ipairs(srcs) do objs[i] = src2obj(x) end
 87-   writebuild("obj/" .. name, rule, objs)
 88+   writebuild("obj/" .. name, rule, objs, ideps)
 89+   if vars then
 90+      for k, v in pairs(vars) do writevar(" " .. k, v) end
 91+   end
 92    for i = 1, #srcs do
 93       writebuild(objs[i], "cc", srcs[i])
 94       local cf = {}
 95@@ -98,10 +99,25 @@ local function aggr(name, rule, srcs, opts)
 96    end
 97 end 
 98 
 99-function neu.bin(bin, srcs, opts) aggr(bin, "ld", srcs, opts) end
100+function neu.bin(bin, srcs, opts)
101+   local ideps = {}
102+   local lf = {}
103+   if opts.deps then
104+      for _, d in ipairs(opts.deps) do
105+         assert(isdep(d), "deps contain invalid object")
106+         if d.file then table.insert(ideps, "obj/" .. d.file) end
107+         table.insert(lf, d.ldflags)
108+      end
109+   end
110+   aggr(bin, "ld", srcs, opts, ideps, {
111+      _ldflags = table.concat(lf, " "),
112+   })
113+end
114 
115 function neu.lib(lib, srcs, opts)
116-   aggr("lib" .. lib .. ".a", "ar", srcs, opts)
117+   local fn = table.concat({ "lib", lib, ".a" })
118+   aggr(fn, "ar", srcs, opts)
119+   return blessdep({ file = fn, ldflags = "-Lobj -l" .. lib })
120 end
121 
122 if not package.searchpath then