I was trying to invent the way for GNU Make to depend on contents of files, rather than on timestamps.

If what was implied is the content change between consequent make invocations (i.e. target should not be remade, if timestamp has changed, but the content did not), it's easy. Prototyped in my own Stackoverflow answer, the solution was simple:

content=.md5-$1-$(shell md5sum <$1 | sed 's/[[:space:]].*//')
define track
$(call content,$1):
        rm .md5-$1-*
        touch $$@
endef

$(eval $(call track,foo))
$(eval $(call track,bar))

all: $(call content,foo) $(call content,bar)
        ...

However, then I tried to solve more common use-case. The file gets updated, but if after update its content didn't change, then treat it as if it wasn't updated. I think it's impossible.

An only way to achieve it is to make makefile rebuild itself after such update. But it means that makefile should depend on this file, and this way the file will be rebuilt at each make invocation, regardless if it's really needed in this particular case.

In other words, once make established its plan of action, chose what targets will be rebuilt, nothing can change this plan. The targets will be executed in an order picked, and nothing that happens during the run will make the order or the set of them change.

And that's virtually the most important and the most restrictive make limitation. When I write my own build system, I'll make it powerful enough to solve this.

And for now, let's keep tracking timestamps, or search for better tools.