Makefile rule depend on directory content changes

Let's say your directory is called dir, then this makefile will do what you want:

FILES = $(wildcard dir/*)

codegen: dir # Add $(FILES) here if you want the rule to run on file changes too.
    generate-my-code

As the comment says, you can also add the FILES variable if you want the code to depend on file contents too.


Kudos to gjulianm who got me on the right track. His solution works perfect for a single directory.

To get it working recursively I did the following.

ASSET_DIRS = $(shell find ../../assets/ -type d)
ASSET_FILES = $(shell find ../../assets/ -type f -name '*')

codegen: ../../assets/ $(ASSET_DIRS) $(ASSET_FILES)
     generate-my-code

It appears now any changes to the directory or files (add, delete, rename, modify) will cause this rule to run. There is likely some issue with file names here (spaces might cause issues).


A disadvantage of having the rule depend on a directory is that any change to that directory will cause the rule to be out-of-date — including creating generated files in that directory. So unless you segregate source and target files into different directories, the rule will trigger on every make.

Here is an alternative approach that allows you to specify a subset of files for which additions, deletions, and changes are relevant. Suppose for example that only *.foo files are relevant.

# replace indentation with tabs if copy-pasting

.PHONY: codegen
codegen:
        find . -name '*.foo' |sort >.filelist.new
        diff .filelist.current .filelist.new || cp -f .filelist.new .filelist.current
        rm -f .filelist.new
        $(MAKE) generate

generate: .filelist.current $(shell cat .filelist.current)
        generate-my-code

.PHONY: clean
clean:
        rm -f .filelist.*

The second line in the codegen rule ensures that .filelist.current is only modified when the list of relevant files changes, avoiding false-positive triggering of the generate rule.