Reputation: 13
I am learning more about makefiles and came across an example I don't quite understand. What is happening in make clean? It is forcibly removing all object files in /obj, but I am lost after that. I know it also removes the exe file, but how is that translated in the code?
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
../hellomake: $(OBJ)
gcc -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
Upvotes: 1
Views: 1902
Reputation: 85827
Let's look at the line
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
The first thing make
does is expanding the $(...)
variables, leading to:
rm -f obj/*.o *~ core /*~
The last part is likely a bug: INCDIR
is not defined, so it expands to nothing. Did you mean $(IDIR)
instead?
The second thing make
does is running the resulting line via /bin/sh -c ...
. The shell expands things like wildcards.
Let's assume the object files in obj
are hellomake.o
and hellofunc.o
. Then obj/*.o
becomes obj/hellofunc.o obj/hellomake.o
.
*~
matches all files in the current directory that end with ~
. Why would you have such a file? Because when you use emacs to edit a file foo
, it will leave a backup copy under foo~
by default. So this is intended to remove emacs backup files.
core
is what you normally get when you enable core dumps and a program you run crashes (and you're not using systemd). It can be used to debug the crash.
The last pattern looks like it was meant to match emacs backup files in INCDIR
, but because that's unset, it tries to find backup files in the root directory, /
. Normally there are no files at all in /
, let alone emacs backups.
If a pattern matches no files, the default behavior of the shell is to leave it unexpanded. So the last part (/*~
) is likely left as-is. Let's assume you have no backup files in the current directory either, so *~
is also left alone:
rm -f obj/hellofunc.o obj/hellomake.o *~ core /*~
This line runs rm
, passing it an array of strings as arguments:
{ "rm", "-f", "obj/hellofunc.o", "obj/hellomake.o", "*~", "core", "/*~" }
rm
(following convention) scans its arguments for strings beginning with -
, which it processes as options. In this case there's one option, f
. f
("force") tells rm
to not ask about files you don't have write permissions for; just delete them anyway. It also suppresses errors such as those you'd normally get for trying to delete non-existent files. (In particular, you probably don't have a file literally called *~
.)
So the whole thing deletes
obj/
core
in the current directory/
(which probably don't exist, and if they exist, you probably don't have permissions to delete)while ignoring any errors.
Upvotes: 6