Make Tutorial: Part 2

9 08 2009

Colleges will be back in session in a month or two. When I first started school, I was forced to use Unix for all CS classes, but given very little instruction in it. Very “sink-or-swim”. I actually still have a page of notes where I wrote down basic commands, such as ‘ls’ and ‘pwd’, from a lecture given on the first day. After that first day, you were on your own. make

This same philosophy applied to our projects. Projects typically consisted of 5 or more files and it quickly became tedious to compile and link all those files by hand. We were given no hints to use Make to assist us. After discovering this tool, it greatly increased my productivity. Because of the gains I saw, I thought I’d write a few tutorials on using Make. Hopefully, it will help a beginning user to get accustomed with the tool and point them in the right direction to learn more.

This is Part 2 of my make tutorial.

Last time, I introduced you to the GNU Make tool and showed you some basic ways that it can speed up your development.

However, the techniques I covered were basic and static; if anything in your project changed, you had to manually edit your makefile quite a few times. In this tutorial, I hope to show you how to use make in more of a dynamic way and minimize the number of changes you have to make when changing your project.

First things first though. I expect that you have read and (at least somewhat) understand Part 1 of this tutorial. I’m not going to rewrite my first tutorial, but I will try to point out important points as needed.

So, what can you expect to get out of this tutorial? Here’s a list:

  • User created variables

Yes, only one bullet point (Why even use a list then?). Variables are a pretty broad topic so I’m going to use this tutorial just for them.

Variables are an important part of other languages, but you may be wondering how variables could ever be useful in something like Make. Well, you can find plenty of uses for them!

Here’s an example makefile for us to look at:

all: finalOutput

finalOutput: part1 part2 part3
	gcc -o finalOutput firstFile.o secondFile.o thirdFile.o

part1: firstFile.o
	gcc -c firstFile.cpp

part2: secondFile.o
	gcc -c secondFile.cpp

part3: thirdFile.o
	gcc -c thirdFile.cpp

	rm demo *.o

This makefile looks pretty reasonable, but let me ask you something. What if you want to add debugging information? You do this by adding the -g flag after any gcc command. That means you have to manually make 4 changes every time you want to switch modes. This will quickly get tedious as you won’t always want debug information, but sometimes you will.

The solution to this problem is to create a variable to store your flags and use that as needed. That way, if you want to change your flags you only need to make 1 change, rather than 4. Or even better, you can create a target to dynamically change the variables you’re working with, such as making a special ‘debug’ target. Let’s take a look at what I’m talking about.


all: finalOutput

debug: CFLAGS+=-g
debug: all

finalOutput: firstFile.o secondFile.o thirdFile.o
	gcc -o finalOutput *.o

part1: firstFile.o

part2: secondFile.o

part3: thirdFile.o

	rm finalOutput *.o

The first change is the ‘CFLAGS=’ and ‘CC=gcc’ lines at the top of the file. These are variable declarations. Note how CFLAGS is initially declared to be empty. That’s perfectly valid, since when using a variable, make simply does text substitution, so the variable just expands to blank space.

You may notice that nowhere in the makefile are the CFLAGS or CC variables actually type. This is because CC and CFLAGS are special variables that make uses when compiling C programs. For C programs, make will automatically run the command stored in the CC variable and pass it the flags in the CFLAGS variable. For C++, the equivalent variables are CXX and CXXFLAGS.

The debug target is interesting to look at, since it contains 2 lines. What this target does is add the -g flag to CFLAGS, which will include debugging information in the executable. It then runs the ‘all’ target and compiles as normal but with the new flags. Let’s look at this makefile’s output:

$ make debug
$ make debug gcc -g -c -o firstFile.o firstFile.c gcc -g -c -o secondFile.o secondFile.c gcc -g -c -o thirdFile.o thirdFile.c gcc -o finalOutput *.o $

Notice how the -g flag is now automatically included! It will not be present if you just run ‘make’ though.

Let’s take a look at how you can use variables to keep a list of your source files, making it even easier to keep track of your projects.

  1. Let’s delete the part1, part2, part3, and finalOutput targets completely.
  2. Create a variable, OBJECTS, and set it equal to all your object files.
  3. Now, add a dependency to the all target to the OBJECTS variable.

After doing that, your makefile will be much simpler and look like:

OBJECTS=firstFile.o secondFile.o thirdFile.o
all: $(OBJECTS)
        gcc -o finalOutput $(OBJECTS)

debug: CFLAGS+=-g
debug: all

        rm finalOutput *.o

Note the syntax to expand a variable is $(VARIABLENAME).
This makefile will produce the exact same results as the previous one, but this one is a whole lot easier to maintain, as I’m sure you can see. Now when you want to add a new file to your makefile, just change the OBJECTS variable.

You can view the files I used in this tutorial here. (Assuming the servers aren’t down of course.)

Originally, I planned to cover more topics in this tutorial, but I don’t want to overload you too much. There’s actually quite a bit more to using variables in makefiles, but this tutorial covered common uses for them. This should help get you started using variables in your programs. For more details, you can read the documentation.

Next time, I’m going to cover variables again, but a different kind of variable. This new type of variable will make your makefile even more dynamic and powerful. (Oooo, mysterious!)




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: