Building a Program

Suppose we want to build an executable program from two source files called myprog.c and math.c.

First, exactly one of the files must contain the main program. In C, this is the function called main().

To build the executable, we must first compile each source file to an object file using the -c flag. When compiling with -c, a file is compiled (translated to an object file containing machine code), but not linked with other object files or libraries to create a complete executable. Object files are not executable, since they only contain part of the machine language of the program. The object files have a ".o" extension. After building all the object files, they are linked together along with additional object files from libraries to produce the complete executable.

Using the Makefile below, make starts at the first rule it finds, indicating that myprog depends on myprog.o and math.o. But before running the link command, make searches the rest of the Makefile and sees that myprog.o depends on myprog.c and that math.o depends on math.c. If either of the ".c" files is newer than the corresponding ".o" file, then those rules are executed before the link rule that uses them as sources.

// math.h

int     square(int c);
// math.c

int     square(int c)

{
    return c * c;
}
// myprog.c

#include <stdio.h>
#include <sysexits.h>
#include <stdlib.h>
#include "math.h"

int     main(int argc,char *argv[])

{
    int     c;
    
    for (c = -10; c < 10; ++c)
        printf("%d ^ 2 = %d\n", c, square(c));
    return EX_OK;
}

# Makefile

# Link myprog.o, math.o and standard library functions to create myprog.
myprog: myprog.o math.o
        cc -o myprog myprog.o math.o -lm

# Compile myprog.c to an object file called myprog.o
myprog.o: myprog.c
        cc -c myprog.c

# Compile math.c to an object file called math.o
math.o: math.c
        cc -c math.c

Caution

Do not explicitly set the compiler to clang or gcc. Doing so renders the Makefile non-portable. Every Unix system has a cc command which is usually the same as clang or gcc, depending on the specific operating system.

Addendum: The book contains some examples using gcc explicitly. At the time the book was written, it was a common practice to install gcc on commercial Unix systems and use it instead of the native cc compiler. This is no longer common.

Running make with this Makefile for the first time, we will see the following output:

shell-prompt: make
cc -c myprog.c
cc -c math.c
cc -o myprog myprog.o math.o
    

If we then edit math.c, then it will be newer than math.o. When we run make again, we will see the following:

shell-prompt: make
cc -c math.c
cc -o myprog myprog.o math.o
    
Practice

Note

Be sure to thoroughly review the instructions in Section 2, “Practice Problem Instructions” before doing the practice problems below.
  1. Show the compiler commands needed to build an executable called calc from source files calc.c and functions.c.

  2. What C compiler command should usually be used by default in a makefile? Why?

  3. How does make know when a source file needs to be recompiled?