Originally published by Robert Beisert at fortcollinsprogram.robert-beisert.com

Linux + C – Make

Compiling your program is easy when you’re working with one source and the standard libraries, but it gets more complex as you go along. That’s why God put “make” on this earth.

The First Makefile

…was created alongside the Earth. Every other makefile is derived from a previous one.

Jokes aside, the make program reads a makefile script to manipulate files and generate calls to your chosen compiler. The format for makefiles is similar to the format for bash scripting, with some subtle variations.

The key elements of a makefile are:

  • Environment Variables – These store sections of code or names of files
  • Tags – These store sections of code to perform
  • default Tag – This tag instructs make to perform a standard operation when called (assuming no other commands called)
  • clean Tag – This tag contains a simple script to undo all the work performed by the default operation

Note: The default name for a makefile is Makefile. If you want to use a different name, you will have to call it like this:

make -f File_Name

An Example: Makefile

It’s very difficult to explain, but reasonably easy to demonstrate. Assuming you’ve been keeping up with the code thus far, this makefile will build all of our sources in one go.


#The Compiler we will use
CC=gcc
#The flags we pass to the compiler
#    -g    Compile with debugging flags
#    -Wall    Compile and throw all warnings
CFLAGS=-g -Wall
#If we were using a set of libraries (OpenSSL, for example), we'd have something here
#LIBS=

#An Environment Variable with all the function names
ALL=ae ap args bad_malloc char_string do_math file_io helloworld input linked_list llt loop new_record point precomp

#If we don't call anything special, build all
default: $(ALL)

#The format for this is a bit particular
# ae:        The final name of the program (matches a name in ALL)
# array_eg.c    The source(s) from which we build this program
# $(CC)        Start the command with the contents of the variable CC
# $(CFLAGS)    Next part of the command is found in the contents of the variable CFLAGS
# -o        gcc tag -o, meaning that the next word of the command is the function name
# $@        Get the name of the tag (in this case, ae)
# $^        Get the source(s) from the line above (in this case, array_eg.c)

ae: array_eg.c
$(CC) $(CFLAGS) -o $@ $^

ap: arr_point.c
$(CC) $(CFLAGS) -o $@ $^
args: args.c
$(CC) $(CFLAGS) -o $@ $^
bad_malloc: bad_malloc.c
$(CC) $(CFLAGS) -o $@ $^
char_string: char_string.c
$(CC) $(CFLAGS) -o $@ $^
do_math: do_math.c
$(CC) $(CFLAGS) -o $@ $^ -lm
file_io: file_io.c
$(CC) $(CFLAGS) -o $@ $^
helloworld: helloworld.c
$(CC) $(CFLAGS) -o $@ $^
input: input.c
$(CC) $(CFLAGS) -o $@ $^
linked_list: linked_list.c
$(CC) $(CFLAGS) -o $@ $^
llt:linked_list_two.c
$(CC) $(CFLAGS) -o $@ $^
loop: loop.c
$(CC) $(CFLAGS) -o $@ $^
new_record: new_record.c person_record.c
$(CC) $(CFLAGS) -o $@ $^
point: pointer_one.c
$(CC) $(CFLAGS) -o $@ $^
precomp: precomp.c
$(CC) $(CFLAGS) -o $@ $^

#When we say "make clean", this will remove all the files so we can recompile from scratch
#These are basic commands
clean:
-rm -f *.o
-rm -f $(ALL)

Using make looks something like this (click for enlarged view):

When we call "make clean", we remove all the compiled programs we created. That's very important if we want to recompile them.
When we call “make clean”, we remove all the compiled programs we created. That’s very important if we want to recompile them.

 

When we call "make", it generates all the compiler commands we wanted.
When we call “make”, it generates all the compiler commands we wanted.

 

When we're done, all the files are back!
When we’re done, all the files are back!