Lab 3 — Makefiles

Slides. How to compile a C program with multiple source code files with Make.

Live-coding examples

main.c

main.c is a C source code file that contains a function named main. Every C program requires one such function as an entry-point into the program. The third line includes the even.h header file with the definition for is_even. Header files are required to expose functions defined in one source file to other source files. In this example, including even.h in main.c makes the function is_even usable there, even though it is defined in even.c.

      #include <stdio.h>
#include "even.h"

int main() {
    int n = 5;

    if (is_even(n)) {
        printf("%d is even\n", n);
    } else {
        printf("%d is odd\n", n);   
    }     
}        
    

even.c

#include "even.h"

int is_even(int n) {
    if (n % 2 == 0) {
        return 1;
    } else {
        return 0;   
    }     
}
    

even.h

The first two lines and the last line are preprocessor directives that protect against the header being included multiple times in one file. #include is very simplistic: it just copies the contents of one file into another during compilation.

      #ifndef __EVEN_H__
#define __EVEN_H__

int is_even(int n);

#endif /* __EVEN_H__ */
    

Sequence of commands to create an executable

To compile the two .c files into an executable, I ran this sequence of commands to create the file program which can then be run with: $ ./program. The $ at the start of each line means that what follows is shell input, and if you're running this for yourself you wouldn't write the $.

      $ gcc even.c -c                 # -c compiles a .o object
      $ gcc main.c -c
      $ gcc main.o even.o -o program  # -o compiles an executable
    

Equivalent makefile

This makefile runs the equivalent of the commands above to compile main.c and even.c together into an executable.

# set the compiler and compiler flags
CC := gcc
CFLAGS := -Wall # -Wall means turn on all warnings

# compile prog from a list of object files
# if you have different source files, rename these
prog: main.o even.o
	$(CC) $(CFLAGS) $^ -o $@

# how to transform source files to object files
%.o: %.c
	$(CC) $(CFLAGS) $< -c

# clean up the directory. -f here makes rm not print
# an error if the file doesn't exist
.PHONY: clean
clean:
	rm -f *.o
	rm -f prog