xparq/bbmake

Path-aware inference rules

Closed this issue · 1 comments

xparq commented

Making inference rules work even if the target and prerequisite are not in the same dir (i.e. they differ also in their path, not just their suffixes) would enable (or vastly simplify) some important practical use cases (i.e. building outside the source tree, without tedious workarounds).

It adds support for path prefixes to implicit prerequisite names (e.g. src/), via an extended inference rule syntax:

test: x.o
src/%.c.o:
	@echo "YAY, path-aware inf. rules!!! $< -> $@"

While this is a vague & incomplete approximation of NMAKE's path-extended inference rules, it could be a "high-gain" first stage toward proper pattern rules a'la GNU make (#2)...

Accordingly, it already uses the % pattern-matching placeholder in the rule definitions, for a (kinda-sorta) forward-compatible approach. However, limitations currently:

  • There's no actual pattern matching, it can only add path prefixes to prerequisites only.
    (The target suffix spec. can't even contain the pattern placeholder, it must still be just a plain old inference rule target suffix, as before; partly because the current syntax doesn't allow the target suffix to start with anything else than a dot. That's one reason why GNU's generalized pattern rule syntax is superior. -> #2)
  • Single-suffix rules haven't been considered yet.

TODO:

  • More rigorous look at these functions (plus their call sites)... Note: it's been "fortunately OK" so far (only ...:; cmd one-liners weren't explicitly rejected in POSIX mode (albeit there things would likely err out earlier anyway!)), but it's a) not properly verified yet, b) not future-proof. So, do something about it...

    • is_suffix: checked earlier: "perfectly compatible", if explicitly added to .SUFFIXES...
    • suffix: really just about a ., so it's not compatible, it all depends on what its callers are up to; and the only relevant call(s) turn(s) out to be in rules.c, and it's been considered from the start
    • target_type: added a minor, trivial adjustment to not refuse the extended inf. rule format; but that new result is not even actually (effectively) used anywhere...
    • ispname/isfname, check_name, is_valid_target: is_valid_target just calls check_name, which is the only caller of ispname/isfname, so that's the relevant one. And it only checks the names in POSIX mode, so, again: we're fine.
  • Tidy up

    • Style fixes
    • More tests
  • Drop the requirement of listing the suffix patterns at .SUFFIXES -> 24d3001

  • Create an uncluttered branch (pdp-cmp) for the "net" changes only, for easier review -> diff!...

  • Discuss with Ron. (In case it may get adopted, also move the manual tests into the auto-test suite, and/or remove the DP (debug printf) macro stuff.)


NOTES:

  • Works fine when the prefix paths themselves contain dots (also relative ones like ../)
  • No regressions found: all existing tests pass
  • -Wall-clean with CLANG & GCC (with each of -DDEBUG/NDEBUG/nothing; not relevant for a merge, just a note to self, for my WIP version)
  • This feature, even with the (preferable) future option of GNU-style pattern rules, could be refined and extended a fair bit (remaining compatible with its initial version), so it may still have considerable shelf-life before being obsoleted by #2:
    • eliminate the need for listing in .SUFFIXES (DONE now: 24d3001)
    • single-suffix rules?
    • some actual pattern manip. (e.g. extended syntax to allow more control over correlating the input and output names)
    • ...
xparq commented

BTW, this alone already makes it possible to build an entire source tree, auto-scanned, into a separate output tree (with some minor little extra hand-holding):

PROGRAM = test
SRC = src
OUT = out

# --- No edits needed below

sources != find $(SRC) -name '*.c'
objs = $(sources:$(SRC)/%.c=$(OUT)/%.o)

all: linktree_kludge # See below...

$(PROGRAM): $(objs)
    $(CC) $^ -o $@

$(SRC)/%.c.o:
    @mkdir -p `dirname $@`
    $(CC) -c $< -o $@

# Work around the current rigid out/%.o -> src/out/%.c name inference:
linktree_kludge: mk_treelink .WAIT $(PROGRAM) .WAIT rm_treelink
mk_treelink:; @if [ ! -e $(SRC)/$(OUT) ]; then ln -s '.' $(SRC)/$(OUT); fi
rm_treelink:; @if [   -L $(SRC)/$(OUT) ]; then rm        $(SRC)/$(OUT); fi