为什么最后一个文件没有重新编译?

问题描述 投票:0回答:1

假设项目根目录如下:

|-> Makefile
|-> obj         // Empty folder)
|-> src         // Contains a.c, b.c, c.c, d.c, e.c source files

Makefile内容如下:

CC=gcc
RM=rm -rf

DIRSRC=./src
DIROBJ=./obj
SRCS=a.c b.c c.c d.c e.c
OBJS=$(patsubst  %.c,%.o,$(SRCS))
OBJX=$(addprefix  $(DIROBJ)/,$(OBJS))

app: $(OBJX)
        $(CC) -Wall -o app $(OBJX)

$(DIROBJ)/%.o: $(DIRSRC)/%.c  $(DIROBJ)   // (line 13)
         $(CC) -Wall -c -o $@ $<

$(DIROBJ):
         mkdir $(DIROBJ)

.PHONY: clean
clean:
         $(RM) $(OBJX)
         $(RM) $(DIROBJ)
         $(RM) ./app

在 Makefile 的第 13 行,我没有使用仅限订单的先决条件,而是故意使用了普通的先决条件。

当我第一次执行

make
时,输出是:

mkdir ./obj
gcc -Wall -c -o obj/a.o src/a.c
gcc -Wall -c -o obj/b.o src/b.c
gcc -Wall -c -o obj/c.o src/c.c
gcc -Wall -c -o obj/d.o src/d.c
gcc -Wall -c -o obj/e.o src/e.c
gcc -Wall -o app ./obj/a.o ./obj/b.o ./obj/c.o ./obj/d.o ./obj/e.o

我再次执行

make
,现在输出如下:

gcc -Wall -c -o obj/a.o src/a.c
gcc -Wall -c -o obj/b.o src/b.c
gcc -Wall -c -o obj/c.o src/c.c
gcc -Wall -c -o obj/d.o src/d.c
gcc -Wall -o app ./obj/a.o ./obj/b.o ./obj/c.o ./obj/d.o ./obj/e.o

我的问题是:在第二次、第三次等执行中,为什么最后一个

.c
文件{在本例中为
e.c
)没有编译?

makefile gnu-make gnu
1个回答
0
投票

问题不在于为什么不重建该文件。问题是为什么所有“其他”文件都被重建。如果您连续运行 make 两次,那么使用正确编写的 makefile,第二次调用应该不会执行任何操作,因为所有内容都是最新的。 所有问题的答案正是 @tripleee 所建议的:您已将目录列为目标文件的先决条件。

对于

make

,目录没有进行特殊处理。它们被视为目标,并且它们的最后修改时间用于确定依赖于它们的任何目标是否已过期。

但是对于文件系统来说,目录的最后修改时间并没有按照您期望的方式处理。尽管如此,当您考虑一下时,这是完全有道理的:只要目录内容被修改,目录的修改时间就会被设置。也就是说,当添加新文件、删除文件或重命名文件时。

更改
文件而不执行其中一项操作,不会更改目录,因此目录的修改时间不会更新。

因此,当 make 去检查目标文件以查看它是否过期时,它会将文件的修改时间与目录的修改时间进行比较。然后,当您在该目录中创建新文件时(例如),它会更改 mod 时间,因此当您再次运行 make 时,目标已过期。 那么为什么不是每个

.o

文件都被重建呢?最有可能的是因为文件上时间戳的粒度不足以检测最后一个文件的此更改。

您可以通过添加

-d
选项来查看 make 的想法。它会告诉你:

Finished prerequisites of target file 'obj/d.o'. Prerequisite 'src/d.c' is older than target 'obj/d.o'. Prerequisite 'obj' is newer than target 'obj/d.o'. Must remake target 'obj/d.o'.

但是:

   Finished prerequisites of target file 'obj/e.o'.
   Prerequisite 'src/e.c' is older than target 'obj/e.o'.
   Prerequisite 'obj' is older than target 'obj/e.o'.
  No need to remake target 'obj/e.o'.

© www.soinside.com 2019 - 2024. All rights reserved.