Skip to main content

3. Macros in make

So far you have an existing Makefile that looks like it contains a lot of repetition. If you had a large number of source files, this could make creation and management of your Makefile a bit tedious. make gets around this by having a feature called macros. Macros are a bit like shorthand. A macro called, say, name is defined in the following general way:

 name = text string 

where subsequent references to the macro are made using

 $(name) 

or

 ${name} 

in this case, such references will be substituted by make for the actual text string. In the case of your example Makefile, you could introduce the following macros:

CC = /usr/bin/gcc
INCLUDE = -I.
objs = hellomain.o hellofunc.o
TMPDIR = /tmp/

In this case your new Makefile could take the form

CC = /usr/bin/gcc
INC = -I.
objs = hellomain.o hellofunc.o
DIR = /tmp/

myexecutable: ${objs}
   ${CC} -o myexecutable ${objs}
   mv myexecutable ${TMP}
hellomain.o: hellomain.c ${CC} -c hellomain.c
hellofunc.o: hellofunc.c ${CC} -c hellofunc.c ${INC}
clean: rm -f core myexecutable ${objs}

It does't seem as if this has simplified your Makefile, merely because you only have a few source files.

As with file names (as you found out in Section 1.3?), you should take care to not include any special characters in your macro names (such as < and \ for example).

useful aspect of macros is that they can be defined recursively. For example, the following set of macro definitions is entirely legitimate:

DIR = /tmp/
EXT = remote
FILE = ${DIR}/source.${EXT}

You can also define these macros in any order - so in the above example, you could have line 3 coming first, and make will still make the correct substitutions.

make has a number of helpful internal definitions. You can find extensive lists of these from books or websites - for the moment we'll focus on some common internal macros.

The internal macro $@ is interpreted as the current target. For example, we could substitute the entry where you build myexecutable such that it reads as

myexecutable: ${objs}
	${CC} -o $@ ${objs}
	mv $@ ${DIR}

The internal macro $? is interpreted as the list of pre-requisites that are newer than the current target. For example, we could substitute the entry where you build hellomain.o such that it reads as

hellomain.o: hellomain.c 
	${CC} -c $?
Putting it into practice
Edit your Makefile to include these two internal macros

Your Makefile should now read

# here are the macro definitions
CC = /usr/bin/gcc
INC = -I.
objs = hellomain.o hellofunc.o
DIR = /tmp/

myexecutable: ${objs}
	${CC} -o $@ ${objs}
	mv $@ ${DIR}
hellomain.o: hellomain.c ${CC} -c ${INC} $?
hellofunc.o: hellofunc.c ${CC} -c ${INC} $?
clean: rm -f core ${objs} myexecutable