gmake 在子目录中创建一个 Makefile(如果不存在),然后再切换到递归 make

问题描述 投票:0回答:1

我希望我的 gmake 在所有子目录中递归 gmake,但首先将 Makefile 复制到给定的子目录,然后再在那里运行 make(如果它尚不存在)。

以下工作完美,但我想要一种更自制的方式来做到这一点。

SUBDIRS = ${sort ${patsubst %/,%,${dir ${wildcard */}}}}

all $(MAKECMDGOALS):: $(SUBDIRS)

.PHONY: $(SUBDIRS)

$(SUBDIRS)::
    @echo;echo;echo;echo;echo
    [ -f $@/Makefile] || cp ../somewhere/Makefile.default $@/Makefile
    $(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS)

我尝试过以下类似的方法,但没有成功。 (是的,乍一看这是向后逻辑:显然子目录必须存在才能拥有 Makefile,对吧?但子目录实际上并没有被创建,而是一个虚假目标,只是创建了一个 TODO 列表。它不是子目录这实际上取决于它的 Makefile,而是分配给需要 Makefile 的虚假目标的任务或“配方”。)

# $@ evaluates to ""
$(SUBDIRS)::$@/Makefile

以下有效。 但是,从技术上讲,它似乎断言所有子目录都依赖于所有子目录 Makefile,因此它在进入第一个目录之前立即创建所有 Makefile。 从功能上来说,这是完全可以接受的,但它似乎不是“正确”的解决方案。

SUBDIRMAKEFILES = ${patsubst %,%/Makefile,${SUBDIRS}}
$(SUBDIRS)::$(SUBDIRMAKEFILES)
        @echo;echo;echo;echo;echo
        $(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS)

$(SUBDIRMAKEFILES):
    cp ../somewhere/Makefile.default $@/Makefile

那么有没有更干净的方法来做到这一点?

gnu-make
1个回答
0
投票

使所有子目录依赖于所有“foo”文件是N对N关系,没错。

但实际上你没有任何子目录对其“foo”文件的依赖,这是相反的。每个“foo”文件都取决于其子目录的存在。

至少有两个选项,见下文。


对其他问题的一些评论您在评论中留下的,未来的访问者很难找到。

  1. 如果其中一个目录无法修改(例如权限),它将阻止其他本来可以正常编译的目录的进度。因此,告诉 gmake 它必须不按顺序执行操作,理论上可能会阻止工作。

您不会通过 Makefile 的内容来处理这个问题。使用

-k
(
--keep-going
) 选项调用 make。 Make 仅中止失败的依赖分支,但继续处理独立分支。

  1. 我想学习正确的语法。

如果您有错误的语法,make 会让您知道。我认为你的意思是语义,或者正确的方法。

其他一些注意事项:

  1. 一些开发人员认为多 Makefile 项目很糟糕,因为它们很难掌握。他们更喜欢单一的一体化 Makefile。恐怕没有唯一正确的方法。
  2. 仅对子目录进行排序,如果后续 make 的顺序取决于该顺序。
  3. 由于通配符模式包含路径分隔符,
    ${dir ...}
    对我来说看起来多余,因为只收集目录。
  4. 实际上不需要删除尾随路径分隔符,您可以使用
    -C path/
    调用make。不过,我保留了这个。
  5. 对于您的“foo”文件,您不清楚其依赖关系,无论它们是否依赖于“../somewhere/foo.default”。
    如果它们依赖,请删除相应规则中的注释符号。然后您可以将复制命令中重复的名称替换为
    $<

    如果没有依赖项,则只会从当前默认值创建缺少的“foo”文件。更改默认值不会更新现有的“foo”文件。
  6. make手册说双冒号规则很少使用。重新考虑你的决定。

1.在第一个子 make 之前提供所有“foo”文件

每个“foo”文件都依赖于其子目录的存在。您可以通过从

SUBDIRFOO
派生
SUBDIRS
自动实现此目的。

定义

all
首先取决于
SUBDIRFOO
,然后取决于
SUBDIRS

我更喜欢如图所示的更简单的语法,从

SUBDIRFOO
构建
SUBDIRS
。这仅适用于变量。

SUBDIRS = ${patsubst %/,%,${wildcard */}}

SUBDIRFOO = $(SUBDIRS:%=%/foo)

all: $(SUBDIRFOO) $(SUBDIRS)

$(SUBDIRFOO): #../somewhere/foo.default
    cp ../somewhere/foo.default $@

$(SUBDIRS):
    $(MAKE) --no-print-directory -C $@

2.处理子目录中的依赖

由于每个子目录的“foo”文件都依赖于该子目录的存在,因此您将规则移动到子目录的 Makefile 中。

如果您想避免重复,请使用

include
指令并提供一个中心文件。这将简化此规则的维护,因为它在每个子目录中都是相同的。也将此应用于其他常见的东西。

这是最顶层的Makefile,现在只负责它的级别。

SUBDIRS = ${patsubst %/,%,${wildcard */}}

all: $(SUBDIRS)

$(SUBDIRS)::
    $(MAKE) --no-print-directory -C $@

任何子目录中的每个 Makefile 都有一个附加规则来提供其“foo”文件。

all: foo

foo: #../../somewhere/foo.default
    cp ../../somewhere/foo.default $@
© www.soinside.com 2019 - 2024. All rights reserved.