如何将目标名称传递给子Makefile列表?

13

我有这样的设定:

/Makefile
/foo/Makefile
/foo/bar/Makefile
/foo/baz/Makefile

顶层Makefile包含一个任务,该任务调用/foo/Makefile。这个Makefile在子目录(例如barbaz)中创建了一个Makefile列表。对于每个子目录,它都会调用相应的Makefile:

$(SUB_DIRS):
    $(MAKE) -C $@

当然,如果只是针对all任务,这样做也没问题。但是,如果我想做其他事情,我就卡住了。是否有可能将目标传递给子makefile的列表中呢? 例如:

$(SUB_DIRS):
    $(MAKE) -C $@ <task>

clean: $(SUB_DIRS)-clean # or something?

还是我的整个概念错误了吗?


我已经做过类似的事情,但我也对解决这个问题的其他方案感兴趣。 - UpAndAdam
你不可能“做出这样的事情”,因为没有解决方案。我的例子根本不起作用。 - musicmatze
你使用的是哪个版本的make?我完全按照这样做。 - UpAndAdam
3个回答

11

你可以简单地使用MAKECMDGOALS变量:

若在命令行中指定了目标,则Make会将特殊变量MAKECMDGOALS设置为已指定的目标列表。如果没有在命令行中指定目标,则该变量为空。

$(SUB_DIRS):
    +$(MAKE) -C $@ $(MAKECMDGOALS)

在这里,+符号很重要,因此底层的作业服务器还可以正确地处理递归的make调用,以使用正确数量的线程/核心。


您也可以像这样使用$(foreach )函数:

clean:
    $(foreach DIR, $(SUB_DIRS), $(MAKE) -C $(DIR) $@;)

请注意,正如评论中所提到的@musicmatze一样,make标志(例如-j)在此处将无法正确传递给子make进程。


1
记录一下:这个(MAKECMDGOALS)是最干净的解决方案。我的解决方案也可以工作。foreach方法确实可行,但如果你想要做make -j 4(例如),那么foreach方法就不具有可扩展性了,我猜测。 - musicmatze

4

我终于让它工作了。具体方式如下:

SUB_DIRS        = $(wildcard */.)
SUB_DIRS_ALL    = $(SUB_DIRS:%=all-%)
SUB_DIRS_TEST   = $(SUB_DIRS:%=test-%)
SUB_DIRS_CLEAN  = $(SUB_DIRS:%=clean-%)

#
# Standard task
#
all: $(SUB_DIRS_ALL)

test_uml: $(SUB_DIRS_TEST)

clean: $(SUB_DIRS_CLEAN)

$(SUB_DIRS_ALL):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:all-%=%)

$(SUB_DIRS_TEST):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:test-%=%) test

$(SUB_DIRS_CLEAN):
        @$(MAKE) $(MAKE_FLAGS) -C $(@:clean-%=%) clean

我在这里找到了解决方案:http://lackof.org/taggart/hacking/make-example/

(注:此文章为提供链接,无需翻译)

1
这基本上是我发布的相同内容,只是进一步推广,以便在无法使用目录名称本身时进行操作(您需要在执行时添加/删除前缀/后缀)。我经常做的几乎与您描述的完全一样,但我不想逐字逐句地发布它,因为我希望有人提供我尚未发现的解决问题的方法,例如MAKECMDGOALS,并且我个人认为它的价值超出了我已经描述的内容。 - UpAndAdam

1

是的,您只需按照指定的方式进行操作,有趣的部分在于当您可能希望既执行某些操作又可能再次递归时,需要处理下一级。

例如,我有一个像这样的递归安装:

$(INSTALL_DIRS):
    $(MAKE) -C $@ install

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