When I was first learning how to write a Makefile to compile a C program, one
thing that stuck me (and almost everyone who encounters it) as odd was the
requirement that each command line start with a tab character
('\t'
). Makefiles are used to automate repetitive tasks (such as recompiling a
C/C++ program), and have a unique syntax. They are made up of rules, which
consist of a “target”, a list of “dependencies”, and a series of
“commands”. They look like this:
target: dependencies
command
For example, suppose I want to automate two different tasks: recompiling my program after editing some of the source code, and deleting all non-source files after editing them. I could write a Makefile that looks like this:
.PHONY: clean
myprogram: myprogram.c
gcc myprogram.c -o myprogram
clean:
rm *.o *~ myprogram
The .PHONY makes sure that when I run the shell command make clean
, I don’t
create a file named clean
. Instead, I run the command underneath, which
removes the files I don’t want in my directory. The other rule has a target
filename myprogram
, which requires a file named myprogram.c
. If it finds
this .c file in my directory, it will compile it using the command below. If you
want to learn more about makefiles and their syntax, a resource that I highly
recommend is Makefile Tutorial.
Notice how each command is indented with a tab character. The UNIX utility
make
doesn’t allow you to list a command underneath a target/dependency
combination, or to indent with a number of spaces. In the
“tabs vs. spaces” war, make
has
definitifely taken a side. Why is this?
The author of make
, Stuart Feldman, has explained this debacle a few times,
including
once to Michael Stillwell.
Stuart explained that make
was written in a weekend. To tokenize Makefiles, he
was using lex, which was in
its first version at the time. He got frustrated with trying to write a pattern
for commands, and instead used a fixed pattern ('\t'
) to indicate rules. After
a while, about a dozen people at Bell Labs were using make
. He didn’t want to
disrupt his users, and so left the “tab in column 1” rule in the UNIX command to
preserve backwards compatibility.
As he says in the email:
> Within a few weeks of writing Make, I already had a dozen friends who were
> using it.
>
> So even though I knew that "tab in column 1" was a bad idea, I didn't want
> to disrupt my user base.
>
> So instead I wrought havoc on tens of millions.
If you don’t want to begin your commands with '\t'
, different versions of
make
allow you to specify other characters. For example,
GNUMake
allows for a special variable, .RECIPEPREFIX
, where you can change the
character that make
assumes is introducing a recipe line. However, from
personal experience, this isn’t much help to someone who is trying to make a
binary file and keeps getting syntax errors!