我需要一个Makefile,该文件允许我输入make foo-program
,并且如果自上次构建以来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'
更新:可以在on GitHub中找到我的最终(非抽象的)Makefile。请注意,我的解决方案与我撰写此问题时的意图有所不同。查看该Makefile还可以使我更清楚地了解我的最初目标。
答案 0 :(得分:2)
我不确定cut -d'/'
的目的。
但是,如果您只想要当前目录中的*.hs
文件列表(以递归方式找到),然后根据它们是否已更改来构建目标/可执行文件,则可以执行以下操作:
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
是如何生成依赖于其.hs文件等效文件的.dep文件(这可以是.o .obj或任何其他文件类型)的规则。 $(DIRS)
:是在需要时创建输出目录的规则。因此,如果.dep
文件不存在,则所有.hs
文件都将被“编译”。如果所有.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'.