Reputation: 1893
I am pulling out my hair trying to debug an issue with make. It seems like make is randomly treating certain prerequisites as order-only prerequisites, resulting in them being left out of the static library target that depends on them. Most of the time the build works find but occasionaly some .cpp files are built but not included in the .a. When i run Make with --debug I see the following output for the suspect prerequisites.
Prerequisite `blah.o' is newer than target `/path/to/foo.a`
Prerequisite `blah1.o' is newer than target `/path/to/foo.a`
Prerequisite `blah2.o' is newer than target `/path/to/foo.a`
No need to remake target `/path/to/foo.a'
For all of the prereqs that do make it into the .a the last line is "Must remate target /path/to/foo.a" as I would expect.
Because make is invoked in several subdirectories, target /path/to/foo.a is updated several times. We are not running make in parallel so I don't think updates to the file are stomping each other. It seems that make is deliberately not updating the .a file despite the fact that the .o's are newer. The recipe to make foo.a is as follows:
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $?
Where ARFLAGS=rv and OBJLIB would be /path/to/foo.a.
Am i right in thinking that the .o files are being treated as order-only dependencies? Is there something else I'm missing here? I am using $(info) to output the contents of OBJLIB and OBJS and there are no errant pipe ('|') characters making their way into the variable contents that would induce order-only dependencies.
Upvotes: 0
Views: 262
Reputation: 1893
Unfortunately the answer had nothing to do with make. As far as I can tell the filesystem is the real culprit. Several people were experiencing success with the build but I was not. The difference between our systems which were using a common build environment was that I was building on an ext3 filesystem while they were using an ext4 filesystem.
Since ext3 does not support sub-1s timestamps (ext4 does) in some cases when the rule was invoked with only a few CPP files they were being compiled in the same second that the archive was updated by a previous invocation and everything was ending up with the same timestamps. Copying the directory over to an ext4 filesystem fixed the issue.
The real fix is to write a proper set of make rules but at least we have an answer as to why it was working for everyone but me.
Upvotes: 1
Reputation: 8923
Try this instead.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $(OBJLIB) $^
Your problem is that the variable $? is a list of dependencies that are newer than the target, while $^ is a list of all dependencies.
Also, you can use $@ for to be more idiomatic.
$(OBJLIB): $(OBJS)
$(AR) $(ARFLAGS) $@ $^
Upvotes: 0
Reputation: 57163
You mentioned several updates to the .a file because make is invoked in different subdirectories. Probably the message
No need to remake target `/path/to/foo.a'
comes from one subdirectory, and is newer
- from another. Consider building the lib out of all objects in one step.
Upvotes: 0