Often it is convenient to put commands into the makefile that don't actually build a file, but are somehow logically associated with the build process. For example, a very common procedure in makefiles is something like this:
prefix=/usr/local install: our_program install -m 0755 our_program $(prefix)/bin install -m 0644 *.png $(prefix)/share/our_program/icons .PHONY: install
When someone types makepp install
, then
makepp first builds our_program
, then runs the
commands associated with the install target. The
install
command simply copies its arguments to the
specified directory, and sets the file's protection to the indicated
value. So it copies our_program
into
/usr/local/bin
, and some associated data files into
/usr/local/share/our_program/icons
. But this doesn't
create a file called install
in the current
directory.
The install
target here is called a phony
target because makepp treats it as if it were a real
file, but it is not actually a file, it's just a trick for forcing
makepp to build its dependencies and then run some
commands.
That's what the line
.PHONY: install
is for. It tells makepp that it really shouldn't expect
the file ./install
to exist after the commands have
executed. If you forget the phony declaration, then makepp
will expect the file install
to exist after executing
the commands, and it will complain loudly if it does not.
You can also write the phony declaration like this:
$(phony install): our_program ...
and then omit the .PHONY: install
line. This
means that you can declare the target as phony on the same line as
you define it, which may make your makefiles more readable.
Phony targets are extremely common in makefiles. In almost all
makefiles, the first target is the phony target all
,
like this:
$(phony all): program1 program2 program3
If no target is specified on the command line, makepp
attempts to build the first target in the file. If your makefile
makes more than just one program, you most likely want to build all
of the programs by default. In this example, if the programmer just
types makepp
without any arguments, makepp
attempts to build all
, which forces it to build all
three programs from this directory.
Here is a sample makefile fragment that illustrates some commonly used phony targets:
PROGRAMS := combobulator discombobulator
$(phony all): $(PROGRAMS) # All is the first target, so it's the default.
combobulator: $(COMBOBULATOR_OBJS)
$(CXX) $(inputs) -o $(output)
discombobulator: $(DISCOMBOBULATOR_OBJS)
$(CXX) $(inputs) -o $(output)
#
# This target makes sure everything is compiled, and then puts the
# programs into a place where everyone can access them. We make the
# directories if they don't exist yet.
#
prefix := /usr/local
$(phony install): all
test -d $(prefix) || mkdir $(prefix)
test -d $(prefix)/bin || mkdir $(prefix)/bin
for prog in $(PROGRAMS); do \
install -m 0755 $$prog $(prefix)/bin; \
done
test -d $(prefix)/share || mkdir $(prefix)/share
test -d $(prefix)/share/combobulate || mkdir -p $(prefix)/share/combobulate
for icon in *.xbm; do \
install -m 0644 $$icon $(prefix)/share/combobulate; \
done
# Note the use of the double dollar sign to pass a single dollar sign to
# the shell. Note also the backslashes at the end of a line to indicate
# that a shell command continues to the next line.
#
# This target gets rid of all the junk that gets built during compiles.
# (Note that this could be done more thoroughly with the
# only-targets
function.)
#
$(phony clean):
rm -f $(PROGRAMS) *.o
#
# This target makes a source distribution for shipping out to someone.
#
VERSION := 3.14
$(phony distribution):
rm -rf combobulate-$(VERSION) # Get rid of previous junk, if any.
mkdir combobulate-$(VERSION)
cp *.c *.h Makefile README INSTALL combobulate-$(VERSION)
tar cf - combobulate-$(VERSION) | gzip -9c > combobulate-$(VERSION).tar.gz
rm -rf combobulate-$(VERSION)
#
# This target runs regression tests to make sure the program(s) are
# doing what they are supposed to do.
#
$(phony test): $(PROGRAMS)
noecho for testfile in *.test; do \
./combobulate $$testfile | ./discombobulate - > junk_output; \
if cmp -s junk_output $$testfile; then \
echo passed $$testfile; \
else \
echo failed $$testfile; \
fi; \
done
#
# If "noecho" is the first word of the action, the action itself is not
# printed before it is executed. In this case, printing the action
# would merely clutter up the screen so it is very common to suppress
# printing for such long commands.
#