what is mean by "make skips the implicit rule search for phony targets " - makefile

I am new to Makefiles and was reading some docs on PHONY targerts. Can some one please explain what is mean by "make skips the implicit rule search for phony targets". If we are declaring a PHONY target as default target, is there any restriction?

It means that if a target is marked as .PHONY, then it must be an explicit rule, i.e. something like
a.o: a.c
$(CC) -o $# -c $<
and not an implicit rule, like a pattern rule or a suffix rule. As an example, consider the following makefile:
.PHONY: a.o
all: a.o b.o
%.o: %.c
$(CC) -o $# -c $<
Invoking make will do the following:
$ make
cc -o b.o -c b.c
$
Note that only b.c was compiled, not a.c.

Related

makefile: No rule to make target '%.o'

I have 3 files: Source.cpp 2ndfile.cpp 2ndfile.hpp
And I'm trying to compile them with mingw32-make
makefile that doesn't work:
all: launch.exe
launch.exe: %.o
g++ -o $# $^
%.o: %.cpp
g++ -c $< -std=gnu++11
makefile that works:
all: launch.exe
launch.exe: source.o 2ndfile.o
g++ -o $# $^
source.o: source.cpp
g++ -c source.cpp -std=gnu++11
2ndfile.o: 2ndfile.cpp
g++ -c 2ndfile.cpp -std=gnu++11
My question is: why the first one doesn't work? What's my problem with '%' patterns?
The error I get: mingw32-make: *** No rule to make target '%.o', needed by 'launch.exe'. Stop.
My question is: why the first one doesn't work? What's my problem with '%' patterns?
A pattern rule matches targets to prerequisites via a common element in their names, represented by the % wildcard. You present your own example in the form of this rule:
%.o: %.cpp
g++ -c $< -std=gnu++11
On the other hand, this rule ...
launch.exe: %.o
g++ -o $# $^
... is not a pattern rule, because the target name does not contain a %. There, you seem to be trying to use % in an entirely different sense, analogous to * in a glob pattern. It does not serve that purpose, even in pattern rules. That would give pattern rules a very different (and much less useful) meaning. Instead, in your non-pattern rule, the % is treated as an ordinary character.
There are many ways to write makefiles, but a good, simple model to start from for exploring pattern rules would be a combination of your first and second examples:
all: launch.exe
launch.exe: source.o 2ndfile.o
g++ -o $# $^
%.o: %.cpp
g++ -c $< -std=gnu++11
Substitute % with *.
all: launch.exe
launch.exe: *.o
g++ -o $# $^
*.o: *.cpp
g++ -c $^ -std=gnu++11
EDIT: there's an answer below why this is a bad idea. Here's what works:
all: launch.exe
launch.exe: Source.o 2ndfile.o
g++ -o $# $^
%.o: %.cpp
g++ -c $^ -std=gnu++11

GNU Make ignoring a phony rule specified by wildcard?

I am learning some courses about compiling some C code into specific assembly. I decided that the generated assembly should be manually inspected, so I came up with less something.s as a "test" rule.
As a fan-but-newbie of Make, I wrote this Makefile:
CODES := a
LESS ?= less
CODES_TEST := $(patsubst %,%-test,${CODES})
.PHONY: all test ${CODES_TEST} clean
all: $(patsubst %,%.s,${CODES})
test: all
%-test: %.s
${LESS} $^
%.s: %.c
${CC} ${CFLAGS} -S -o $# $^
clean:
rm -f *.o *.s
And I have this minimal a.c file:
int asdfg(void) { return 54321; }
I then typed make a-test in Bash, expecting less showing up with the content of a.s, only to be told this:
make: Nothing to be done for 'a-test'.
I got the above response regardless of the presence of a.s, which generates normally if I do make a.s or just make (implicitly runs the first rule, all).
I checked my Makefile and I don't think I made a typo or another simple mistake.
What did I miss with the above Makefile?
How can I get Make to execute less a.s when I run make a-test?
There is nothing to be done for a-test because the only rule that would make it is the implicit pattern rule:
%-test: %.s
${LESS} $^
and, per the manual 4.6 Phony Targets:
The implicit rule search (see Implicit Rules) is skipped for .PHONY targets.
and, since it is .PHONY, its mere non-existence does make it out-of-date.
To get around this, while preserving the phoiness, replace:
%-test: %.s
${LESS} $^
with:
${CODES_TEST}: %-test: %.s
${LESS} $^
Then the rule is a static pattern rule and no longer an implicit one.

Rule with empty recipe and empty prequisite and pattern rule

This is a snippet of the make file:
main.o :
%.o: main.c strlen.h main.h common.h
#echo $^
My question is that since main.o has an empty prerequisite and recipe then why the pattern rule is listing the dependency for main.o? As output shows like :
main.o : main.c strlen.h main.h common.h
Please explain any body help is appreciated!!!!!!!
A rule without a recipe simply adds any provided prerequisites to the given target. In other words, there can be only one rule with a recipe for a given target, but there can be as many rules without recipes for the same target as you like.
This:
foo.o: foo.h
foo.o: bar.h
foo.o:
foo.o: biz.h
foo.o: foo.c
$(CC) -c -o $# $<
is identical, from the point of view of make, to this:
foo.o: foo.c foo.h bar.h biz.h
$(CC) -c -o $# $<

Running Makefile targets

I am trying to 'fire' off the compilation by making all dependencies in a list of items, which are themselves targets.
From the answer (last, posted by Carl..) given in seems to suggest that something like this is possible.
Wildcard targets in a Makefile
all: $(OBJECTS)
OBJECTS = foo.o bar.o
bar.o: bar.c
#echo make $#
foo.o: foo.c
#echo make $#
.PHONY: all
My question is, when I run make I get the following, I cannot seem to get it to compile.
make: Nothing to be done for `all'.
Reverse the order of the first two lines, like so:
OBJECTS = foo.o bar.o
all: $(OBJECTS)
In your example, when Make gets to the all rule, OBJECTS has not yet been defined, so it resolves to this:
all:
Make sees a rule with no commands and no prerequisites-- nothing to be done.
You can do something like
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
This means:
To make a .o file, we need a .c file with the same name ( represented by %). The command to make the .o file is the name of the C compiler $(CC), followed by any compiler flags $(CFLAGS), then -c, etc. $< is the name of the first prerequisite ($^ is the names of all prerequisites, if you want that), and $# is the name of the target.

Change Makefile variable value depending on a target

I am not proficient with makefiles, but am used to simple ones. Right now, I have a task on hand.
I need to compile and link a test application with a different library and different include path based on the given target. If target is TARGET1, then link against LIB1 and include INCLUDEPATH1 during compilation. Similarly, if given target is TARGET2, then compile with INCLUDEPATH2 in CFLAGS and link with LIB2.
%.o: %.c
#echo [CC] $< ...
$(CC) $(CFLAGS) -o $*.o $<
Now I have a rule as above which compiles my test application. Now how can the CFLAGS be changed based on the target.
If you are using GNU Make, you can use target-specific variables:
target1: CFLAGS = -IINCLUDEPATH1
target1: LDLIBS = -lLIB1
target2: CFLAGS = -IINCLUDEPATH2
target2: LDLIBS = -lLIB2
all: target1 target2
target1: target1.o misc.o
target2: target2.o
However this doesn't work quite as well as you'd like: if target1 and target2 share some source files, you'll need to arrange for them to each be compiled twice and to differently-named .o files -- which will rather complexify your makefile.
Also, if you type make target1 then -IINCLUDEPATH1 will be propagated to the compilation of misc.c, as desired. However if you type make misc.o it has no way to know that this is eventually destined for target1 and the compilation of misc.c will get no special $CFLAGS value (though it'll get the global one, if there is one).
So this is really only useful in simple cases. But maybe your case is sufficiently simple.
I don't think you can alter variable depending on a target. Assume you invoke
make TARGET1 TARGET2
What value would the CFLAGS have then?
In this case, you can use non-pattern rules to distinguish targets.
TARGET1: a.c
#echo [CC] $< ...
$(CC) -I INCLUDEPATH1 ...
TARGET2: a.c
#echo [CC] $< ...
$(CC) -I INCLUDEPATH2 ...
To decrease repetition, you may also use variables and "functions". Then, you could re-use what would be the body of your pattern rule in different rules.
define compile_cmd
#echo [CC] $< ...
$(CC) -I $1 -l$2 $(CFLAGS)
endef
TARGET1: a.c
$(call compile_cmd,INCLUDEPATH1,LIB1) -o $# $<
TARGET2: a.c
$(call compile_cmd,INCLUDEPATH2,LIB2) -o $# $<
%.o: %.c
$(call compile_cmd,INCLUDEPATH_DEFAULT,LIB_DEFAULT) -o $# $<
That would make a nice enough and flexible makefile that suits your needs.

Resources