Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between %.c and *.c in GNU Make

What is the difference between %.c and *.c in makefiles. For example we may have:

vpath %.c    $(BASE_DIR)platform/$(TARGET)

and

Files += $(wildcard *.c) 

Both include all the files in certain directory which end with .c to be take into account. But when we use %.c and when *.c? In other words why I can't use

vpath *.c    $(BASE_DIR)platform/$(TARGET)

instead of

vpath %.c    $(BASE_DIR)platform/$(TARGET)

?

Thank you.

like image 804
Radoslaw Krasimirow Avatar asked Jul 27 '15 12:07

Radoslaw Krasimirow


2 Answers

Both % and * in GNU Make can be regarded as wildcards, but in a very different way.

The * character is what the GNU Make manual calls a wildcard: it represents a glob match, a pattern match against files present on the file system. E.g. *.a expands to the list of files present in the current directory whose names end in .a, or to literal *.a if no such files exist.

For example:

sh> rm -f *.a *.b *.c
sh> cat Makefile 
all: *.a

*.a : *.b *.c
        @echo $+ > $@
sh> make
make: *** No rule to make target '*.b', needed by '*.a'.  Stop.
sh> touch x.a
sh> make
make: *** No rule to make target '*.b', needed by 'x.a'.  Stop.
sh> touch y.b
sh> make
make: *** No rule to make target '*.c', needed by 'x.a'.  Stop.
sh> touch z1.c z2.c
sh> make
sh> cat x.a
y.b z2.c z1.c

As you can see, * is interpreted by matching it against the files that happen to exist in the file system. For instance, make interprets *.a as the literal filename *.a until I create files with a names ending in .a, at which point it expands to the names of those files; the same for *.b and *.c.

So use * only if you really want to specify a set of files already present on your file system. This is common for source files (prerequisites in the rules) but it is really weird to use it in targets of rules, like in this example.

The % character also performs pattern matching, but in a very different way: when used on both sides of the :, it is part of a pattern rule, and it states a relationship between the names of the target file(s) and the names of the dependencies.

For example:

sh> rm -f *.a *.b *.c
sh> cat Makefile
all: %.a

%.a : %.b %.c
        @echo $+ > $@
sh> make
make: *** No rule to make target '%.a', needed by 'all'.  Stop.
sh> touch x.a y.b z1.c z2.c
sh> make
make: *** No rule to make target '%.a', needed by 'all'.  Stop.
sh> make x.a
make: Nothing to be done for 'x.a'.
sh> make y.a
make: *** No rule to make target 'y.a'.  Stop.
sh> touch y.c
sh> make y.a
sh> cat y.a
y.b y.c

The % character is never matched against files on the file system, but instead expresses a correspondence between the target and prerequisite filenames: %.a: %.b %.c means: you can use this rule to make any file whose name ends in .a from files whose names are the same except that they end in .b and .c. So we can make x.a using this rule from x.b and x.c, but never from y.b or z1.c, and this is true even when x.b and x.b do not yet exist, as long as they, too, can be made (although this example doesn't show that). If not, GNU Make will (confusingly) behave as if the rule doesn't exist, as you can see in the example.

like image 97
reinierpost Avatar answered Jan 01 '23 08:01

reinierpost


Both the % and * in GNU Make are wildcard functions. The difference between them is that % can be used as part of a Text Substitution Function whereas * cannot.

If you are trying to make the fastest possible makefile, you should try and use the * Wildcard Function in preference to the % Substitution Function as there should be no resources used to store the name of the matched item and substitute it into a subsequent function call. If you are not that bothered about optimising your make system to the limit, you do not need to worry much about which one you choose.

like image 26
TafT Avatar answered Jan 01 '23 10:01

TafT