Reputation: 31
Is there a way to override the prerequisites of a target in later part of Makefile?
A common Makefile is used by multiple users. To accommodate individual unique usage, an include directive is added at the end.
E.g. in common.make
SomeVar1 =
all: step5
step1:
recipe1
step2: step1
recipe2
step3: step2
recipe3
step4: step3
recipe4
step5: step4
recipe5
-include local.make
Whenever necessary, individual user can override variables or even recipes from common.make in his/her own local.make.
However, it seems prerequisite from common.make can't be overridden in local.make.
E.g. if a user needs to skip step3 & step4, adding the following in local.make doesn't remove step4 as prerequisite for step5 target.
step5: step2
Does GNU make have some syntax to force override prerequisites of targets defined in earlier part of Makefile?
Perhaps, something like:
.OVERRIDE: step5: step2
The only way I can think of is to define prerequisites of each rule in common.make as variables. But it will be unwieldy for large numbers of steps -- lots of variables to define and association/mapping of variable names to their steps requires separate documentations.
I would like to avoid the prerequisite-variable approach if possible. Hopefully, GNU make has some syntax that can do so better.
Thank you for your help.
HCN
Upvotes: 1
Views: 1010
Reputation: 619
If you want you can just add:
step1b: step1
touch "$@"
step1c: step1b
touch "$@"
step2: step1c
in local.make and call like this:
$ make step2; make -t step4; make step5
touch "step1"
touch "step1b"
touch "step1c"
touch "step2"
touch step3
touch step4
touch "step5"
(here to test the makefile I replace recipeN with touch "$@"
so touch with quote is my recipe and touch without is printed by GNU Make.)
I know it works because it is very linear. If it doesn't I might just capture target list with make -n
or something similar and do a command line like this.
What if instead of overriding you defined: step1.make step2.make and you include them all. If you generate them by script then it is fine: you modify stepN.make but not the global one that include everybody. And the user could then choose to override precisely which step he wants.
So Makefile will have this shape:
# WARNING feel free to modify this file but don't modify stepN.make
#
# If you have missing target double check it isn't defined
# in stepN.make directly or with pattern (%) rule
include step1.make
include step2.make
include step3.make
Upvotes: 0
Reputation: 5301
One way to get that override-like behavior is exploiting the pattern matching preferring "the most exact match". Making the original targets just a little ambiguous by a little pattern allows local.make to override with an exact match.
SomeVar1 =
all: step5
s%ep1:
recipe1
s%ep2: step1
recipe2
s%ep3: step2
recipe3
s%ep4: step3
recipe4
s%ep5: step4
recipe5
-include local.make
If having step5
in local.make it is more exact than s%ep5
.
(I do not actually like this solution, but you do you, I just bring the tech.)
Upvotes: 1
Reputation: 31
I just thought of a workaround that is not quite elegant as the desired hypothetical .OVERRIDE:
but it doesn't require defining variable for each prerequisite in common.make.
Using the same common.gmake example, if a user needs to skip step3 & step4, but needs to add step1b & step1c between step1 & step2, his/her local.make will look as followed.
step1b: step1
recipe1b
step1c: step1b
recipe1c
step2: step1c
step3:
:
step4:
:
In addition, GNU make will also display warning messages about step3 & step4 targets being overridden, which is helpful.
local.make:10: warning: overriding commands for target `step3'
local.make:13: warning: overriding commands for target `step4'
common.make:12: warning: ignoring old commands for target `step3'
common.make:15: warning: ignoring old commands for target `step4'
Nevertheless, since this doesn't actually override dependencies, user has to force no-op to all dependencies to be skipped. In this case, no-op is necessary for both step3 & step4 targets, where in real common.make, each skipped target may have multiple prerequisites.
This is the only gotcha I can think of. I believe it'll work even with -j option for parallel execution.
Any potential pitfall in such local.make override usage that I haven't thought of, since I can't predict all possible GNU make options users may combine with local.make override?
HCN
Upvotes: 1
Reputation: 5301
Make has ?=
for overriding behavior:
-include local.make
# local.make definition of STEPX_PREREQS "overrides" below defaults
STEP1_PREREQS ?=
STEP2_PREREQS ?= step1
STEP3_PREREQS ?= step2
step1: $(STEP1_PREREQS)
recipe1
step2: $(STEP2_PREREQS)
recipe2
step3: $(STEP3_PREREQS)
recipe3
Upvotes: 0