master
ninqu.rules
1; genconfig.sh config produces four files from build.cfg:
2; config.set (read by ninqu), config.kv (read by mkman),
3; nofork_list.h (included by wexec.c), and features.h (-included
4; into every compile). each gets its own rule so ninqu can find a
5; producer for any of them
6;
7(rule CONFIG_SET
8 (out "scripts/mk/config.set")
9 (dep "build.cfg" "scripts/genconfig.sh")
10 (exec sh scripts/genconfig.sh config))
11
12(rule NOFORK_LIST_H
13 (out "shared/libutil/nofork_list.h")
14 (dep "build.cfg" "scripts/genconfig.sh")
15 (exec sh scripts/genconfig.sh config))
16
17(rule FEATURES_H
18 (out "scripts/mk/features.h")
19 (dep "build.cfg" "scripts/genconfig.sh")
20 (exec sh scripts/genconfig.sh config))
21
22(set-file "scripts/mk/config.set")
23
24; static libraries: compile every .c in each lib dir then AR
25;
26(rule LIBUTF_OBJ
27 (glob "shared/libutf/*.c")
28 (dep $(MATCH))
29 (out "$(STEM).o")
30 (exec $(CC) $(CPPFLAGS) -Ishared/libutf $(CFLAGS) -c -o $(OUT) $(MATCH)))
31
32(rule LIBUTF
33 (dep LIBUTF_OBJ)
34 (out "shared/libutf/libutf.a")
35 (description "utf-8 and rune handling, linked into every aruu tool")
36 (feature core-lib)
37 (exec $(AR) $(ARFLAGS) $(OUT) $(IN)))
38
39(rule LIBUTIL_OBJ
40 (glob "shared/libutil/*.c")
41 (dep $(MATCH))
42 (after NOFORK_LIST_H FEATURES_H)
43 (out "$(STEM).o")
44 (exec $(CC) $(CPPFLAGS_LIBUTIL) -Ishared/libutil $(CFLAGS) -c -o $(OUT) $(MATCH)))
45
46(rule LIBUTIL
47 (dep LIBUTIL_OBJ)
48 (out "shared/libutil/libutil.a")
49 (description "allocation, error reporting, and string helpers shared by every tool")
50 (feature core-lib)
51 (exec $(AR) $(ARFLAGS) $(OUT) $(IN)))
52
53(rule LIBREDLINE_OBJ
54 (glob "shared/libredline/*.c")
55 (dep $(MATCH))
56 (out "$(STEM).o")
57 (exec $(CC) $(CPPFLAGS) -Ishared/libredline $(CFLAGS) -c -o $(OUT) $(MATCH)))
58
59(rule LIBREDLINE
60 (dep LIBREDLINE_OBJ)
61 (out "shared/libredline/libredline.a")
62 (description "line editing used by sh and any other interactive tool")
63 (feature core-lib)
64 (exec $(AR) $(ARFLAGS) $(OUT) $(IN)))
65
66(group lib LIBUTF LIBUTIL LIBREDLINE)
67
68; perfile: every *.c directly inside one of these dirs becomes its
69; own binary of the same name, individually gated by
70; build_<category>_<ident> (lowercase, hyphens and dots turned to
71; underscores, see the $(IDENT) comment above BOX_OBJ below for why)
72; (skip) excludes files that belong to a multi-file tool below instead
73;
74(map EXTRA_LIBS
75 (diff "-lm")
76 (wget $(LDLIBS_TLS)))
77
78; Every .c file in a category builds into its own binary. (PERFILE)
79; Only EXTRA_AFTER differs cuz POSIX waits for GETCONF_H, the rest pass "".
80; cmd/posix/bc.c overrides this with its own yacc-based rule, so no need for
81; PERFILE to have that as a special case
82;
83(template PERFILE (NAME CATEGORY DESC EXTRA_AFTER)
84 (rule $(NAME)
85 (glob "cmd/$(CATEGORY)/*.c")
86 (gate build_$(CATEGORY)_$(IDENT))
87 (dep $(MATCH) LIBUTIL LIBUTF)
88 (after $(EXTRA_AFTER))
89 (out $(STEM))
90 (description $(DESC))
91 (feature perfile)
92 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS) $(EXTRA_LIBS:$(BASESTEM)))))
93
94(use PERFILE POSIX_BIN posix "one POSIX2024 utility per source file under cmd/posix" GETCONF_H)
95(use PERFILE LINUX_BIN linux "Linux-only utility, one source file per binary under cmd/linux" "")
96(use PERFILE NET_BIN net "networking utility, one source file per binary under cmd/net" "")
97(use PERFILE XSI_BIN xsi "XSI-specified utility, one source file per binary under cmd/xsi" "")
98(use PERFILE PSEUDO_BIN pseudo "common but undefined utility, one source file per binary under cmd/pseudo" "")
99(use PERFILE EXTRA_BIN extra "extra utility outside POSIX/XSI scope, one source file per binary under cmd/extra" "")
100
101(group posix lib POSIX_BIN POSIX_BC POSIX_AWK POSIX_SH POSIX_MAKE)
102(group linux lib LINUX_BIN)
103(group net lib NET_BIN)
104(group xsi lib XSI_BIN)
105(group pseudo lib PSEUDO_BIN)
106(group extra lib EXTRA_BIN EXTRA_YAP)
107
108; codegen: generate sources consumed by the build rules below. Ungated
109; ones always run. conditional ones use (req) so they only run when
110; their inputs exists in this checkout
111;
112(rule GETCONF_H
113 (gate build_posix_getconf)
114 (out "cmd/posix/getconf.h")
115 (dep "scripts/getconf.sh")
116 (exec sh scripts/genconfig.sh getconf))
117
118(rule POSIX_BC_C
119 (gate build_posix_bc)
120 (req "cmd/posix/bc.y")
121 (out "cmd/posix/bc.c")
122 (dep "cmd/posix/bc.y")
123 (exec sh scripts/genconfig.sh bc))
124
125(rule POSIX_AWK_C
126 (gate build_posix_awk)
127 (out "cmd/posix/awk/awkgram.tab.c")
128 (dep "cmd/posix/awk/awkgram.y")
129 (exec sh scripts/genconfig.sh awk))
130
131(rule POSIX_SH_C
132 (gate build_posix_sh)
133 (out "cmd/posix/sh/syntax.c")
134 (dep "cmd/posix/sh/mksyntax.c" "cmd/posix/sh/mknodes.c" "cmd/posix/sh/mkbuiltins" "cmd/posix/sh/mktokens")
135 (exec sh scripts/genconfig.sh sh))
136
137(rule DEVCONF
138 (req "cmd/dev/configure")
139 (out "cmd/dev/config.h")
140 (dep "cmd/dev/configure")
141 (phony)
142 (exec sh cmd/dev/configure))
143
144(group codegen GETCONF_H POSIX_BC_C POSIX_AWK_C POSIX_SH_C DEVCONF)
145
146; multi: one binary from all .c files in one or more dirs (minus skip).
147; codegen must run first so generated sources are present before these
148; globs collect them
149;
150(rule POSIX_BC_OBJ
151 (glob "cmd/posix/bc.c")
152 (gate build_posix_bc)
153 (dep $(MATCH))
154 (after POSIX_BC_C)
155 (out "$(STEM).o")
156 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
157
158(rule POSIX_BC
159 (gate build_posix_bc)
160 (member posix bc)
161 (dep POSIX_BC_OBJ LIBUTIL LIBUTF)
162 (out "cmd/posix/bc")
163 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS) -lm))
164
165(rule POSIX_AWK_OBJ
166 (glob "cmd/posix/awk/*.c")
167 (gate build_posix_awk)
168 (skip "maketab.c")
169 (dep $(MATCH))
170 (after POSIX_AWK_C)
171 (out "$(STEM).o")
172 (exec $(CC) $(CPPFLAGS) -Icmd/posix/awk $(CFLAGS) -c -o $(OUT) $(MATCH)))
173
174(rule POSIX_AWK
175 (gate build_posix_awk)
176 (member posix awk)
177 (dep POSIX_AWK_OBJ LIBUTIL LIBUTF)
178 (out "cmd/posix/awk/awk")
179 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS) -lm))
180
181(rule POSIX_SH_OBJ
182 (glob "cmd/posix/sh/*.c")
183 (gate build_posix_sh)
184 (skip "mknodes.c" "mksyntax.c")
185 (dep $(MATCH))
186 (after POSIX_SH_C)
187 (out "$(STEM).o")
188 (exec $(CC) $(CPPFLAGS) -DSHELL -Icmd/posix/sh $(CFLAGS) -c -o $(OUT) $(MATCH)))
189
190(rule POSIX_SH
191 (gate build_posix_sh)
192 (member posix sh)
193 (dep POSIX_SH_OBJ LIBUTIL LIBUTF LIBREDLINE)
194 (out "cmd/posix/sh/sh")
195 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
196
197(rule POSIX_MAKE_OBJ
198 (glob "cmd/posix/make/*.c")
199 (gate build_posix_make)
200 (dep $(MATCH))
201 (out "$(STEM).o")
202 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
203
204(rule POSIX_MAKE
205 (gate build_posix_make)
206 (member posix make)
207 (dep POSIX_MAKE_OBJ LIBUTIL LIBUTF)
208 (out "cmd/posix/make/make")
209 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
210
211(rule EXTRA_YAP_OBJ
212 (glob "cmd/extra/yap/*.c")
213 (gate build_extra_yap)
214 (dep $(MATCH))
215 (out "$(STEM).o")
216 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
217
218(rule EXTRA_YAP
219 (gate build_extra_yap)
220 (member extra yap)
221 (dep EXTRA_YAP_OBJ LIBUTIL LIBUTF)
222 (out "cmd/extra/yap/yap")
223 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS) -ltinfo))
224
225; (member GROUP ALIAS) gives a rule a qualified user-facing name
226; (e.g. posix/bc) while keeping its internal name (POSIX_BC) for deps,
227; gates, and other references
228;
229
230; dev: the aruu toolchain. ar/as/ld are standalone and cc
231; shares one object pool linked into three frontends
232;
233(rule AR_OBJ
234 (glob "cmd/dev/ar/*.c")
235 (gate build_dev_ar)
236 (skip "tinyar.c")
237 (dep $(MATCH))
238 (out "$(STEM).o")
239 (exec $(CC) $(CPPFLAGS) -Icmd/dev/ar $(CFLAGS) -c -o $(OUT) $(MATCH)))
240
241(rule AR
242 (gate build_dev_ar)
243 (dep AR_OBJ LIBUTIL LIBUTF)
244 (out "cmd/dev/ar/ar")
245 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
246
247(rule XCUTIL_OBJ
248 (glob "cmd/dev/xcutil/*.c")
249 (gate build_dev_cc)
250 (dep $(MATCH))
251 (out "$(STEM).o")
252 (exec $(CC) $(CPPFLAGS) -Icmd/dev/xcutil $(CFLAGS) -c -o $(OUT) $(MATCH)))
253
254(rule AS_OBJ
255 (glob "cmd/dev/as/*.c" "cmd/dev/as/arch/x64/*.c")
256 (gate build_dev_cc)
257 (dep $(MATCH))
258 (out "$(STEM).o")
259 (exec $(CC) $(CPPFLAGS) -Icmd/dev/xcutil -Icmd/dev/as -Icmd/dev/as/arch/x64 -Ishared $(CFLAGS) -c -o $(OUT) $(MATCH)))
260
261(rule AS
262 (gate build_dev_cc)
263 (dep AS_OBJ LIBUTIL LIBUTF)
264 (after XCUTIL_OBJ)
265 (out "cmd/dev/as/as")
266 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
267
268(rule LD_OBJ
269 (glob "cmd/dev/ld/*.c")
270 (gate build_dev_ld)
271 (dep $(MATCH))
272 (out "$(STEM).o")
273 (exec $(CC) $(CPPFLAGS) -Icmd/dev/xcutil -Icmd/dev/ld $(CFLAGS) -c -o $(OUT) $(MATCH)))
274
275(rule LD
276 (gate build_dev_ld)
277 (dep LD_OBJ LIBUTIL LIBUTF)
278 (after XCUTIL_OBJ)
279 (out "cmd/dev/ld/ld")
280 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
281
282; CCPOOL_OBJ globs the whole directory. The entry points below use
283; literal globs, so the override excludes them automatically
284(rule CCPOOL_OBJ
285 (glob "cmd/dev/cc/*.c")
286 (gate build_dev_cc)
287 (dep $(MATCH))
288 (out "$(STEM).o")
289 (exec $(CC) $(CPPFLAGS) -Icmd/dev/cc $(CFLAGS) -c -o $(OUT) $(MATCH)))
290
291(rule CC1_OBJ
292 (glob "cmd/dev/cc/cc1.c")
293 (gate build_dev_cc)
294 (dep $(MATCH))
295 (out "$(STEM).o")
296 (exec $(CC) $(CPPFLAGS) -Icmd/dev/cc $(CFLAGS) -c -o $(OUT) $(MATCH)))
297
298(rule CC1
299 (gate build_dev_cc)
300 (dep CC1_OBJ CCPOOL_OBJ LIBUTIL LIBUTF)
301 (out "cmd/dev/cc/cc1")
302 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
303
304(rule CPP_OBJ
305 (glob "cmd/dev/cc/cpp.c")
306 (gate build_dev_cc)
307 (dep $(MATCH))
308 (out "$(STEM).o")
309 (exec $(CC) $(CPPFLAGS) -Icmd/dev/cc $(CFLAGS) -c -o $(OUT) $(MATCH)))
310
311(rule CPP
312 (gate build_dev_cc)
313 (dep CPP_OBJ CCPOOL_OBJ LIBUTIL LIBUTF)
314 (out "cmd/dev/cc/cpp")
315 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
316
317(rule CCDRV_OBJ
318 (glob "cmd/dev/cc/driver.c" "cmd/dev/cc/util.c")
319 (gate build_dev_cc)
320 (dep $(MATCH))
321 (out "$(STEM).o")
322 (exec $(CC) $(CPPFLAGS) -Icmd/dev/cc $(CFLAGS) -c -o $(OUT) $(MATCH)))
323
324(rule CCDRV
325 (gate build_dev_cc)
326 (dep CCDRV_OBJ LIBUTIL LIBUTF)
327 (out "cmd/dev/cc/cc")
328 (exec $(CC) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS)))
329
330; Like BOX_OBJ: rename main and hide other globals so ninqu can link
331; into aruu-box. It is still not reentrant, so it stays out of
332; NOFORK_LIST
333;
334(rule NINQU_BOX_OBJ
335 (glob "cmd/dev/ninqu/*.c")
336 (gate build_dev_ninqu)
337 (dep $(MATCH))
338 (after LIBUTIL LIBUTF LIBREDLINE NOFORK_LIST_H FEATURES_H GETCONF_H)
339 (out ".box/cmd/dev/$(BASESTEM).o")
340 (description "ninqu as a box builtin, main renamed for the box dispatch table")
341 (shell "$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH) && sym=`echo $(BASESTEM) | tr '.-' '__'`_main && $(OBJCOPY) --redefine-sym main=$sym $(OUT) && $(OBJCOPY) --keep-global-symbol=$sym $(OUT)")
342 (group box))
343
344(group dev lib DEVCONF AR AS LD CC1 CPP CCDRV)
345
346; man pages: build mdoc and text pages from ?man-marked sources
347;
348(rule MKMAN
349 (dir "scripts/mkman")
350 (dep "glob:scripts/mkman/*.go")
351 (out "scripts/mkman/mkman")
352 (exec go build -o mkman .))
353
354(rule MAN_MDOC
355 (glob "cmd/**/*.c")
356 (mark "?man")
357 (dep (after MKMAN))
358 (out "man/man$(SEC_OF:$(DIR))/$(BASESTEM).$(SEC_OF:$(DIR))")
359 (exec scripts/mkman/mkman -fmt mdoc -config scripts/mk/config.kv $(MATCH))
360 (redirect))
361
362(rule MAN_TXT
363 (glob "cmd/**/*.c")
364 (mark "?man")
365 (dep (after MKMAN))
366 (out "man/man$(SEC_OF:$(DIR))/$(BASESTEM).$(SEC_OF:$(DIR)).txt")
367 (exec scripts/mkman/mkman -fmt txt -config scripts/mk/config.kv $(MATCH))
368 (redirect))
369
370(map SEC_OF
371 (cmd/posix 1)
372 (cmd/linux 8)
373 (cmd/net 8)
374 (cmd/xsi 1)
375 (cmd/pseudo 1)
376 (cmd/extra 1)
377 (cmd/dev 1))
378
379(group man MAN_MDOC MAN_TXT)
380
381(rule CLEAN
382 (phony)
383 (shell "
384 printf ' CLEAN object files\n'
385 find shared cmd -name '*.o' -exec rm -f {} +
386
387 printf ' CLEAN static libraries\n'
388 find shared -name '*.a' -exec rm -f {} +
389
390 printf ' CLEAN compiled binaries\n'
391 find cmd -type f ! -name '*.*' -perm -100 -exec rm -f {} +
392
393 sh scripts/genconfig.sh clean
394 rm -f scripts/mk/config.mk scripts/mk/config.kv scripts/mk/rules.mk shared/libutil/nofork_list.h
395
396 printf ' CLEAN build tools\n'
397 rm -f scripts/mkman/mkman
398
399 printf ' CLEAN dev artifacts\n'
400 rm -f cmd/dev/cc/cc1 cmd/dev/cc/cpp cmd/dev/as/as cmd/dev/ld/ld cmd/dev/ar/ar
401 rm -f shared/libaruuelf.so
402 rm -f cmd/dev/config.h cmd/dev/cc/config.h cmd/dev/version.h
403
404 printf ' CLEAN misc\n'
405 rm -rf man/man1 man/man8
406 rm -rf aruu-box .box
407 rm -rf .ninja_log .ninja_deps
408
409 printf ' CLEAN done\n'
410 "))
411
412(group clean CLEAN)
413
414; install every built executable and generated man page
415(rule INSTALL
416 (phony)
417 (after ALL_BINS MAN_MDOC MAN_TXT)
418 (shell "
419 mkdir -p \"$(PREFIX)/bin\" \"$(MANPREFIX)/man1\" \"$(MANPREFIX)/man8\"
420
421 find cmd -type f ! -name '*.*' -perm -100 | while read -r bin; do
422 name=${bin##*/}
423 printf ' INSTALL %s/bin/%s\n' '$(PREFIX)' \"$name\"
424 cp \"$bin\" \"$(PREFIX)/bin/$name\"
425 chmod 755 \"$(PREFIX)/bin/$name\"
426 done
427
428 find man/man1 man/man8 -type f -name '*.[18]' 2>/dev/null | while read -r f; do
429 sec=${f%/*}; sec=${sec##*/}
430 name=${f##*/}
431 cp \"$f\" \"$(MANPREFIX)/$sec/$name\"
432 done
433 "))
434
435(group install INSTALL)
436
437; remove exactly what install would have copied
438(rule REMOVE
439 (phony)
440 (shell "
441 find cmd -type f ! -name '*.*' -perm -100 | while read -r bin; do
442 name=${bin##*/}
443 printf ' REMOVE %s/bin/%s\n' '$(PREFIX)' \"$name\"
444 rm -f \"$(PREFIX)/bin/$name\"
445 done
446
447 find man/man1 man/man8 -type f -name '*.[18]' 2>/dev/null | while read -r f; do
448 sec=${f%/*}; sec=${sec##*/}
449 name=${f##*/}
450 printf ' REMOVE %s/%s/%s\n' '$(MANPREFIX)' \"$sec\" \"$name\"
451 rm -f \"$(MANPREFIX)/$sec/$name\"
452 done
453 "))
454
455(group remove REMOVE)
456(group uninstall REMOVE)
457
458(rule FMT
459 (phony)
460 (shell "
461 printf ' FMT cmd and shared (skipping dir tools)\n'
462 find cmd shared -type f \( -name '*.c' -o -name '*.h' \) \
463 ! -path 'cmd/posix/awk/*' \
464 ! -path 'cmd/posix/sh/*' \
465 ! -path 'cmd/posix/make/*' \
466 ! -path 'cmd/extra/yap/*' \
467 ! -path 'cmd/posix/bc.c' \
468 -print | xargs -r clang-format -i
469 "))
470
471(rule FMT_ALL
472 (phony)
473 (shell "
474 printf ' FMT cmd and shared (including dir tools)\n'
475 find cmd shared -type f \( -name '*.c' -o -name '*.h' \) -print \
476 | xargs -r clang-format -i
477 "))
478
479(group fmt FMT)
480(group fmt-all FMT_ALL)
481
482; box: one executable containing every enabled tool, dispatched through
483; a table. a single-file tool just gets its main renamed by BOX_OBJ.
484; multi-file tools (POSIX_BC, POSIX_AWK, POSIX_SH, POSIX_MAKE, EXTRA_YAP)
485; go through a partial link (ld -r) first, merging their objects into
486; one before main gets renamed and helper symbols hidden. replaces
487; scripts/mkbox
488;
489; object files live under .box/, mirroring the cmd/ layout
490;
491; Ninqu determines which tools enter the box using the gate on BOX_OBJ.
492; BOX_DISPATCH reads the object paths passed on argv rather than consulting
493; build.cfg or config.set directly
494;
495
496; CATEGORY_OF maps a directory path to its category name, matching the toggles
497; in build.cfg. Since BOX_OBJ globs multiple directories, its gate evaluates the
498; category dynamically based on the match directory
499;
500; Gates evaluate $(IDENT) instead of $(BASESTEM) because toggle names must be
501; valid shell variables. Genconfig.sh replaces hyphens and periods with
502; underscores, and $(IDENT) applies the same normalization so they match
503;
504(map CATEGORY_OF
505 (cmd/posix posix)
506 (cmd/linux linux)
507 (cmd/net net)
508 (cmd/pseudo pseudo)
509 (cmd/xsi xsi)
510 (cmd/extra extra))
511
512; Tool basestems match their C symbols using a shell transform (tr '.-' '__'
513; and appending _main) in both the objcopy step and in genbox.sh. A static map
514; is unnecessary because no current tools require custom overrides, and
515; genbox.sh only receives paths via argv
516;
517
518; the match directory picks the gate and output path, so one rule covers
519; all six categories. bc.c inside cmd/posix is excluded automatically by
520; the literal-glob override mechanism
521;
522(rule BOX_OBJ
523 (glob "cmd/posix/*.c" "cmd/linux/*.c" "cmd/net/*.c" "cmd/pseudo/*.c"
524 "cmd/xsi/*.c" "cmd/extra/*.c")
525 (gate build_$(CATEGORY_OF:$(DIR))_$(IDENT))
526 (dep $(MATCH))
527 (after LIBUTIL LIBUTF LIBREDLINE NOFORK_LIST_H FEATURES_H GETCONF_H)
528 (out ".box/$(DIR)/$(BASESTEM).o")
529 (description "one object per enabled tool, main renamed for the box dispatch table")
530 (shell "$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH) && sym=`echo $(BASESTEM) | tr '.-' '__'`_main && $(OBJCOPY) --redefine-sym main=$sym $(OUT) && $(OBJCOPY) --keep-global-symbol=$sym $(OUT)")
531 (group box))
532
533; POSIX_BC, POSIX_AWK, POSIX_SH, POSIX_MAKE, and EXTRA_YAP cant go through
534; the single-file objcopy step, their global helper symbols would collide
535; once linked into one binary. a partial link (ld -r) resolves those
536; internal references first, then main gets renamed and the rest hidden
537;
538; Combined objects use the layout .box/cmd/<category>/<tool>.o so genbox.sh
539; can parse them without structural modifications
540;
541(rule POSIX_BC_BOX_OBJ
542 (glob "cmd/posix/bc.c")
543 (gate build_posix_bc)
544 (dep $(MATCH))
545 (after POSIX_BC_C)
546 (out ".box/parts/$(STEM).o")
547 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
548
549(rule POSIX_BC_BOX
550 (gate build_posix_bc)
551 (dep POSIX_BC_BOX_OBJ)
552 (out ".box/cmd/posix/bc.o")
553 (description "bc's objects combined into one relocatable object, main renamed for the box dispatch table")
554 (shell "$(LD) -r -o $(OUT) $(IN) && $(OBJCOPY) --redefine-sym main=bc_main $(OUT) && $(OBJCOPY) --keep-global-symbol=bc_main $(OUT)")
555 (group box))
556
557(rule POSIX_AWK_BOX_OBJ
558 (glob "cmd/posix/awk/*.c")
559 (gate build_posix_awk)
560 (skip "maketab.c")
561 (dep $(MATCH))
562 (after POSIX_AWK_C)
563 (out ".box/parts/$(STEM).o")
564 (exec $(CC) $(CPPFLAGS) -Icmd/posix/awk $(CFLAGS) -c -o $(OUT) $(MATCH)))
565
566(rule POSIX_AWK_BOX
567 (gate build_posix_awk)
568 (dep POSIX_AWK_BOX_OBJ)
569 (out ".box/cmd/posix/awk.o")
570 (description "awk's objects combined into one relocatable object, main renamed for the box dispatch table")
571 (shell "$(LD) -r -o $(OUT) $(IN) && $(OBJCOPY) --redefine-sym main=awk_main $(OUT) && $(OBJCOPY) --keep-global-symbol=awk_main $(OUT)")
572 (group box))
573
574(rule POSIX_SH_BOX_OBJ
575 (glob "cmd/posix/sh/*.c")
576 (gate build_posix_sh)
577 (skip "mknodes.c" "mksyntax.c")
578 (dep $(MATCH))
579 (after POSIX_SH_C)
580 (out ".box/parts/$(STEM).o")
581 (exec $(CC) $(CPPFLAGS) -DSHELL -Icmd/posix/sh $(CFLAGS) -c -o $(OUT) $(MATCH)))
582
583(rule POSIX_SH_BOX
584 (gate build_posix_sh)
585 (dep POSIX_SH_BOX_OBJ)
586 (out ".box/cmd/posix/sh.o")
587 (description "sh's objects combined into one relocatable object, main renamed for the box dispatch table")
588 (shell "$(LD) -r -o $(OUT) $(IN) && $(OBJCOPY) --redefine-sym main=sh_main $(OUT) && $(OBJCOPY) --keep-global-symbol=sh_main $(OUT)")
589 (group box))
590
591(rule POSIX_MAKE_BOX_OBJ
592 (glob "cmd/posix/make/*.c")
593 (gate build_posix_make)
594 (dep $(MATCH))
595 (out ".box/parts/$(STEM).o")
596 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
597
598(rule POSIX_MAKE_BOX
599 (gate build_posix_make)
600 (dep POSIX_MAKE_BOX_OBJ)
601 (out ".box/cmd/posix/make.o")
602 (description "make's objects combined into one relocatable object, main renamed for the box dispatch table")
603 (shell "$(LD) -r -o $(OUT) $(IN) && $(OBJCOPY) --redefine-sym main=make_main $(OUT) && $(OBJCOPY) --keep-global-symbol=make_main $(OUT)")
604 (group box))
605
606(rule EXTRA_YAP_BOX_OBJ
607 (glob "cmd/extra/yap/*.c")
608 (gate build_extra_yap)
609 (dep $(MATCH))
610 (out ".box/parts/$(STEM).o")
611 (exec $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $(OUT) $(MATCH)))
612
613(rule EXTRA_YAP_BOX
614 (gate build_extra_yap)
615 (dep EXTRA_YAP_BOX_OBJ)
616 (out ".box/cmd/extra/yap.o")
617 (description "yap's objects combined into one relocatable object, main renamed for the box dispatch table")
618 (shell "$(LD) -r -o $(OUT) $(IN) && $(OBJCOPY) --redefine-sym main=yap_main $(OUT) && $(OBJCOPY) --keep-global-symbol=yap_main $(OUT)")
619 (group box))
620
621; Genbox.sh relies on arguments passed by ninqu, where each argument matches
622; an output from BOX_OBJ or a custom box rule. The script derives categories
623; and tool names directly from these paths and outputs the dispatch code
624;
625(rule BOX_DISPATCH
626 (dep BOX_OBJ POSIX_BC_BOX POSIX_AWK_BOX POSIX_SH_BOX POSIX_MAKE_BOX EXTRA_YAP_BOX NINQU_BOX_OBJ)
627 (out ".box/aruu-box.c")
628 (description "dispatch table and main() for aruu-box, generated from the enabled tool list")
629 (exec scripts/genbox.sh $(IN))
630 (redirect)
631 (group box))
632
633; Libm is linked unconditionally because bc requires it, and unused library
634; references are safe. Modern toolchains omit unreferenced archive components.
635; Yap requires terminfo, which is an optional system dependency. Linking it
636; unconditionally breaks builds on systems without ncurses-dev when yap is
637; disabled. Genconfig.sh exports BOX_EXTRA_LIBS as "-ltinfo" or an empty string
638; based on whether yap is enabled
639;
640(rule BOX
641 (dep BOX_DISPATCH BOX_OBJ POSIX_BC_BOX POSIX_AWK_BOX POSIX_SH_BOX POSIX_MAKE_BOX EXTRA_YAP_BOX NINQU_BOX_OBJ LIBUTIL LIBUTF LIBREDLINE)
642 (out "aruu-box")
643 (description "single multi-call binary, one dispatch table for every enabled tool")
644 (shell "$(CC) $(CPPFLAGS) $(CFLAGS) -o $(OUT) $(IN) $(LDFLAGS) $(LDLIBS) $(BOX_EXTRA_LIBS)")
645 (group box))
646
647(group box BOX)
648
649; -------------------------------------------------------------------
650; top level. (group all) contains every build target except clean
651; and box. box is separate because it produces a different binary
652; with different .o files, and mixing it with standalone builds
653; would cause confusion. clean is never in all because it removes
654; what all builds
655; -------------------------------------------------------------------
656
657(rule ALL_BINS
658 (phony)
659 (after LIBUTIL LIBUTF LIBREDLINE
660 POSIX_BIN LINUX_BIN NET_BIN XSI_BIN
661 PSEUDO_BIN EXTRA_BIN
662 POSIX_BC POSIX_AWK POSIX_SH POSIX_MAKE EXTRA_YAP
663 AR AS LD CC1 CPP CCDRV)
664 (exec true))
665
666(group all ALL_BINS)
667
668(group default all)
669
670; meta-targets: apply an override, then build a normal target under
671; it. invoke as `ninqu META.TARGET` (`ninqu debug.posix`) or bare
672; `ninqu META` to apply the override and build (group default)
673;
674(meta debug
675 (set CFLAGS "$(CFLAGS) -g -O0"))
676
677(meta release
678 (set CFLAGS "$(CFLAGS) -O2 -DNDEBUG"))