I need a Makefile that allows me to enter make foo-program
and, if any foo-program/**/*.hs
file has changed since last build, build the target (output in foo-program/.stack-work
).
Here is my directory tree:
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
Here is what I have so far:
# 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 $@
When I run make foo-program
, whether the source has changed or not, I get:
make: Nothing to be done for 'foo-program'
UPDATE: My final (non-abstracted) Makefile can be found on GitHub. Note that my solution took a different turn than I intended when I wrote up this question. Looking at that Makefile also might also make it more clear as to my original goal.
I am not quite sure of the the purpose of cut -d'/'
there.
But if you just want a list of *.hs
files in the current directory (recursively found) and then build a target/executable based on whether they have changed, you can do something like this:
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)
Where:
PROGS
is your list of .hs
filesDEPS
is a list of generated dependency files (empty but date stamps will be used)DIRS
is a list of output directories that need to be created (I guess they don't exist by default since they are output folders?)foo-program
is a rule that you can call (PHONY
because at the moment it does not create a real file)%.dep: %.hs
is a rule how to generate a .dep file (this could be a .o .obj or any other file type) which depends on its .hs file equivalent. $(DIRS)
: is a rule to create your output directories if needed.So if the .dep
files don't exist, all of the .hs
files will be "compiled". If all the .dep
files exist and are up to date, then nothing will be compiled. If one or more file is out of date then just those files will be built. Here is the output of running this on my PC with a few test files:
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'.