Beyond Syntax

Looking beyond syntactical meaning

A Quick Introduction to Makefiles

Today at the Marquette Student ACM meeting, I gave a short presentation (PDF) about development on Linux. Specifically using Makefiles. As promised I have uploaded it to this site and I will give a little more information in this post.


The two main types of variables in a Makefile are "recursively expanded" (=; equal to) and "simply expanded" (:=; set equal to---thanks Algol). Recursively expanded is by far the most common and, realistically, the most confusing. This form of a variable will not perform the substitution until the last possible moment (lazy evaluation), so if you have the line SOURCES = ${CONFIG} demo.c, make will remember that you use ${CONFIG} until it must be known. So if the value of CONFIG changes, the newest version of CONFIG will be used when it is evaluated. Simple expansion occurs when the variable is declared (eager evaluation), if another variable (CFLAGS) is referenced in a simply expanded declaration it will be replaced with the current value of CFLAGS.


A target occurs on the left-hand side of a rule, typically this is the name of the file you want to build. There are special cases of this, most commonly, "clean". Usually when someone wants to "make clean" they want all the object files generated from a previous make to be removed. However, if you were to create a file named "clean" the rule would never execute because the file clean is up-to-date. This can be remedied with by a PHONY target.

.PHONY: clean
    rm -f *.o

This creates a phony target that depends on clean, which tells make to ignore any files named clean.

More on Variables

The important "automatic" variables are talked about in the presentation ($@, $<, $^, $+, and $?). Also useful is the % expansion variable. For example, if there was the rule %.o: %.c in a Makefile, this will tell make that to make any file ending in .o will depend on the same file ending in .c (i.e. a rule foo.o: foo.c automatically exists). This will then execute the same commands (say gcc -m32 -Os -o foo.o foo.c) for all files ending in .o. This is a perfect example of why using automatic variables is a great idea.

Well, I think that is everything I have to say about Makefiles in a short amount of time. If you have any questions please feel free to post in the comments. I'll try my best to answer them promptly!

(While most of the content here is off the top of my head, I did reference the GNU make page. They have everything you wanted to know about make.)