I use make in certain circumstances because it is extremely useful, but not often enough that I have memorized its intricacies. Here's one (for GNU make) that I always have to look up. (Although maybe now that I've noded it, it will be imprinted into my brain.) (It turns out I was also deluded about how make thinks, and surprisingly not in a way that affected the code. Thanks, OldMiner, for clarifying!)

If you use a makefile consisting of only a pattern rule, such as

%.o: %.c
	cc -c -o $@ $<

then calling make on its own won't do anything. You can manually specify the object files to make (make foo.o bar.o), but to have it work without arguments you need at least one non-pattern rule. You might think you could get away with this:

.PHONY: all
all: *.o

%.o: %.c
	cc -c -o $@ $<

The .PHONY line declares that the all rule doesn't refer to a file named all, and that it should always be run when it is invoked.

But the *.o only works if you already have the .o files. The cheap way to solve this is to compile by hand once, and then the rules above will work fine. However, your makefile will be broken if you ever clean out your .o files.

The real solution is to use this monstrosity:

.PHONY: all
all: $(patsubst %.c,%.o,$(wildcard *.c))

%.o: %.c
	cc -c -o $@ $<

wildcard returns a list of all .c files in the current directory, and patsubst performs a simple pattern-based replacement on the list, changing all ".c" to ".o". Thus the all rule depends on .o versions of all your .c files---whether you've got the .o files already or not! Problem solved, happy makeing.

See also the GNU make documention pages on phony targets and the wildcard function.