ele lont
ele lont

Reputation: 479

Why does make not use my explicit rules when implicit rule is also in use?

I have (old suffix type) rules inside my Makefile for .c and .o files. The problem is that when i run make all those rules are not used and instead the implicit rules are used.

If i run make all -r then it will tell me make: *** No rule to make target... which is expected since i have intentionally not added explicit rules for program1...3.

In order to fix this issue i can add explicit rules for program1...3:

program1: program1.o

So a solution is not what i am after here. Just an explanation.

all: program1 program2 program3
.o:
    @echo What is going on 1
    $(CC) $(LIBS) $(LDFLAGS) $< -o $(OUT)/$@

.c.o:
    @echo What is going on 2
    $(CC) -c $(CFLAGS) $(IFLAGS) $(CPPFLAGS) $< -o $@

Why does make use implicit rules in the current case even though i have explicitly written the rules for .c and .o files?

Upvotes: 0

Views: 254

Answers (2)

raspy
raspy

Reputation: 4261

When running make without -r option, the built-in rule comes in place:

%: %.c
#  recipe to execute (built-in):
        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

This can be verified with make -p:

...
program1: program1.c
#  Command line target.
#  Implicit rule search has been done.
#  Implicit/static pattern stem: 'program1'
#  Last modified 2019-11-19 14:28:03.247550778
#  File has been updated.
#  Successfully updated.
# automatic
# @ := program1
# automatic
# % :=
# automatic
# * := program1
# automatic
# + := program1.c
# automatic
# | :=
# automatic
# < := program1.c
# automatic
# ^ := program1.c
# automatic
# ? := program1.c
# variable set hash-table stats:
# Load=8/32=25%, Rehash=0, Collisions=1/21=5%
#  recipe to execute (built-in):
        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
...

This rule is selected over chain of implicit rules %.c -> %.o -> % as documented:

There are some special implicit rules to optimize certain cases that would otherwise be handled by rule chains. For example, making foo from foo.c could be handled by compiling and linking with separate chained rules, using foo.o as an intermediate file. But what actually happens is that a special rule for this case does the compilation and linking with a single cc command. The optimized rule is used in preference to the step-by-step chain because it comes earlier in the ordering of rules.

Now, when you disable built-in rules with -r, old-fashioned rules that you use are also disabled, due to .SUFFIXES being empty, as documented:

Suffix rule definitions are recognized by comparing each rule’s target against a defined list of known suffixes. When make sees a rule whose target is a known suffix, this rule is considered a single-suffix rule.

The known suffixes are simply the names of the prerequisites of the special target .SUFFIXES.

The ‘-r’ or ‘--no-builtin-rules’ flag causes the default list of suffixes to be empty.

Upvotes: 2

Beta
Beta

Reputation: 99084

Your question omits some details, but I'll go out on a limb.

You have written a rule for the target .o, and a pattern rule for targets of the pattern "%.o". But you are not asking make to build .o or program1.o, you are asking it to build program1. Had you examined the results of running Make, you would have noticed that there is no object file involved.

Upvotes: 0

Related Questions