Projects and Makefiles

Chris Riesbeck
Last updated: July 3, 2009

Real programs, even the simple ones we do in introductory EECS courses, are built by compiling multiple source files and linking in multiple library files. While you can do this in one long call to gcc, it's pretty tedious and error-prone to have to type out such things. Furthermore, most of the time, when you have several source files, only a few need to be recompiled, so compiling all of them is a waste of time.

This is why make was invented. make is a program that lets you specify in a text file, usually called Makefile (note the capitalization), exactly how to build an application.

In an integrated development environment (IDE) for C++ or Java or C#, the corresponding concept is usually called a project. You specify in the IDE what files are in the project, what libraries and compiler switches to use, and so on. Internally, the IDE creates either a makefile, or something equivalent to a makefile. The build command in an IDE is the equivalent of calling make in Unix. A similar modern utility is Ant. Ant is very often used in Java application development.

The syntax of Makefiles developed over time to handle many different tasks involved in compiling and deploying large applications. Common repeated activities were given shorthand notations. These can make Makefiles very compact but cryptic.

The NU EECS Magic Makefile

To simplify the use of Makefiles in introductory courses in C++, I made the NU EECS Magic Makefile. Put this file, with the name Makefile -- no extension! -- in a directory with C++ code, i.e., .h and .cpp files. Then, in a terminal shell window, cd to that directory and type make.

For example, if the directory geometry contains several C++ files that are needed to make an application, then

The Magic Makefile assumes you have installed the UnitTest++ library in /usr/local. If you don't have UnitTest++, open Makefile in a text editor, and change these lines

CFLAGS = -c -g -Wall -I/usr/local/include
LDFLAGS = -L/usr/local/lib/UnitTest++
LIBS = -lUnitTest++


CFLAGS = -c -g -Wall

If you have other libraries you want to include, add them to the above three lines.

The Magic Makefile has two other handy options. First, to create a Zip file of your source file, suitable for handing in:

make handin

This will create a fresh Zip file, e.g., and print out what's in it, so that you can make sure there's no junk.

Finally, sometimes you can get spurious compiler errors because of leftover old code. To remove all compiled output and leave just your source:

make clean

For more about make, see these helpful links.


When debugging Makefile's, the following two flags can be handy:

Therefore, an easy way to "dry run" a Makefile is to type:

make -B -n

This will show the commands that the Makefile will do to build a project from scratch.


Make sure that all indented command lines start with a tab character. This is the single most common problem with makefiles. If the indented lines start with spaces, make will mis-interpret them.

In any other file, e.g., source code, avoid tab characters. Turn them off in your editor. There is no standard amount for indenting a line with a tab character. It depends on the setting of the editor. Some emailers erase tab characters. Nicely laid out code with tab characters will most likely be an unreadable mess when looked at by someone else.

Comments? comment icon Let me know!

Valid HTML 4.01 Transitional