Make (software) - Example Makefiles

Example Makefiles

Makefiles are traditionally used for compiling code (*.c, *.cc, *.C, etc.), but they can also be used for providing commands to automate common tasks. One such makefile is called from the command line:

make # Without argument runs first TARGET make help # Show available TARGETS make dist # Make a release archive from current dir

The makefile:

PACKAGE = package VERSION = ` date "+%Y.%m%d%" ` RELEASE_DIR = .. RELEASE_FILE = $(PACKAGE)-$(VERSION) # Notice that the variable LOGNAME comes from the environment in # POSIX shells. # # target: all - Default target. Does nothing. all: echo "Hello $(LOGNAME), nothing to do by default" # very rarely: echo "Hello ${LOGNAME}, nothing to do by default" echo "Try 'make help'" # target: help - Display callable targets. help: egrep "^# target:" akefile # target: list - List source files list: # Won't work. Each command is in separate shell cd src ls # Correct, continuation of the same shell cd src; \ ls # target: dist - Make a release. dist: tar -cf $(RELEASE_DIR)/$(RELEASE_FILE) && \ gzip -9 $(RELEASE_DIR)/$(RELEASE_FILE).tar

Below is a very simple makefile that by default (the "all" rule is listed first) compiles a source file called "helloworld.c" using the gcc C compiler and also provides a "clean" target to remove the generated files if the user desires to start over. The $@ and $< are two of the so-called internal macros (also known as automatic variables) and stand for the target name and "implicit" source, respectively. In the example below, $^ expands to a space delimited list of the prerequisites. There are a number of other internal macros.

CC = gcc CFLAGS = -g all: helloworld helloworld: helloworld.o # Commands start with TAB not spaces $(CC) $(LDFLAGS) -o $@ $^ helloworld.o: helloworld.c $(CC) $(CFLAGS) -c -o $@ $< clean: FRC rm -f helloworld helloworld.o # This pseudo target causes all targets that depend on FRC # to be remade even in case a file with the name of the target exists. # This works with any make implementation under the assumption that # there is no file FRC in the current directory. FRC:

Many systems come with predefined Make rules and macros to specify common tasks such as compilation based on file suffix. This allows user to omit the actual (often unportable) instructions of how to generate the target from the source(s). On such a system the above makefile could be modified as follows:

all: helloworld helloworld: helloworld.o $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ clean: FRC rm -f helloworld helloworld.o # This is an explicit suffix rule. It may be omitted on systems # that handle simple rules like this automatically. .c.o: $(CC) $(CFLAGS) -c $< FRC: .SUFFIXES: .c


That "helloworld.o" depends on "helloworld.c" is now automatically handled by Make. In such a simple example as the one illustrated here this hardly matters, but the real power of suffix rules becomes evident when the number of source files in a software project starts to grow. One only has to write a rule for the linking step and declare the object files as prerequisites. Make will then implicitly determine how to make all the object files and look for changes in all the source files.

Simple suffix rules work well as long as the source files do not depend on each other and on other files such as header files. Another route to simplify the build process is to use so-called pattern matching rules that can be combined with compiler-assisted dependency generation. As a final example requiring the gcc compiler and GNU Make, here is a generic makefile that compiles all C files in a folder to the corresponding object files and then links them to the final executable. Before compilation takes place, dependencies are gathered in makefile-friendly format into a hidden file ".depend" that is then included to the makefile.

# Generic GNUMakefile # Just a snippet to stop executing under other make(1) commands # that won't understand these lines ifneq (,) This makefile requires GNU Make. endif PROGRAM = foo C_FILES := $(wildcard *.c) OBJS := $(patsubst %.c, %.o, $(C_FILES)) CC = cc CFLAGS = -Wall -pedantic LDFLAGS = all: $(PROGRAM) $(PROGRAM): .depend $(OBJS) $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o $(PROGRAM) depend: .depend .depend: cmd = gcc -MM -MF depend $(var); cat depend >> .depend; .depend: @echo "Generating dependencies..." @$(foreach var, $(C_FILES), $(cmd)) @rm -f depend -include .depend # These are the pattern matching rules. In addition to the automatic # variables used here, the variable $* that matches whatever % stands for # can be useful in special cases. %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ %: %.c $(CC) $(CFLAGS) -o $@ $< clean: rm -f .depend *.o .PHONY: clean depend

Read more about this topic:  Make (software)