makefileprerequisites

Build make target if contents of directory have changed


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.


Solution

  • 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:

    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'.