GNU Make forgets prerequisites?
This is a bit complex so I have uploaded an example here.
How to test it:
- Download the tarball and unpack it
- cd make_problem/make
- make aclean (forgot to remove the archive from the archive ;))
- make alib (will re-create the simple and silly archive you just removed)
- ./weird.sh
What weird.sh does is simply to touch a source file, re-make, touch another source file, re-make, a few times.
This is what the output looks like on my Linux system using GNU Make 3.81:
$ ./weird.sh #### 1 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo1.o ../swu/1/src/foo1.c ar cr ../make/libmine.a ../swu/1/src/foo1.o ==== 1 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar1.o ../swu/1/src/bar1.c ar cr ../make/libmine.a ../swu/1/src/bar1.o #### 2 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo2.o ../swu/1/src/foo2.c ==== 2 ==== gcc -c开发者_如何学JAVA -g -Wall -Wextra -o ../swu/1/src/bar2.o ../swu/1/src/bar2.c #### 3 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo3.o ../swu/1/src/foo3.c ==== 3 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar3.o ../swu/1/src/bar3.c #### 4 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo4.o ../swu/1/src/foo4.c ==== 4 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar4.o ../swu/1/src/bar4.c #### 5 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo5.o ../swu/1/src/foo5.c ==== 5 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar5.o ../swu/1/src/bar5.c #### 6 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo6.o ../swu/1/src/foo6.c ==== 6 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar6.o ../swu/1/src/bar6.c #### 7 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo7.o ../swu/1/src/foo7.c ==== 7 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar7.o ../swu/1/src/bar7.c ar cr ../make/libmine.a ../swu/1/src/bar7.o #### 8 #### gcc -c -g -Wall -Wextra -o ../swu/1/src/foo8.o ../swu/1/src/foo8.c ==== 8 ==== gcc -c -g -Wall -Wextra -o ../swu/1/src/bar8.o ../swu/1/src/bar8.c $
Now I expected the archive be re-built every time a source was touched, but that evidently did not happen.
Can anyone explain this? And explain how to make sure it always works as expected?
The problem here is the relatively low resolution of file modification timestamps, which causes make to get confused when you run it twice in a row really quickly, like your weird.sh
does.
Specifically, weird.sh
will:
- touch
foo1.c
- run make, which
- rebuilds
foo1.o
and - rebuilds
libmine.a
- rebuilds
- touch
bar1.c
- run make, which
- rebuilds
bar1.o
- maybe(see below) rebuilds
libmine.a
- rebuilds
If the time between step 2.2 and step 4.2 is less than the timestamp resolution of your filesystem, then make sees libmine.a
as already having the same timestamp as bar1.o
, and so doesn't rebuild it.
The timestamp resolution for the Linux ext3 file system is 1 second. This explanation from the maintainer of make describes the problem in more detail, and also mentions that Solaris has better timestamp resolution, which probably explains why your example works as expected there.
If this is a problem for you in a real application, you might try the ext4 filesystem, which has nanosecond resolution timestamps. Otherwise, just put a sleep 1
after each make command in weird.sh
, and the problem goes away :-)
精彩评论