HCN
HCN

Reputation: 31

How to Override Prerequisites of a Target in Later part of Makefile?

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

Answers (4)

Et7f3XIV
Et7f3XIV

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

Andreas
Andreas

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

HCN
HCN

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

Andreas
Andreas

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

Related Questions