bli00
bli00

Reputation: 2797

Makefile: change in dependencies fail to trigger rebuild

I have a Makefile target that depends on a dynamic list of source files. This list is parsed on make invocations so it could potentially change. It looks like this:

target: $(shell cat foo.txt)
    @echo "build target"

foo.txt changes from time to time. What I'm seeing is that target will be rebuilt the first time foo.txt changes content to X. Say that foo.txt changes content to Y then changes back to X then target won't be built. I know I can include foo.txt as a dependency itself but for reasons difficult to explain that's not an option.

As a more concrete example, foo.txt looks like this:

google.golang.org/[email protected]/dialoptions.go

but could change to something like:

google.golang.org/[email protected]/dialoptions.go

What's going on? Is Makefile caching something?


EDIT

I guess Makefile is caching the timestamp of the dependencies and thus if the dependency files didn't change at all then the target won't be rebuilt? Is there a way to fix this?

Upvotes: 0

Views: 434

Answers (1)

MadScientist
MadScientist

Reputation: 100926

Make caches nothing. It has no preserved data whatsoever about any previous build. Make uses the filesystem as its "cache".

Because you're using $(shell cat foo.txt), make knows absolutely nothing about the file foo.txt. All it knows about is the set of files inside the foo.txt files. It treats all of those as prerequisites.

Then it merely compares the time last modified of the target file (target) with the time last modified of the prerequisite file that is contained in foo.txt.

So if foo.txt contains google.golang.org/[email protected]/dialoptions.go then it's as if your makefile was written to be:

target: google.golang.org/[email protected]/dialoptions.go

and if the time last modified of target is older than google.golang.org/[email protected]/dialoptions.go (use ls -l to see these values) then make decides target is out of date and must be rebuilt. If it's newer, then make decides target is up to date and doesn't have to be rebuilt.

If you change the contents of foo.txt to be google.golang.org/[email protected]/dialoptions.go then it compares the time last modified between target and google.golang.org/[email protected]/dialoptions.go, the same way.

That's all make does, at its root.

I don't really understand your requirements so I can't give any suggestions for solutions. If you need to have target rebuilt if either the contents of foo.txt changes or the modification time on the prerequisite listed in foo.txt changes, then the only way to do that is list foo.txt as a prerequisite so make can detect when it was changed. You say you can't do that so... I don't have any good solutions for you.

Upvotes: 3

Related Questions