aostruszka/nonrec-make — pull request #12 by KholdStare (2014-02-15 22:39:44+00:00)
Title: Deferring rule creation after all submakefiles have been included.

Hi! First of all, thank you for creating this - I'm finding it a joy to use. I've been looking for a makefile library to use for large projects, and have a few requirements in mind.

-----------

TLDR: Move `tgt_rule` invocation from `footer.mk`, into `Makefile` after `Rules.top` is included. Testcase in the form of a project is provided. Breaks `SUBDIR_TGTS`. Please advise :)

-----------

## Problem and solution - deferred rule creation

One of these requirements is handling very complicated (and ugly) dependencies. If a particular target requires a library from a sibling directory (such as a commonly used testing library) there are potentially two ways to express that:

* Use relative paths to specify these sibling targets. This becomes unwieldy as moving target directories around requires rewriting all these relative paths.
* Have a way to variable that can be referred to globally for this path. e.g. `TEST_LIB_DIR`

If we go with the second approach, it would be nice to define this variable in the `Rules.mk` file of the corresponding library.

TEST_LIB_DIR := $(d)

And then in a unittest target we could do

unittest_DEPS = unittest.o $(TARGETS_$(TEST_LIB_DIR))

However, the use of this variable imposes a certain inclusion order on the submakefiles so it in scope when it is used. In particular, even though `_DEPS` variables are deferred, they are eagerly evaluated during `tgt_rule` creation (Make's fault). One can get by the problem temporarily by ensuring the inclusion order is correct.

If we push this further, we can have dependencies that criss-cross directories, meaning that no ordering can solve the problem.

.
├── dir1
│ ├── appA
│ └── libB
└── dir2
├── appB
└── libA

appA depends on libA
appB depends on libB

In this case we either need two rounds of expansion where we use `.SECONDEXPANSION` and throw in a few `$$` into the mix; OR we defer rule creation for targets until the very last minute.

This change introduces this late rule creation, making the test case work, BUT it breaks `SUBDIR_TGTS`.

## SUBDIR_TGTS breakage

This happens because is constantly being updated. If we decide to "save" the variable per directory, it also doesn't work easily:

# This doesn't work becasue `$(d)` is also constantly updated.
unittest_DEPS = unittest.o $(SUBDIR_TGTS_$(d))

We need some way of evaluating `$(d)` in a deferred statement. Unfortunately I can't think of any nice solutions to this. I started a [stackoverflow question here](http://stackoverflow.com/questions/21802379/deferred-assignment-in-makefile-with-one-round-of-expansion) to find people's suggestions.

Thanks again. What are your thoughts on this?