如果目录内容已更改,则构建 make 目标

Build make target if contents of directory have changed

我需要一个允许我输入 make foo-program 的 Makefile,如果自上次构建以来有任何 foo-program/**/*.hs 文件发生更改,则构建目标(在 foo-program/.stack-work 中输出)。

这是我的目录树:

project/
|-bar-other-program/
  |-.stack-work/ # Generated output goes here
  |-src/
    |-BarOtherProgram.hs
  |-test/
    |-Tests.hs
|-foo-program/
  |-.stack-work/ # Generated output goes here
  |-src/
    |-FooProgram.hs
  |-test/
    |-Tests.hs
|-notes/ # non-source, so no Make target for this

这是我目前的情况:

# evaluates to 'bar-other-program foo-program'
PROGS := $(shell find * -type f -name '*.hs' | cut -d'/' -f1 | uniq)

.SECONDEXPANSION:
$(PROGS): $$(wildcard $$@/src/*.hs) $$(wildcard $$@/test/*.hs)
    # do-build $@

当我运行make foo-program时,无论源是否改变,我得到:

make: Nothing to be done for 'foo-program'

更新:可以找到我的最终(非抽象)Makefile on GitHub。请注意,当我写下这个问题时,我的解决方案与我预期的不同。查看该 Makefile 也可能使我的最初目标更加清晰。

我不太确定 cut -d'/' 的目的。

但是如果你只是想要当前目录中的 *.hs 个文件列表(递归找到),然后根据它们是否已更改构建一个 target/executable,你可以这样做:

PROGS = $(subst ./,,$(shell find . -type f -name '*.hs'))
DEPS = $(addprefix stackwork/,$(addsuffix .dep,$(basename $(PROGS))))
DIRS = $(dir $(DEPS))

.PHONY: foo-program
foo-program: $(DEPS) $(DIRS)

stackwork/%.dep: %.hs | $(DIRS)
    @echo making $@
    @touch $@

$(DIRS):
    @echo creating dir $@
    @mkdir -p $@

clean:
    @rm -rf $(DEPS) $(DIRS)

其中:

  • PROGS 是您的 .hs 个文件列表
  • DEPS是生成的依赖文件列表(空但会使用日期戳)
  • DIRS 是需要创建的输出目录列表(我猜它们默认不存在,因为它们是输出文件夹?)
  • foo-program是可以调用的规则(PHONY因为目前它还没有创建真正的文件)
  • %.dep: %.hs 是如何生成 .dep 文件(可以是 .o .obj 或任何其他文件类型)的规则,这取决于它的 .hs 文件等价物。
  • $(DIRS): 是根据需要创建输出目录的规则。

因此,如果 .dep 个文件不存在,则所有 .hs 个文件都将是 "compiled"。如果所有 .dep 文件都存在并且是最新的,则不会编译任何内容。如果一个或多个文件已过期,则只会构建这些文件。这是 运行 在我的 PC 上使用一些测试文件的输出:

admin@osboxes:~/sandbox$ make
    creating dir stackwork/
    creating dir stackwork/test/
    creating dir stackwork/test/test2/
    making stackwork/file.dep
    making stackwork/test/file.dep
    making stackwork/test/test2/file2.dep

admin@osboxes:~/sandbox$ make
    make: Nothing to be done for 'foo-program'.

admin@osboxes:~/sandbox$ touch test/file.hs      
admin@osboxes:~/sandbox$ make
    making stackwork/test/file.dep

admin@osboxes:~/sandbox$ make
    make: Nothing to be done for 'foo-program'.