为什么makefile为生成的文件请求文件夹

为什么makefile为生成的文件请求文件夹,makefile,Makefile,我编写了一个makefile来编译生成的文件 %.o: %.cc g++ -c $< -o $@ default: gen main.o gen: touch main.cc 但是,如果我为生成的.cc和.o文件添加一个文件夹,它就会工作 obj/%.o: src/%.cc g++ -c $< -o $@ default: gen obj/main.o gen: touch src/main.cc obj/%.o:src/%.cc g++-

我编写了一个makefile来编译生成的文件

%.o: %.cc
    g++ -c $< -o $@

default: gen main.o

gen:
    touch main.cc
但是,如果我为生成的.cc和.o文件添加一个文件夹,它就会工作

obj/%.o: src/%.cc
    g++ -c $< -o $@

default: gen obj/main.o

gen:
    touch src/main.cc
obj/%.o:src/%.cc
g++-c$<-o$@
默认值:gen obj/main.o
消息:
触摸src/main.cc

为什么要请求文件夹obj和src

它们不是。这种行为来自于
make
的优化,而您的
Makefile
对它所做的事情并不真诚

make
读取目录时,它将散列所有目录内容,并在此目录中执行将来的文件查找。当
make
第一次启动时,没有
main.cc
文件,因此目录哈希不包含
main.cc
的条目。由于您的
Makefile
生成了该文件,但没有声明它,
make
不知道有一个目标生成了
main.cc
文件,当它在哈希中查找时,该文件不在那里。因此,您的隐含规则被视为不可能被拒绝:

$ make -dr default
...
Considering target file 'default'.
 File 'default' does not exist.
 Looking for an implicit rule for 'default'.
 No implicit rule found for 'default'.
  Considering target file 'gen'.
   File 'gen' does not exist.
   Finished prerequisites of target file 'gen'.
  Must remake target 'gen'.
touch main.cc
Putting child 0x55de3daaa6a0 (gen) PID 6075 on the chain.
Live child 0x55de3daaa6a0 (gen) PID 6075
Reaping winning child 0x55de3daaa6a0 PID 6075
Removing child 0x55de3daaa6a0 PID 6075 from chain.
  Successfully remade target file 'gen'.
  Considering target file 'main.o'.
   File 'main.o' does not exist.
   Looking for an implicit rule for 'main.o'.
   Trying pattern rule with stem 'main'.
   Trying implicit prerequisite 'main.cc'.
   Trying pattern rule with stem 'main'.
   Trying implicit prerequisite 'main.cc'.
   Looking for a rule with intermediate file 'main.cc'.
    Avoiding implicit rule recursion.
   No implicit rule found for 'main.o'.
   Finished prerequisites of target file 'main.o'.
  Must remake target 'main.o'.
make: *** No rule to make target 'main.o', needed by 'default'.  Stop.
如果您
strace
此调用,您将注意到两件事:a
getdents64
调用读取目录内容(用于查找和散列)和b
main.cc
根本没有
stat
,这意味着磁盘上没有检查文件存在,因为它的存在是通过缓存解析的:

$ strace make -r default
...
stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents64(3, /* 3 entries */, 32768)   = 80
getdents64(3, /* 0 entries */, 32768)   = 0
close(3)                                = 0
...
stat("gen", 0x7fff4f66a3d0)             = -1 ENOENT (No such file or directory)
stat("main.o", 0x7fff4f66a460)          = -1 ENOENT (No such file or directory)
... <-- locale-related calls for error message
write(2, "make: *** No rule to make target"..., 71make: *** No rule to make target 'main.o', needed by 'default'.  Stop.
如果您按照规则正确编写
Makefile
,并声明正在创建的文件,
make
将按预期运行:

$ cat Makefile
%.o: %.cc
        g++ -c $< -o $@

default: main.o

main.cc:
        touch $@

$ make default
touch main.cc
g++ -c main.cc -o main.o
$cat Makefile
%.o:%.cc
g++-c$<-o$@
默认值:main.o
main.cc:
触碰$@
$makedefault
touch main.cc
g++-c main.cc-o main.o
$ make -dr default
...
Considering target file 'default'.
 File 'default' does not exist.
 Looking for an implicit rule for 'default'.
 No implicit rule found for 'default'.
  Considering target file 'gen'.
   File 'gen' does not exist.
   Finished prerequisites of target file 'gen'.
  Must remake target 'gen'.
touch main.cc
Putting child 0x555646acc6a0 (gen) PID 6079 on the chain.
Live child 0x555646acc6a0 (gen) PID 6079
Reaping winning child 0x555646acc6a0 PID 6079
Removing child 0x555646acc6a0 PID 6079 from chain.
  Successfully remade target file 'gen'.
  Considering target file 'main.o'.
   File 'main.o' does not exist.
   Looking for an implicit rule for 'main.o'.
   Trying pattern rule with stem 'main'.
   Trying implicit prerequisite 'main.cc'.
   Found an implicit rule for 'main.o'.
    Considering target file 'main.cc'.
     Looking for an implicit rule for 'main.cc'.
     No implicit rule found for 'main.cc'.
     Finished prerequisites of target file 'main.cc'.
    No need to remake target 'main.cc'.
   Finished prerequisites of target file 'main.o'.
  Must remake target 'main.o'.
g++ -c main.cc -o main.o
Putting child 0x555646ad0690 (main.o) PID 6080 on the chain.
Live child 0x555646ad0690 (main.o) PID 6080
Reaping winning child 0x555646ad0690 PID 6080
Removing child 0x555646ad0690 PID 6080 from chain.
  Successfully remade target file 'main.o'.
 Finished prerequisites of target file 'default'.
Must remake target 'default'.
Successfully remade target file 'default'.
$ cat Makefile
%.o: %.cc
        g++ -c $< -o $@

default: main.o

main.cc:
        touch $@

$ make default
touch main.cc
g++ -c main.cc -o main.o