nx_nxmake.nx
buildroot/runtime/nx_nxmake.nx
about
nxmake.nx -- sovereign build driver (replaces GNU make).
Scope claim:
GNU make is Turing-complete and huge. We don't need most of it.
The typical Nishi build is: list of inputs -> one or more
command invocations -> an output file. Make's real
differentiator is MTIME-based staleness checking; we replicate
that with fs.nx's fstat.
Replaces on the Nishi build path:
make / gmake / bmake — any POSIX make
File format: plain-text stanzas in "nx.build":
target: kernel.elf
inputs: boot.S trap.S src/sched_bootstrap.S nishi-kernel.s
cmd: ./nxld --base 0x80000000 -o kernel.elf <inputs>
target: nishi-kernel.s
inputs: src/kmain.nx src/uart.nx ...
cmd: ./nxc2 --target asm --opt src/kmain.nx > $@
Comments: lines starting with '#'. Blank lines separate stanzas.
Subprocess-exec is intentionally absent from this seed. Windows
host (CreateProcessA) and Linux host (clone+execve) diverge at
the syscall layer and we don't have a portable abstraction yet.
Instead nxmake emits a build plan -- an ordered list of commands
and their staleness verdicts -- that a thin shim script runs.
This is honest: nxmake owns the dependency reasoning, the shim
owns the syscall specifics. Decoupled sovereignty.
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_fs.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 56 | const MAX_RULES: i64 = 64 |
| 57 | const MAX_INPUTS: i64 = 1024 |
| 58 | const MAX_LINES: i64 = 512 |
| 59 | const RULE_SIZE: i64 = 48 |
| 60 | const INPUT_SIZE: i64 = 16 |
| 61 | const LINE_SIZE: i64 = 16 |
functions
| 64 | func rule_target_off(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 0; return a as *i64 } |
| 65 | func rule_target_len(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 8; return a as *i64 } |
| 66 | func rule_n_inputs(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 16; return a as *i64 } |
| 67 | func rule_inputs_at(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 24; return a as *i64 } |
| 68 | func rule_cmd_off(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 32; return a as *i64 } |
| 69 | func rule_cmd_len(rb: i64, i: i64) -> *i64 { let a: i64 = rb + i * RULE_SIZE + 40; return a as *i64 } |
| 71 | func input_off_p(ib: i64, j: i64) -> *i64 { let a: i64 = ib + j * INPUT_SIZE + 0; return a as *i64 } |
| 72 | func input_len_p(ib: i64, j: i64) -> *i64 { let a: i64 = ib + j * INPUT_SIZE + 8; return a as *i64 } |
| 74 | func line_off_p(lb: i64, k: i64) -> *i64 { let a: i64 = lb + k * LINE_SIZE + 0; return a as *i64 } |
| 75 | func line_len_p(lb: i64, k: i64) -> *i64 { let a: i64 = lb + k * LINE_SIZE + 8; return a as *i64 } |
| 81 | func nxmake_strlen(p: *u8) -> i64 |
| 89 | func slice_eq_cstr(buf: *u8, off: i64, len: i64, kw: *u8) -> i64 calls 1: nxmake_strlen |
| 101 | func slice_starts_with(buf: *u8, off: i64, len: i64, kw: *u8) -> i64 |
| 113 | func slice_to_cstr(buf: *u8, off: i64, len: i64, out: *u8) -> i64 called by 1: slice_mtime |
| 124 | func trim_left(buf: *u8, off: i64, end: i64) -> i64 called by 1: parse_rules |
| 138 | func trim_right(buf: *u8, off: i64, len: i64) -> i64 called by 1: parse_rules |
| 157 | func split_lines(buf: *u8, n: i64, line_base: i64) -> i64 |
| 200 | func parse_rules( called by 1: main calls 13: line_off_pline_len_ptrim_lefttrim_rightslice_starts_withrule_target_off+7 |
| 316 | func nxmake_mtime(path: *u8) -> i64 |
| 331 | func find_rule( |
| 356 | func slice_mtime(buf: *u8, off: i64, len: i64) -> i64 |
| 363 | func is_stale( called by 1: emit_plan_for calls 7: rule_target_offrule_target_lenslice_mtimerule_n_inputsrule_inputs_atinput_off_p+1 |
| 394 | func emit_plan_for( called by 2: emit_plan_formain calls 12: rule_n_inputsrule_inputs_atinput_off_pinput_len_pfind_ruleemit_plan_for+6 |
| 437 | func main(argc: i64, argv: *i64) -> i64 |