对于Makefile变量的每个目标

3

我有一个看起来像下面这样的makefile

apps = app1 app2 app3

all: dir app1 app2 app3 zip cleanup

现在我想在apps变量列表上进行一些循环操作,

类似于

`loop on apps

endloop`

在Makefile中可以对变量列表进行循环操作,需要循环遍历apps变量列表。

更新

假设这个变量(apps)是由我的程序在make文件中生成的,为每个项目提供了不同的apps值,有时候是apps= app1 app2,有时候是apps= app1,有时候可能会有20个或更多的应用apps= app1 app2 appN

如何迭代apps变量并执行某些操作?例如,在每次迭代中打印类似于以下内容:

now im in `app1`
now im in `app2`
etc

尝试以下操作时:

.PHONY: foo
all: foo
APPS = app1 app2 app3 app4
foo : $(APPS)
    for $$f in $(APPS); do echo $$f is here; done

我遇到了以下错误: make: *** No rule to make targetapp1',需要 foo'。停止。

我也不明白你所说的“从应用程序中打印值”的意思...你的问题非常不清楚。 - Basile Starynkevitch
@BasileStarynkevitch - 假设这个变量(apps)是由我的Golang程序在make文件中生成的,为每个项目提供不同的apps值,有时它是apps= app1 app2,有时它是apps= app1,有时可能有20个或更多的应用程序apps= app1 app2 appN - user6124024
请不要在问题中添加注释,但请编辑您的问题,因为它需要大量改进。在添加三个段落并解释您的动机时,请不要害羞。如果可以的话,请提供一些最小可复现示例(MCVE)。 - Basile Starynkevitch
即使进行了编辑,我仍然不明白你想做什么。许多现有的Makefile都有shell for循环。例如,GCC的源代码有一个生成MakefileMakefile.in文件,两者都有for循环。 - Basile Starynkevitch
@BasileStarynkevitch - 你现在可以看一下最后的编辑吗? - user6124024
显示剩余5条评论
2个回答

11

我看到你有些反复,让我简单地发表一下评论,也许会有帮助。

通常情况下,您不会在make的recipes中编写循环,因为make本身提供了"循环"。所以当您编写如下规则时:

all: app1 app2 app3 app4

make会逐个构建这些先决条件。因此,如果您想要一个 makefile,在apps变量的每个条目上回显一行,您可以像这样操作:

all: $(apps)

$(apps):
        @echo $@

这将告诉 make 从目标 all 开始,尝试“构建”变量 apps 中的每个先决条件。

然后,您定义了一个用于构建应用程序的规则,并且对于每个应用程序,您都指定规则为 echo $@,其中 $@ 是一个自动变量,它扩展为当前正在构建的目标。

在 make 中,语法:

foo bar biz:
        some command

是简写且与以下书写方式相同:

foo:
        some command
bar:
        some command
biz:
        some command

编写makefile时最重要的是考虑如何编写规则以从零个或多个前置文件创建一个文件(目标)。然后,让make担心如何连接所有这些前置文件并正确排序。

注意: 如果您想要在$(apps)变量中保存的长列表中为一个特定目标制定特殊规则,则可以采用以下方法:

$(filter-out bar,$(apps)):
        @echo print $@

bar:
        some other command

非常感谢,这正是我需要的 :) 再有一个问题,如果我想让 bar 运行 其他命令,我该怎么做? - user6124024
1
你可以像我上一个例子中那样写出所有的规则,而不是为所有的 $(apps) 写一个规则。如果你有很多的应用程序,但只想让其中一个不同,那么你需要做的就是将 $(apps): 目标更改为 $(filter-out bar,$(apps)):,这样它就不会为 bar 创建规则,然后再创建一个单独的规则 bar: 来完成你想要的操作。 - MadScientist
可以请您将翻译添加到答案中吗? - user6124024

3
也许您想要类似于以下内容(我假设 Makefile 的其他部分描述了如何使用适当的规则构建 app1app2 等...)。
foo: app1 app2 app3 app4 
     for f in $^ ; do echo $$f is here ; done

或者(稍微好一点)
APPS = app1 app2 app3 app4
foo : $(APPS)
     for f in $(APPS); do echo $$f is here; done

你可能会对 make 中的 foreach 函数(或者它的 eval 函数,也许混合了其他东西)感兴趣。

最后,你的 makefile(或其中一些 包含 的部分)可以由某个(shell、AWK、Python 等)脚本(甚至是另一个用 C++、Java、Ocaml 或其他语言编写的程序)生成。

我建议使用 remake,以 remake -x 调试你的 Makefile

你还可以生成一些 submakefile 并在某个 recipe 中运行 $(MAKE) -f submakefile

我强烈建议在编写Makefile之前,花至少一个小时完整阅读GNU make文档。并且你可能还需要阅读bash文档
最后,你可以考虑使用其他构建自动化工具,比如ninja(其哲学有所不同:期望build.ninja文件被生成,并且你需要为其提供一个生成器)。
对于你的下一个问题,请提供一些MCVE

好的,问题在于我没有为app1到appN制定规则,我能以某种方式克服它吗? - user6124024
没有生成这些规则,就没有其他选择了吗? - user6124024
1
我不知道,因为我仍然不理解你的问题。这很像一个XY问题 - Basile Starynkevitch
提供整个画面将非常困难,您要我在聊天中完成吗? - user6124024
1
@BasileStarynkevitch: for $$f in $^ ; do echo $$f is here ; done 可能不是你想要的。难道应该是 for f in $^ ; do echo $$f is here ; done 吗?另一个提案中也有同样的错别字。 - Renaud Pacalet
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接