I have two different OS environment: CentOS6 and CentOS7.
The CentOS6 GNU make version is 3.81
The CentOS7 GNU make version is 3.82
My Makefile is below
%o : %c
$(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@
3.81 works very well.
But 3.82 will NOT execute the cmmand
$(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@
It seems ONLY execute its default command
%o : %c
What i see on the terminal, will expand like this ===> gcc c -o main.o main.c
After some test, I'm sure that this line $(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@ will NEVER be executed.
After searching by Google, I rewrite in another syntax format
.c.o:
$(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@
This works!! $(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@ will execute!!!
I read the 3.82 release note and doesn't get any clue about this problem.
Could you help me to explain why?
I don't think this is caused by different GNU make version.
Thanks!!!
When you say:
It seems ONLY execute its default command
%o : %c
that is not correct. The default rule for building an object file from a C source file is not %o : %c
, it is %.o : %.c
. The difference here (the added .
) may seem small but it is the reason for the behavior you see.
Since the default rule is %.o : %.c
, when you define your own rule using %o : %c
that is a completely different rule: it does not replace the existing rule, it is a new rule in addition to the existing rule.
So now there are two pattern rules that can be used to build an object file from a C source file. How does make decide which one to use? The algorithm for choosing changed between GNU Make 3.81 and GNU Make 3.82.
In GNU Make 3.81 and earlier, the first defined rule was always chosen (where default rules are considered to be define last). That means that your rule %o: %c
was chosen.
In GNU Make 3.82 and later, the best match is always chosen. The best match is define as the rule where the stem (the part that matches the %
) is the shortest (our put alternatively, the most specific rule is chosen). If we want to build foo.o
from foo.c
, then in the default rule the stem is foo
and in your alternative rule the default is foo.
(for a pattern %o
matching the string foo.o
the stem--the part matching %
--is foo.
).
Since the stem of the built-in rule is shorter (foo
is 3 characters long) than the stem of your pattern rule (foo.
is four characters long), the built-in rule is more specific and so it will be chosen.
If you want your makefile to work with all versions then instead of creating an extra rule you should replace the built in rule by using the same patterns, not different patterns; write your rule as:
%.o : %.c
$(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@
and it will work with all versions of GNU Make.
Your rule is not great anyway since by leaving out the .
it means that rule would match any target file that ended with o
(not just .o
) and any prerequisite that ended with c
(not just .c
).