Phony Targets

Some additional common targets are included in most Makefiles, such as "install" to install the binaries, libraries, and documentation, and "clean" to clean up files generated by the Makefile. These targets are not actual files and usually have no associated source, and are only executed if specified as a command line argument to make. Note that make builds the first target it finds in the Makefile by default, but if we provide the name of a target as a command line argument, it builds only that target instead.

To ensure that they behave properly even if a file exists with the same name as the target, they should be marked as phony by listing them as sources to the .PHONY target. Otherwise, if there happens to be a file called "install" or "clean" in the directory, its time stamp will determine whether the install or clean targets actually run.

# Values that the user cannot override

BIN     = myprog
OBJS    = myprog.o math.o

# Set only if the user (or package manager) has not provided a value
# -Wall:    Issue all possible compiler warnings
# -g:       Compile with debug info to help locate crashes, etc.

CC      ?= cc
CFLAGS  ?= -Wall -O -g
LD      = ${CC}
LDFLAGS += -lm

# Defaults for commands that may be provided by the package manager
MKDIR   ?= mkdir
INSTALL ?= install
RM      ?= rm

# Most build systems should perform a staged install (install to a
# temporary location indicated by ${DESTDIR}) rather than install
# directly to the final destination, such as /usr/local.  The package
# manager can then check the staged install under ${DESTDIR} for
# problems before copying to the final target.

# Defaults for paths that may be provided by the package manager.
# This will install under ./stage/usr/local unless the user or package
# manager provides a different location.
DESTDIR ?= ./stage
PREFIX  ?= /usr/local

${BIN}: ${OBJS}
        ${LD} -o ${BIN} ${OBJS} ${LDFLAGS}

myprog.o: myprog.c Makefile
        ${CC} -c ${CFLAGS} myprog.c

math.o: math.c
        ${CC} -c ${CFLAGS} math.c

.PHONY: install clean

install:
        ${MKDIR} -p ${DESTDIR}${PREFIX}/bin
        ${INSTALL} -c -m 0755 ${BIN} ${DESTDIR}${PREFIX}/bin

clean:
        ${RM} -f ${BIN} *.o
    
shell-prompt: make install
cc -c myprog.c
cc -c math.c
cc -o myprog myprog.o math.o
mkdir -p ./stage/usr/local/bin
install -c -m 0755 myprog ./stage/usr/local/bin

shell-prompt: make clean
rm -f myprog *.o
    

PREFIX is a standard make variable that indicates the common parent directory for all installed files. Executables (binaries) and scripts are typically installed in ${PREFIX}/bin, libraries in ${PREFIX}/lib, header files in ${PREFIX}/include/project-name, and data files in ${PREFIX}/share/project-name. Some projects might also install auxiliary programs or scripts not meant to be run directly by the user. These typically go under ${PREFIX}/libexec/project-name. Using a project-name subdirectory minimizes collisions, where multiple projects install files with the same name. For example, several FreeBSD ports install files called version.h, but there is no collision since they install them under their own directories:

/usr/local/include/alsa/version.h
/usr/local/include/assimp/version.h
/usr/local/include/bash/version.h
    

DESTDIR is another standard variable that was created to protect systems against install collisions. We do not use subdirectories under bin, and occasionally two projects will install a program or script by the same name. For example, the open source projects splay and mp3blaster both install a program called splay. Poorly designed Makefiles or other build systems may not check for collisions, and will simply clobber (overwrite) files previous installed by another project. Most package managers now require that the project install target use DESTDIR, so that the package manager can safely perform a staged install under a temporary directory, and then use its own safe methods to copy the installed files to their final destination, while watching for collisions. A staged installation also allows the package manager to check for proper permissions and verify that the installation conforms to filesystem hierarchy standards. Makefiles do not need to set DESTDIR, but they should prefix all install destinations with it.

Note

We do not need a '/' between DESTDIR and PREFIX, since PREFIX should be an absolute path name, which already begins with one.

    # Wrong
    ${MKDIR} -p ${DESTDIR}/${PREFIX}/bin
    ${INSTALL} -c -m 0755 ${BIN} ${DESTDIR}/${PREFIX}/bin

    # Right
    ${MKDIR} -p ${DESTDIR}${PREFIX}/bin
    ${INSTALL} -c -m 0755 ${BIN} ${DESTDIR}${PREFIX}/bin
    
Practice

Note

Be sure to thoroughly review the instructions in Section 2, “Practice Problem Instructions” before doing the practice problems below.
  1. Which target in a makefile is checked first, if no target is specified in the make command?

  2. How do we ensure that the install target runs when specified, even if there is a file called "install" in the directory?