Makefile dependencies without triggering dependent rules - makefile

If I have a target, that has some dependencies, and I invoke that target, make will try and generate the dependencies if the relevant rules are available (they are). Is there any way to prevent this behaviour, essentially telling make that to use that target the dependencies must be available, but to just error out if they aren't?
Example, assuming that foo and bar do not exist:
foo:
echo a > foo
bar:
echo b > bar
target: foo bar
cat foo bar > foobar
Desired behaviour
> make target
error, cannot satisfy dependencies
Actual behaviour
> make target
echo a > foo
echo b > bar
cat foo bar > foobar
GNU make is being used, if it makes any difference.

No. If make cannot find a rule to build a prerequisite, and it doesn't exist, then make will fail. If make CAN find a rule to build a prerequisite, and it's out of date, then make will build it.
If you don't want it rebuilt, you should not list it as a prerequisite. You can do something like this:
target:
[ -f foo ] && [ -f bar ] || { echo "cannot satisfy prerequisites"; exit 1; }

What I usually do is something like
target: dependency
dependency:
#echo fatal error: $# is missing; exit 1

Related

Apply a single Makefile target rule to multiple input files

Say I have the following set of inputs:
list = foo \
bar \
baz
And say I have a rule such as follows:
$(somedir)/%:
# Do something here
I know I am able to invoke the rule by statically defining the target and its dependency:
$(somedir)/foo : foo
$(somedir)/bar : bar
$(somedir)/baz : baz
However, would there be a way to apply this rule to an evergrowing $(list) of inputs rather than having to statically define them all?
To be more specific, I am looking for a way to run a rule for each input and get an output (which is $(somedir)/input). Is this possible in Make?
Well, not sure I understand all the details but it seems to me that pattern rules are exactly what you need:
$(somedir)/%: %
# your recipe
This tells make that any $(somedir)/foo depends on foo and is built by the given recipe. Of course, you will also need to tell make which target you want to build:
make somedir=there there/foo there/bar
Bonus: if you know the list you can add a phony target to build them all at once:
list = foo bar baz
.PHONY: all
all: $(addprefix $(somedir)/,$(list))
$(somedir)/%: %
# your recipe
Second bonus: to help writing your recipe you can use automatic variables: $# expands as the target, $< as the first prerequisite, $^ as all prerequisites, etc. So your recipe could resemble this:
$(somedir)/%: %
build $# from $<

Make: drop targets after recursion

Make is a beautiful and powerful tool for wide and sundry use. I love it, and this is only a detail.
Suppose I have a recursive make recipe defined as follows:
submake-cmd:
make ${SUBMAKEGOALS} -C foo
# where I have derived ${SUBMAKEGOALS} earlier
And here is the crux: I can either set the make interface up like so...
$: make submake-cmd SUBMAKEGOALS="foo bar"
-- OR --
# preferably
make submake-cmd foo bar biz baz
The only problem is that if I calculate the ${SUBMAKEGOALS}, then I am forced to write the submake-cmd rule like so in order to avoid unpredictable behavior:
submake-cmd:
make ${SUBMAKEGOALS} -C foo
exit 1
Such that make will exit, and I will see make exit with an error.
There must be some way to clear out the make targets or indicate that make has completed successfully when using make recursion...
Does anyone have any ideas?
preferably
make submake-cmd foo bar biz baz
You're probably overthinking something. If you want to pass an unknown number of targets to submake then it could be done like this:
ifneq ($(sub),)
.DEFAULT:
$(MAKE) -C $(sub) $#
endif
And then: make sub=dir1 foo; make sub=dir2 bar biz bazetc. (I assume the root makefile does not contain any of foo/bar/biz/baz of its own; if it's not so, then you have to patch these rules appropriately).

Makefile lazy expansion of rule prerequisite

I have a couple of rules which are parametrised as follows:
.SECONDEXPANSION:
NAME=default
foo: x-$$(NAME)
bar: NAME=bar
bar: foo
baz: NAME=baz
baz: foo
x-%:
#echo building $#
I would expect the following output when running make bar:
$ make bar
building x-bar
But I see:
$ make bar
building x-default
Is there a way to delay expansion in a rules' prerequisites until after it is being invoked so I can parametrize the rules like this? I would like to avoid using define ... endef etc. because my rules are quite complicated and having another level of $$ in there would really hurt readability.
This was a bug in make. Fixed in make 4.4. It yields the output you expected:
# make bar
building x-bar

Ordering in makefiles

I've two targets foo and bar. Neither depend on the other, but if bar has to be rebuilt, it has to be done before foo. They are what gnu-make calls phony targets, their rules have always to be executed when they are specified.
Currently, we express a main target which depends on both like this:
# user level targets
all: bar
#$(MAKE) foo
#echo all
alt: foo
#echo alt
# internal targets
foo:
#echo foo
bar: qux
#echo bar
qux:
#echo qux
#touch qux
and we have the required behavior: if qux is not up-to-date: make bar outputs qux bar foo all (in that order) and make alt outputs foo alt; if qux is up-to-date, make bar output bar foo all and make alt outputs foo alt.
This is increasingly uncomfortable as foo has to be handled specifically (all targets which depend on both have to be handled that way, foo can't be put in a variable describing dependencies if bar is also there, the submake is itself an issue and the command line has to be maintained to pass additional variables). We now have another target which has to be handled in the same way and I'm looking for other, more convenient, ways to handle the structure.
Note 1 : In practice, I'm currently using only gnu-make but the only known dependency on a gnu-make extension over POSIX is the possibility to include files (which is quite widely available). I'd prefer something which keep the current state (i.e. widely supported constructs), but if it is not possible, the use of a gnu-make only extension is acceptable.
Note 2: gnu-make has a notion of order-only-prerequisites, but it apparently doesn't provide what we need. With
# user level targets
all: bar foo
#echo all
alt: foo
#echo alt
# internal targets
foo: | bar
#echo foo
bar:
#echo bar
make alt also build bar (if a file bar exist, its date doesn't influence the decision of rebuilding foo, which is the documented behavior).
Note 3: The more I think about it, the less I think it is possible to solve this problem with make without using a recursive call. It seems to me that it need two passes on the dependency graph, one to determine what has to be built, one to determine the ordering and I know nothing in make behavior which can't be done with a one pass algorithm.
Hmmm, how about this hack (for a hack it undoubtedly is :-)).
Basically, you could run make -d -n plus your command arguments. The output will contain several lines like Must remake target 'clean'. This information tells you whether this run of make will attempt to build both foo and bar. If this turns out to be the case, just add a rule to cause the serialisation you want.
A sketch:
this := $(lastword ${MAKEFILE_LIST})
ifndef DONTRECURSE
targets-that-will-get-remade := $(patsubst %',%,$(shell ${MAKE} -f ${this} ${MAKECMDGOALS} --debug=b -n DONTRECURSE=nosiree | grep -Po "Must remake target '\K.*'"))
endif
ifeq (bar foo,$(sort $(filter bar foo,${targets-that-will-get-remade})))
foo: bar
endif
.PHONY: foo bar
foo bar:
sleep 3
: $#
So, you run make. DONTRECURSE is not set so the $(shell …) runs. That runs make a second time with the same makefile and goals, but adds the -d (debug) and -n (don't actually run the recipes) flags. DONTRECURSE is set to prevent a third copy of make running.
The expansion of all that is a list of the targets this run of make will attempt to build on this run. (Extracting the target names is pretty tiresome—there is probably a cleaner way.)
If this list of targets includes both foo and bar, simply add a foo: bar dependency. Job done. The sleep 3 lines show this serialisation working when you use -j4 (say).

Path dependency in Makefile

Here is two targets in my Makefile.
.SECONDARY:
exp-%.ans:
echo $* > eval/$#
%.scores: %.ans
cat eval/$< > eval/$#
When I write make -n exp-40.scores output would be:
echo 40 > eval/exp-40.ans
cat eval/exp-40.ans > eval/exp-40.scores
which is good except one thing. It does not aware of the dependency is already hold. If I create eval/exp-40.scores (first time) then I expect that make will say it is already in there if I run the same command. So I try to change my Makefile like this:
.SECONDARY:
exp-%.ans:
echo $* > eval/$#
%.scores: eval/%.ans
cat eval/$< > $#
When I write make -n exp-40.scores again and output would be:
echo eval/40 > eval/eval/exp-40.ans
cat eval/eval/exp-40.ans > exp-40.scores
which is completely wrong because my parameter should be 40 not eval/40.
How can I achieve the best of the these two worlds? Namely, I want to create *.scores in eval/ folder. I also want make to check whether file is already exist or not. Then make should proceed according to that file existence.
Thanks.
One of the core rules of make is that you need to build the target your rule told make that you'd build. A rule like foo : bar tells make that if it runs that recipe, the recipe will create or update a file named foo. If the recipe creates or updates a file named biz/foo instead, then your makefile is wrong and things will not work.
Make always puts the target it expects the recipe to create into the $# automatic variable. Your recipe should create or update $# and exactly $#. Not something else.
So in your case, you need to write:
eval/exp-%.ans:
echo $* > $#
eval/%.scores: eval/%.ans
cat $< > $#
If you want to be able to run make exp-40.scores and have it actually create eval/exp-40.scores, then you can add a rule like this:
%.scores: eval/%.scores ; #:
(you have to provide some kind of recipe for pattern rules, they cannot have an empty recipe; the one above does nothing).

Resources