Things you should know how to do

The purpose of this tutorial is to ensure your ability to write a makefile to facilitate the testing and grading of your projects. We will look at a few topics.

Renaming files to match project specifications

When a project is assigned to you, we usually will specify the name of the program you are to create. For example, if you are building a parser, we may tell you that it must be named "parser" and that the main source file must be "parser.c". Sometimes, we change our minds about the names of the files, or don't come up with one until after you have started. ( Okay, sometimes we're just plain sloppy with our project specs.) Get used to it, this is life. Real customers and bosses will probably be even more idiotic in the changes they make, and usually aren't as good at specifying what they want in the first place. I'm not kidding, I've been there.

So, let's say that you have been building a parser from the file "myparse.c", and have been building an executable called "myparse". Your makefile may look something like this:


myparse: myparse.c support.o
	cc -o myparse myparse.c support.o

support.o: support.c
	cc -c -o support.o support.c

Now, the evil Randy comes along and says "I want your main project source file to be named `parser.c' and the executable to be named `fred'." Why? Because he is a petty, vindictive, and merciless TA, that's why. It doesn't matter if it makes no sense: the grader gets what he wants, or you get a 0.

You now have two choices:

  1. Panic. In which case Randy will just sit back and watch the show.
  2. Think about it, then change something.

I'm quite sure you have all had enough practice to handle the first option without any further instruction, so let's try the second. If we have written a decent makefile, we should be able to change the rules to use the new names.

The original makefile was:


myparse: myparse.c support.o
	cc -o myparse myparse.c support.o

support.o: support.c
	cc -c -o support.o support.c

The program needs to be called "fred" rather than "myparse", so we can simply change the rule that generates "myparse". In this rule we change the target so that "make" looks for "fred" rather than "myparse" when deciding if to build it. We also need to change the command to build "myparse" so that it builds "fred" instead. The new rule looks like this:

fred: myparse.c support.o
	cc -o fred myparse.c support.o

That was simple. Now we need to figure out how to handle Randy's idiotic decree about the name of our source file. Essentially, we must change "myparse.c" to "parser.c" everywhere it appears in the makefile. This isn't really that difficult either. In this example we only have two places where "myparse.c" is mentioned, both in the rule for what is now "fred":

fred: parser.c support.o
	cc -o fred parser.c support.o

Our new makefile looks like this:

fred: parser.c support.o
	cc -o fred parser.c support.o

support.o: support.c
	cc -c -o support.o support.c

Of course, you will have to rename the source file itself, which may cause other problems, but if you don't panic, and don't build overly complicated makefiles, you should be able to handle it.

For the record it is unlikely that we will have you change the name of a file on short notice. It has happened before though, so you should be able to handle the situation.

Let's look at another solution to the same problem. This time, we will add a rule to the makefile instead of changing the current rules. The original makefile was again:


myparse: myparse.c support.o
	cc -o myparse myparse.c support.o

support.o: support.c
	cc -c -o support.o support.c

We need to have the executable "fred" made, but there is no reason we can't make "myparse" instead and then rename it. So let's add a rule to do just that:

fred: myparse
	mv myparse fred

myparse: myparse.c support.o
	cc -o myparse myparse.c support.o

support.o: support.c
	cc -c -o support.o support.c

Now, when we build "fred", we actually build "myparse" then rename it to "fred". Easy enough. No panic necessary. We can do the same type of thing for "parser.c" and "myparse.c" by adding a rule that copies "parser.c" to "myparse.c":

fred: myparse
	mv myparse fred

myparse.c: parser.c
	cp parser.c myparse.c

myparse: myparse.c support.o
	cc -o myparse myparse.c support.o

support.o: support.c
	cc -c -o support.o support.c

Notice that we didn't move parser.c to myparse.c, we just have make copy it whenever we change parser.c. We still have to rename the source file from "myparse.c" to "parser.c" (because Randy said so, remember), but we don't have to search the entire makefile for each occurence of "myparse.c".

The last solution was inefficient though (from a filespace perspective), so we might try to use another tool that we have learned about: variables.

As we write the file, we could use variables to refer to the programs we wish to build and their sources. Suppose we use EXECFILE and SRCFILE to represent these files respectively. We would then have the following original makefile:


EXECFILE=myparse
SRCFILE=myparse.c

${EXECFILE}: ${SRCFILE} support.o
	cc -o ${EXECFILE} ${SRCFILE} support.o

support.o: support.c
	cc -c -o support.o support.c

Changing the file to build "fred" from "parser.c" only requires a change in the definition of the variables EXECFILE and SRCFILE:

EXECFILE=fred
SRCFILE=parser.c

${EXECFILE}: ${SRCFILE} support.o
	cc -o ${EXECFILE} ${SRCFILE}support.o

support.o: support.c
	cc -c -o support.o support.c

This is easy when first writing the makefile, and makes changes easier later, but is more work than using the first solution once the makefile is written without using the variables.
This page was last modified .