Lab 5 — Using the “make” Facility

Wednesday, December 3, 2008

Objective

·        To learn to create makefiles and to use the make command of Linux and Unix.

Your lab assignment this week should be turned in as part of Homework 4 on Friday, December 5, 2008.

Introduction

This week’s lab introduces an important tool:– the make command. This allows you to easily maintain and keep your files up to date when you are working on a project that is split across several .c files and their associated .h files. You will find your multi-file programs easier to manage if you keep all of the files for one project in a directory and create a makefile, as described below, to manage the compilation of the files.

The file makefile is the usual input file for a tool called make that can be invoked from the command line of a Linux shell. The purpose of make is to help you build, update, and maintain a collection of related program files. It does this by figuring out which files have changed since you last built or rebuilt your programs. It keeps track of dependencies among files, so that it knows which have to be recompiled as a result of any changes you make.

A properly designed makefile is generally a requirement of every non-trivial programming project in Linux or Unix, whether at WPI or in the professional world. It allows someone else — a grader, a boss, a colleague, or a user — to rebuild your system in another situation by simply typing the command make. Using the instructions and dependencies encoded in the makefile, make takes care of it from there, and the result should be an executable copy of the program, system, or application. (Equivalent tools are available in Visual Studio and other integrated development environments.)

Getting Started

1.      Sign the attendance sheet.

2.      Create a directory to hold the files for Lab 5, and change to that directory now. Use the following command to copy the files for this Lab into your directory:–

            cp /cs/cs2301-b08/labs/lab5/* .      

Your directory should now contain the files intarray.c, intarray.h, sinewave.c, and makefile.

What’s in a Makefile?

The collection of files needed to build a system or application usually contains header files (.h files), source files (.c files or source code files for the language you are using), compiled files (.o files), and sometimes other kinds of files. Many of these depend on each other. For example, consider the sinewave program for this week’s lab. The final product is an executable file named sinewave, which is created by linking together two other compiled files, sinewave.o and intarray.o. The two compiled files are created by compiling sinewave.c and intarray.c (both of which use the header file intarray.h). So, one of the dependencies expressed in the makefile is:–

      if sinewave.c or intarray.h changes, then sinewave.o must be regenerated by giving the compiler command:–

gcc -Wall -c -g sinewave.c

To see this dependency, open up the file named makefile in emacs or your favorite editor.

Near the bottom of the file you’ll find these two lines:–

sinewave.o: intarray.h sinewave.c
        gcc -Wall -c -g sinewave.c

The first of these is called a target line, which begins with a file name and a colon. After the colon is a list of zero or more file names. Here’s how to interpret the target line:– The file before the colon (called the target file) depends on the files after the colon. Whenever one of the files after the colon changes, the file before the colon becomes “out of date.” The make tool uses the target line and the last modification dates of the files to determine whether the target file must be rebuilt.

Note: make depends upon a consistent and reliable clock in order to determine whether one file is “newer” than another. If you are using more than one computer and their clocks are not in sync, modification dates on files could be inconsistent with each other, and make could produce unexpected results.

After the target line, there is a series of commands that tell exactly how to rebuild the target file. For the case of sinewave.o, only one gcc command is needed to compile the file. Note that this command includes the -c flag to indicate that gcc should only compile the file(s) in its command line and not attempt to link them into an executable program yet. The gcc command also includes the -g flag in case we need to use the debugger.

Note: There is one other peculiar requirement of makefiles:– command lines, such as the gcc command, must each begin with a tab character, not with 8 spaces!

As a second example of a dependency, the executable file sinewave is created by linking together the object files intarray.o and sinewave.o. If either of these two object files should change, then sinewave also needs to be recreated. Here is the appropriate target line and command from our makefile:–

sinewave: intarray.o sinewave.o
        gcc -Wall -g sinewave.o intarray.o -o sinewave

This target line says that if either sinewave.o or intarray.o is newer than the target file sinewave, then make must cause the sinewave program to be regenerated with the gcc command shown.

Using Make

There are two simple ways to use the make facility to automatically regenerate your files. The first approach builds a specific file. For example, suppose you want to regenerate intarray.o. Then you can use the make command shown here. Type this command in now:–

make intarray.o

The make command will find the dependency information in the makefile. It sees that intarray.o depends on two other files, so it will first ensure that those files are present and regenerate them if necessary. In this example, the two files intarray.h and intarray.c are necessary for generating intarray.o. These two files are present, so the make command proceeds to generate intarray.o, using the gcc command that is specified in the makefile. When the gcc command is executed, it is displayed on the screen, so you will see this appear on the screen:–

gcc -Wall -c -g intarray.c

After this command finishes, you should list the files in your directory, where you will find the object file intarray.o is now present.

You may also use the make command without specifying a file, like this:–

make

Without a specified file, the make command will regenerate the first target that it finds in makefile. Try this now, and you will see that the executable file sinewave is regenerated, since sinewave is the first target file in makefile. During the process of regenerating the sinewave file, make discovers that sinewave depends on intarray.o and on sinewave.o. But the file sinewave.o is not present. So, before make can build sinewave, it must first regenerate sinewave.o. Only then it can proceed to regenerate the executable file sinewave. On the screen you will see the two steps displayed:–

gcc -Wall -c -g sinewave.c

gcc -Wall -g sinewave.o intarray.o -o sinewave

Next, edit the file intarray.h in some trivial way, for example, by adding or changing a comment. Now type the command

make

again and you will see that it rebuilds everything. Can you explain why?

Cleaning up

Notice the last two lines of the makefile. These say

clean:
        rm -f sinewave.o intarray.o sinewave

This is a target line to “make” the target called clean. You can see that clean does not have any dependencies, but it does have one command line, namely a command to remove the .o files and the original target sinewave. This is common practice in system programming — to provide a way of cleaning up intermediate files (in this case the .o files) needed to build a system, leaving only the original files.

Type the command

make clean

and then list your directory. You will see that sinewave and the .o files have disappeared. Now type

make

and you will see that they have been rebuilt.

Using make from within Emacs

If you use emacs as your editor, you can edit and compile from within emacs. For example, make a small edit in one of the .c or .h files, and then give the emacscompile” command by typing

ALT-x compile <ENTER>

This causes emacs to issue the “make –k” command in the current directory. The -k tells make to continue as much as possible after an error. The make program realizes that one of the source files has changed and proceeds to rebuild it as if you had invoked make yourself.

This feature is not available in other editors such as kwrite, vi, or pico. However, something equivalent is available in integrated development environments such as Visual Studio and Eclipse.

Getting Credit for this Lab

Nothing needs to be turned in today. Simply sign the attendance sheet.

However, to get credit for this lab, you should construct and submit a makefile for Homework 4 which is due on Friday. The easiest way to do this is to copy the makefile from this assignment and to edit the dependencies to conform to the files of your homework project.

The graders will attempt to build your homework project by downloading your files to a sub-directory and then typing make.

See you next week!