nbro
nbro

Reputation: 15847

Understanding deeply using a specific case how makefiles are interpreted

I'm trying to understand deeply how makefiles work.

For example, I've the following one:

CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)


test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)


clean:
    rm -rf *.o test_int_array *.dSYM

The part that I really don't understand fully is :

...

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)


test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)

...

I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).

-o means to write the output to the specified file. Which file in this case?

I understood that $@ (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?

What does $< mean?

Could you please explain step by step how the make tool would interpret those two statements?

I think I understood this part more or less:

...
test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)

...

which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $@ from the $(OBJS) files on the right (stated using the option $^).

Is $(CFLAGS) needed in both cases? Does the order matter?

Upvotes: 3

Views: 110

Answers (2)

sokkyoku
sokkyoku

Reputation: 2221

In a Makefile, each rule follows this format:

resulting_file : source_files
  steps to get resulting_file from source_files

What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.


%.ext : %.ext2

is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.

%.c : %.o

is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)

This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.

Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96


You can find out about $@, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101

$@: the entire lefthand

$<: the first file in the righthand

$^: the entire righthand list of files, space separated.

Upvotes: 2

2501
2501

Reputation: 25752

In the example:

test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)

$@ is the filename of the target for this rule: test_int_array.

$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o


In the example:

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

$< is the name of the first prerequisite: %.c

$@ is the filename of the target for this rule: %.o


$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.

Upvotes: 3

Related Questions