What is the difference between % and * in a makefile

[亡魂溺海] 提交于 2019-12-14 00:48:00

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!