问题
The GNU make manual does not excel at explaining this part, I could not find the explanation or I could not infer the information elsewhere.
I realize % is a kind of wildcard, but what is the difference between % and * in the context of targets, dependencies and commands? Where can I use it and does it have the same meaning everywhere?
target: dependencies ...
commands
回答1:
The wildcard character * is used to simply generate a list of matching files in the current directory. The pattern substitution character % is a placeholder for a file which may or may not exist at the moment.
To expand on the Wildcard pitfall example from the manual which you had already discovered,
objects = *.o
simply assigns to the variable the rather useless literal value *.o -- an object file which presumably depends on a file named literally *.c which of course also does not exist. So you get an error, and/or erratic behavior.
The proper way to phrase that is something like
objects := $(patsubst %.c,%.o,$(wildcard *.c))
make itself performs no wildcard expansion in this context, but of course, if you pass the literal value *.o to the shell, that's when expansion happens (if there are matches) and so this can be slightly hard to debug. make will perform wildcard expansion in the target of a rule, so you can say
foo: *.o
and have it work exactly like you intended (provided the required files are guaranteed to exist at the time this dependency is evaluated).
By contrast, you can have a rule with a pattern placeholder, which gets filled in with any matching name as make tries to find a recipe which can be used to generate a required dependency. There are built-in rules like
%.o: %.c
$(CC) $(CCFLAGS) $^ -o $@
(approximating the real thing here) which say "given a file matching %.c, the corresponding file %.o can be generated as follows." Here, the % is a placeholder which can be replaced by anything; so if it is applied against an existing file foo.c it says how foo.o can be generated.
You could rephrase it to say * matches every matching file while % matches any matching file.
回答2:
Both % and * are ordinary characters in Make recipe lines; they are just passed to the shell.
% denotes a file "stem" in pattern substitutions, as in $(patsubst %.o,%.c,$(OBJS)). The pattern %.o is applied to each element in $(OBJS), and % captures the matching part. Then in the replacement pattern %.c, the captured part is substituted for the %, and a list of the substitutions emerges out of patsubst as the return value.
* is useful in the argument of the $(wildcard ...) operator, where it resembles the action of the shell * glob in matching some paths in the filesystem.
On the left hand side of a patsubst, where % denotes a match, it resembles * in that it matches some characters. However, % carries some restrictions, such as that it can only appear once! For instance whereas we can expand the wildcard */*.c, of course, we cannot have a double stem pattern substitution like $(patsubst %/%.o,%/foo/%.c,...). This restriction could be lifted in some future version of GNU Make, but it currently holds as far as I know.
Also there is a subtle difference between % and * in that % matches a nonempty sequence of characters. The wildcard pattern fo*o.c matches foo.c. The substitution pattern fo%o.c does not match foo.c, because then the stem % would be empty which is not allowed.
来源:https://stackoverflow.com/questions/34219186/what-is-the-difference-between-and-in-a-makefile