Compiling a source code files can be tedious, specially when you want to include several source files and have to type the compiling command every single time. That’s one of the reasons why I decided to look into Makefiles. It was a very fun task to learn about Makefiles. I’m writing this post as a short introduction to the Makefiles.

Makefiles are special format files that together with the make utility will help you to build and manage projects.

Comments

The comment is indicated by the comment character “#”.

Variables

Variables that are used in Makefiles may come from a large number of places; variables may be defined in the Makefile itself, or in Make’s large database of predefined variables, or in the command line invocation of Make, or within the environment. The following variables have special significance:

  • CFLAGS – gives a list of flags that should be passed to the C compiler
  • CPPFLAGS –  gives a list of flags that should be passed to the C/C++ preprocessor
  • CXXFLAGS – gives a list of flags that should be passed to the C++ compiler
  • LDFLAGS – gives a list of flags that should be passed to the linker.

Make defines variables for a variety of tools and utilities. The following variables are automatically defined by make:

  • CC – specifies the system’s default C compiler
  • CPP –  specifies the system’s default C preprocesor
  • CXX – specifies the system’s default C++ compiler
  • LD – specifies the system’s default linker.

Macros

A macro definition consists of a macro name, an equal sign “=”, and a macro value. Make replaces $(name) with the appropriate definition. Make automatically imports environmental variables as macros, so you can reference the environmental variable PATH with the expression $(PATH).

For instance: MACRONAME=value

Rules, Targets and Dependency List

A basic syntax of the Makefile can be seen on the Figure 1. A rule specifies when and how to remake targets. It lists the files that are prerequisites of the target, and commands to create or update the target. A target most of the time is a file to be created/updated. target depends upon a set of source files or other targets described in Dependency List. For each target, make checks the modification time of the corresponding dependency files to determine whether the target needs to be rebuilt using the corresponding command.

makefile_syntax

Figure 1: Makefile general syntax

The make process is recursive. Target’s sources are made before the timestamp comparison occurs. This means that file1 and file2 are made before their timestamps are compared with target.

Dependency Rules indicate that if any file to the right of the colon changes, the target to the left of the colon should be considered out-of-date. Pattern Rules are often used for compile-line.

Conventional Targets

By convention, every Makefile is expected to support the following targets:

  • all
  • clean
  • distclean

When make is invoked, it automatically builds the first target listed in the Makefile. This target should be named all and should depend on all other targets and/or build products the Makefile is producing. The clean target removes the result and any intermediate build products of invoking make all. The make distclean target does everything that make clean does, except that it may also remove additional configuration information.

Phony Targets

Sometimes target does not mean a file but it might represent an action to be performed. When a target is not related to a file it is called phony target.

For instance:
getobj:
    -mv obj/*.o . 2>/dev/null

getobj target moves all files with .o extension from obj directory to current directory – not a big deal. However, you should be asking yourself: “What if there is no file in obj?”. In that case the mv command would return an error that would be passed to the make command.

Note: make command default behavior is to abort the processing when an error is detected while executing commands in rules.

To avoid the make command from aborting when an error occurs you can use a special character – (minus) preceding the mv command. There is another special character: @ – tells make not to print the command to standard output before executing.

There is a special phony target called all where you can group several main targets and phony targets.

More special characters

$?   List of dependencies changed more recently than current target.
$@  Name of current target.
$<  Name of current dependency.
$*  Name of current dependency without extension.

An Example

# Macros
CC=g++
CFLAGS=-g -Wall
RM=/bin/rm -f

all: main                      # ensure that every feature of the program is compiled
frog.o: frog.h frog.cc         # create the object file for frog.cc
        ${CC} ${CFLAGS} -c frog.cc

main.o: frog.h main.cc         # create the object file for the main file
        ${CC} ${CFLAGS} -c main.cc

main: main.o frog.o            # create the executable
      ${CC} ${CFLAGS} -o main main.o frog.o

clean:                         # rule for cleaning files generated during compilations
      ${RM} *.o main
Advertisements