Understanding Makefile with .c=.o and $<

First of all, your Makefile has a bug, it does not make the intended targets. Did you try it?

Second, it is not well written; not following best current practices.

So I will first show you the better version of your Makefile, both correct, as well as written with the best practices:

CFLAGS := -Wall -Werror -std=

SRCS := program_1.c \
    program_2.c \
    program_3.c

OBJS := ${SRCS:c=o} 
PROGS := ${SRCS:.c=}

.PHONY: all
all: ${PROGS}

${PROGS} : % : %.o Makefile
    ${CC} $< -o $@

clean:
    rm -f ${PROGS} ${OBJS}

%.o: %.c Makefile
    ${CC} ${CFLAGS} -c $<

Now, the answers to your questions are:

${SRCS:.c=.o} means, take the variable value ${SRCS}, which is a string composed of words separated by spaces, and for each word, replace the suffix .c with .o . I dropped . in my code because it is not needed and it is common to replace only suffixes after the dot.

This syntax is similar to bash string suffix replacement (for one word) if you are familiar with that.

$< when used in the "recipe", means "the first prerequisite" - the first thing after the : in the line above.

and the last question is no longer relevant: .o.c syntax is obsolete and not recommended currently.

Please take a look at my "10 Commandments" - my answer at this post:

makefile enforce library dependency ordering

, they will give you an idea about the best practices. Then you can also read up in the GNU Make manual, about the terms above in quotes, that I did not explain here.


You didn't specify exactly which variant of make you're using -- there are many. I'm going to assume you are using GNU make, the most widely used variant.

In GNU make, $(SRCS:.c=.o) is a substitution reference, and it means "the value of the SRCS variable, where .c is replaced by .o when it appears at the end of a word." In your example, SRCS has the value program_1.c program_2.c program_3.c, so $(SRCS:.c=.o) means program_1.o program_2.o program_3.o.

The .c.o is an example of what's known an old-fashioned suffix rule. It tells GNU make "here's how to build a .o file from a .c file with the same name." The modern equivalent is a pattern rule which would look the same except to use %.o: %.c in place of .c.o.

Finally, $< is an automatic variable which means "the name of the first prerequisite".

Tags:

C

Makefile