开发者

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:

  1. touch foo1.c
  2. run make, which
    1. rebuilds foo1.o and
    2. rebuilds libmine.a
  3. touch bar1.c
  4. run make, which
    1. rebuilds bar1.o
    2. maybe(see below) rebuilds libmine.a

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 :-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜