可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I find I'm writing a lot of Makefiles that could be cleaned up with the use of n-tuple lists. But I can't find any way to do this properly (and cleanly). So far I've only been able to come up with using $(shell ...) and tr, sed, or otherwise non-Makefile standards.
For example, I'd like to do this:
XYZs = \
dog.c pull_tail bark \
duck.c chase quack \
cow.c tip moo
all:
@- $(foreach X Y Z,$(XYZs), \
$(CC) $X -o bully/$Y ; \
ln bully/$Y sounds/$Z ; \
)
Is there a good way to iterate n-tuple lists in Makefiles? Thanks!
回答1:
Makefiles are essentially declarative in nature, so I don't think that make itself provides what you want. However, you seem to be wanting to associate some string values with specific targets, so maybe the Target specific variable values feature of GNU make will be of interest. This is an extract from the manual:
There is one more special feature of
target-specific variables: when you
define a target-specific variable,
that variable value is also in effect
for all dependencies of this target
(unless those dependencies override it
with their own target-specific
variable value). So, for example, a
statement like this:
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
will set CFLAGS
to -g
in the command
script for prog
, but it will also
set CFLAGS
to -g
in the command
scripts that create prog.o, foo.o,
and bar.o, and any command scripts
which create their dependencies.
If you haven't already read it, the GNU make manual is pretty damn good.
Edit: To do what you asked about in your comment:
dog: ANIMAL=dog.c BULLY=pull_tail SOUND=bark
use:
dog: ANIMAL=dog.c
dog: BULLY=pull_tail
dog: SOUND=bark
回答2:
I'd check the GNU Make manual on foreach. here are some random snips that I've used in a different project... the example is incomplete, but maybe it will give you some ideas? I might clean this up later if I've got more time...
REMAKE_PROGS:= dog duck cow
XYZs = \
dog.c pull_tail bark \
duck.c chase quack \
cow.c tip moo
$(foreach src, $(XYZs), $(eval $MAKE $(src))
$(REMAKE_PROGS):
@echo "\n# === $@ linking\n"
$(call compile,$@,$(OBJS_$@),$(CXX),$(MPICXX),$(LDFLAGS) $(LIBS) $(SYSLIBS) $(OTHER_LIB) $(EXTRA_LD_FLAGS))
@echo "\n# --- $@ compiled\n"
define compile
@mkdir -p $(dir $(1))
$(if ${ANNOUNCE},@echo "\n# +++ ${MAKECMDGOALS} compiling\n" $(eval ANNOUNCE=))
$(call compiler,$(1),NOMPI,$(3),$(4))
$(eval MY_FLAGS=$(FLAGS_$(1)) $(5))
$(if $(filter %xlf %xlf90,$(COMPILER_$(1))),$(eval MY_FLAGS:=$(MY_FLAGS:-D%=-WF,-D%)))
$(strip $(COMPILER_$(1)) $(2) $(MY_FLAGS) -o $(1) )
endef
回答3:
Thanks for the hints -- after some hacking I think this is more what I was hoping for:
XYZs = \
dog.c:pull_tail:bark \
duck.c:chase:quack \
cow.c:tip:moo
all:
@- $(foreach XYZ,$(XYZs), \
$(eval X = $(word 1,$(subst :, ,$(XYZ)))) \
$(eval Y = $(word 2,$(subst :, ,$(XYZ)))) \
$(eval Z = $(word 3,$(subst :, ,$(XYZ)))) \
\
$(CC) $X -o bully/$Y ; \
ln bully/$Y sounds/$Z ; \
)
Can anyone do better?
回答4:
None that I know of, but that is because you're trying to force make to work ans an imperative language, when that is not what it is.
In GNU make you'd probably want to do something like:
pull_tail : SOUND=bark
pull_tail : dog.c
$(CC) $< -o $^
ln $@ $(SOUND)
chase : SOUND=quack
chase : duck.c
$(CC) $< -o $^
ln $@ $(SOUND)
...
Or better yet, redefine the default rule for .c files to handle the linking for you, but the strange structure of your names (the program names don't have a lexical relationship to the source names) makes that hard.
If what you want to be able to rebuild this quickly without an lot of hand editing, you probably want to write a script to regenerate the makefile framgment from data and use the include
feature of GNU make...
回答5:
You're doing it backwards.
You're trying to treat make like it's a script. It's not, instead its a set of rules on how to create X given Y. Then the make engine figures out what needs to happen to get that result.
For the example given, you really should be using a script for the generation steps. Perhaps calling that from make, but let make handle the CC stuff.
回答6:
You can use default rules for a set of files with the same extension as in for compiling each c
file to an o
. Of course you are not restricted to any special file extensions. For compiling a set of .c
files you could do it like this:
OBJS = foo.o bar.o baz.o
OUT = myprog
all: $(OBJS)
$(SILENT) echo "LD $@"
$(SILENT) $(CPP) -o $(OUT) $^ $(LDFLAGS)
%.o: %.c
$(SILENT) echo "CC $<"
$(SILENT) $(CC) $(CCOPTS) -o $@ -c $<