GNU Make 忘记了先决条件?
这有点复杂,所以我在此处上传了一个示例。
如何测试它:
- 下载 tarball 并解压它
- cd make_problem/make
- make aclean (忘记从存档中删除存档;))
- make alib (将重新创建您刚刚删除的简单而愚蠢的存档)
- ./
weird.sh odd.sh 所做的只是简单地触摸一个源文件,重新制作,触摸另一个源文件,重新制作,几次。
这就是我使用 GNU Make 3.81 的 Linux 系统上的输出:
$ ./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 -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 $
现在我希望每次接触源代码时都会重新构建存档,但这显然没有发生。
谁能解释一下吗? 并解释如何确保它始终按预期工作?
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 -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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里的问题是文件修改时间戳的分辨率相对较低,这会导致当您快速连续运行两次时 make 会感到困惑,就像您的
weird.sh
那样。具体来说,weird.sh 将:
foo1.c
foo1.o
和libmine.a
bar1.c
bar1.o
libmine.a
如果步骤 2.2 和步骤 4.2 之间的时间小于文件系统的时间戳分辨率,然后 make 会发现
libmine.a
已经具有与bar1.o
相同的时间戳,因此不会重建它。Linux ext3 文件系统的时间戳分辨率为 1 秒。 make 维护者的解释描述了这个问题更详细地说,还提到 Solaris 具有更好的时间戳分辨率,这可能解释了为什么您的示例在那里按预期工作。
如果这在实际应用程序中对您来说是个问题,您可以尝试 ext4 文件系统,它具有纳秒分辨率时间戳。否则,只需在
weird.sh
中的每个 make 命令后放置一个sleep 1
,问题就会消失:-)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:foo1.c
foo1.o
andlibmine.a
bar1.c
bar1.o
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 asbar1.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 inweird.sh
, and the problem goes away :-)