在Makefiles中遍历列表?

我发现我正在写很多Makefile,可以使用n -tuple清单来清理。 但我找不到任何方法来正确(干净地)做到这一点。 到目前为止,我只能使用$(shell …)trsed或其他非Makefile标准。

例如,我想这样做:

XYZs = \ dog.c pull_tail bark \ duck.c chase quack \ cow.c tip moo all: @- $(foreach XYZ,$(XYZs), \ $(CC) $X -o bully/$Y ; \ ln bully/$Y sounds/$Z ; \ ) 

有没有一种很好的方式来重复Makefiles中的n -tuple列表? 谢谢!

Makefiles在本质上基本上是声明性的,所以我不认为自己提供了你想要的。 但是,您似乎想要将某些字符串值与特定目标相关联,因此GNU make的目标特定变量值特性可能会很有用。 这是手册的摘录:

目标特定的变量还有一个特殊的特征:当你定义一个特定于目标的变量时,这个变量值对于这个目标的所有依赖也是有效的(除非那些依赖用自己的特定于目标的变量值覆盖它)。 举个例子,像这样的陈述:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

将在prog的命令脚本中将CFLAGS设置为-g ,但是它也将在创建prog.o,foo.o和bar.o的命令脚本中以及任何创建其依赖关系的命令脚本中将CFLAGS设置为-g

如果你还没有读过它,GNU make手册是非常好的。

编辑:做你在你的评论中问:

 dog: ANIMAL=dog.c BULLY=pull_tail SOUND=bark 

使用:

 dog: ANIMAL=dog.c dog: BULLY=pull_tail dog: SOUND=bark 

感谢提示 – 在一些黑客攻击之后,我认为这更多是我所希望的:

 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 ; \ ) 

谁能做得更好?

我会在foreach上检查GNU Make手册。 这里有一些随机剪辑,我用在一个不同的项目…这个例子是不完整的,但也许会给你一些想法? 如果我有更多的时间,我可能会清理它。

 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 

我所知道的都不是,但是那是因为你试图强制让工作成为一种命令式的语言,那当然不是这样。

在GNU中,你可能会想要做一些事情:

 pull_tail : SOUND=bark pull_tail : dog.c $(CC) $< -o $^ ln $@ $(SOUND) chase : SOUND=quack chase : duck.c $(CC) $< -o $^ ln $@ $(SOUND) ... 

或者更好的是,重新定义.c文件的默认规则来处理你的链接,但是你的名字的奇怪结构(程序名与源名没有词汇关系)使得这很难。

如果您希望能够在不进行大量手动编辑的情况下快速重新编译,您可能需要编写一个脚本来重新生成数据的makefile分层,并使用GNU make的include功能。

你正在倒退。

你正在试图把它看成是一个脚本。 这不是,而是它的一套关于如何创建X给定Y的规则。然后,make引擎计算出要得到结果需要做什么。

对于给出的例子,你真的应该使用一个脚本的生成步骤。 也许是从make来的,但是让我们来处理一下CC的东西吧。

您可以使用与默认规则相同的扩展名的文件来编译每个c文件到o 。 当然你不限于任何特殊的文件扩展名。 要编译一组.c文件,你可以这样做:

 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 $<