Makefile依赖问题-1

参考:
https://juejin.cn/post/6844903687471497223
https://www.cnblogs.com/cuckoos/articles/5049984.html

背景

这块知识有点太烦人了,顶不住,整理一下,省的到处翻了。。。

1、编译行为带来的缺陷

预处理器将头文件中的代码直接插入源文件
编译器只通过预处理后的源文件产生目标文件

因此,规则中以源文件为依赖,命令可能无法执行。这里的没法执行主要是个人在写规则时,目标所依赖的文件没写全。因为目标是否更新主要看依赖和目标文件谁比较新。(在 Makefile 中,依赖关系的比较是基于文件的修改时间(modification time)。当 make 执行时,它会比较目标文件和其依赖文件的修改时间,以决定是否需要重新构建目标文件。)

示例1观察以下makefile文件是否正确:当修改func.h中宏HELLO的内容后,执行make命令发现,编译器无法更新main.c和func.c,进而无法更新执行的结果:原因在于func.h中更新的内容无法自动更新到func.c和main.c文件中,进而导致编译的hello.out文件结果无任何变化。

Makefile就这么点事儿:

target ... : prerequisites ...

recipe ...

...

代码结构组织如下图:
在这里插入图片描述

func.h

#ifndef FUNC.H
#define FUNC.H

#define HELLO "hello makefile"

void foo();

#endif

func.c

#include <stdio.h>
#include "func.h"

void foo()
{
    printf("void foo():%s\n",HELLO);
    
}

main.c

#include <stdio.h>
#include "func.h"

extern void foo();

int main()
{
    foo();
    
    return 0;
}

Makefile

vpath %.h include
vpath %.c src

OBJS := func.o main.o
HEADERDIR = -Iinclude
OBJDIR = obj
BINDIR = bin

hello.out : $(OBJS)
    gcc -o $(BINDIR)/$@ $(addprefix $(OBJDIR)/, $^)
    @echo "Target File => $(BINDIR)/$@"

$(OBJS) : %.o : %.c
    gcc $(HEADERDIR) -o $(OBJDIR)/$@ -c $<

.PHONY: clean

clean:
    -rm -rf $(OBJDIR)/*.o $(BINDIR)/hello.out                             

运行结果:
在这里插入图片描述
其实你去写Makefile的时候就看到了,hello.out是目标,依赖func.o main.o,而func.o main.o是否更新完全依赖与.c,我们没有在prerequisites中写.h这个东西,很难受,我们在*.h写了个宏,如果说我们修改了这个宏,因为没有跟目标建立依赖关系,所以改了等于白改,就像下边这样:
。。。
。。。
。。。

你要这么想就错啦!!!!

在这里插入图片描述
不信你看:
在这里插入图片描述
很明显每次都会生成一个新的hello.out,所以即便你没有包含对.h的依赖,func.h对宏的改变,仍然能反映到hello.out结果中,难受。。。

如果说你是个犟种,想查明原因,这时候直接甩出来:

make -d

来吧,展示:

......
......
Updating goal targets....
Considering target file 'hello.out'.
 File 'hello.out' does not exist.
  Considering target file 'func.o'.
   File 'func.o' does not exist.
    Considering target file 'func.c'.
     Looking for an implicit rule for 'func.c'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.y'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.l'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.w'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.w'.
     Trying pattern rule with stem 'func.c'.
     Trying implicit prerequisite 'func.c,v'.
     Trying pattern rule with stem 'func.c'.
     Trying implicit prerequisite 'RCS/func.c,v'.
     Trying pattern rule with stem 'func.c'.
     Trying implicit prerequisite 'RCS/func.c'.
     Trying pattern rule with stem 'func.c'.
     Trying implicit prerequisite 's.func.c'.
     Trying pattern rule with stem 'func.c'.
     Trying implicit prerequisite 'SCCS/s.func.c'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.y'.
     Looking for a rule with intermediate file 'func.y'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'func.y'.
      Trying implicit prerequisite 'func.y,v'.
      Trying pattern rule with stem 'func.y'.
      Trying implicit prerequisite 'RCS/func.y,v'.
      Trying pattern rule with stem 'func.y'.
      Trying implicit prerequisite 'RCS/func.y'.
      Trying pattern rule with stem 'func.y'.
      Trying implicit prerequisite 's.func.y'.
      Trying pattern rule with stem 'func.y'.
      Trying implicit prerequisite 'SCCS/s.func.y'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.l'.
     Looking for a rule with intermediate file 'func.l'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'func.l'.
      Trying implicit prerequisite 'func.l,v'.
      Trying pattern rule with stem 'func.l'.
      Trying implicit prerequisite 'RCS/func.l,v'.
      Trying pattern rule with stem 'func.l'.
      Trying implicit prerequisite 'RCS/func.l'.
      Trying pattern rule with stem 'func.l'.
      Trying implicit prerequisite 's.func.l'.
      Trying pattern rule with stem 'func.l'.
      Trying implicit prerequisite 'SCCS/s.func.l'.
     Trying pattern rule with stem 'func'.
     Trying implicit prerequisite 'func.w'.
     Looking for a rule with intermediate file 'func.w'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'func.w'.
      Trying implicit prerequisite 'func.w,v'.
      Trying pattern rule with stem 'func.w'.
      Trying implicit prerequisite 'RCS/func.w,v'.
      Trying pattern rule with stem 'func.w'.
      Trying implicit prerequisite 'RCS/func.w'.
      Trying pattern rule with stem 'func.w'.
      Trying implicit prerequisite 's.func.w'.
      Trying pattern rule with stem 'func.w'.
      Trying implicit prerequisite 'SCCS/s.func.w'.
     Trying pattern rule with stem 'func'.
     Rejecting impossible implicit prerequisite 'func.w'.
     No implicit rule found for 'func.c'.
     Finished prerequisites of target file 'func.c'.
    No need to remake target 'func.c'; using VPATH name 'src/func.c'.
   Finished prerequisites of target file 'func.o'.
  Must remake target 'func.o'.
gcc -Iinclude -o obj/func.o -c src/func.c
Putting child 0x60155b02cf40 (func.o) PID 2558427 on the chain.
Live child 0x60155b02cf40 (func.o) PID 2558427 
Reaping winning child 0x60155b02cf40 PID 2558427 
Removing child 0x60155b02cf40 PID 2558427 from chain.
  Successfully remade target file 'func.o'.
  Considering target file 'main.o'.
   File 'main.o' does not exist.
    Considering target file 'main.c'.
     Looking for an implicit rule for 'main.c'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.y'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.l'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.w'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.w'.
     Trying pattern rule with stem 'main.c'.
     Trying implicit prerequisite 'main.c,v'.
     Trying pattern rule with stem 'main.c'.
     Trying implicit prerequisite 'RCS/main.c,v'.
     Trying pattern rule with stem 'main.c'.
     Trying implicit prerequisite 'RCS/main.c'.
     Trying pattern rule with stem 'main.c'.
     Trying implicit prerequisite 's.main.c'.
     Trying pattern rule with stem 'main.c'.
     Trying implicit prerequisite 'SCCS/s.main.c'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.y'.
     Looking for a rule with intermediate file 'main.y'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'main.y'.
      Trying implicit prerequisite 'main.y,v'.
      Trying pattern rule with stem 'main.y'.
      Trying implicit prerequisite 'RCS/main.y,v'.
      Trying pattern rule with stem 'main.y'.
      Trying implicit prerequisite 'RCS/main.y'.
      Trying pattern rule with stem 'main.y'.
      Trying implicit prerequisite 's.main.y'.
      Trying pattern rule with stem 'main.y'.
      Trying implicit prerequisite 'SCCS/s.main.y'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.l'.
     Looking for a rule with intermediate file 'main.l'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'main.l'.
      Trying implicit prerequisite 'main.l,v'.
      Trying pattern rule with stem 'main.l'.
      Trying implicit prerequisite 'RCS/main.l,v'.
      Trying pattern rule with stem 'main.l'.
      Trying implicit prerequisite 'RCS/main.l'.
      Trying pattern rule with stem 'main.l'.
      Trying implicit prerequisite 's.main.l'.
      Trying pattern rule with stem 'main.l'.
      Trying implicit prerequisite 'SCCS/s.main.l'.
     Trying pattern rule with stem 'main'.
     Trying implicit prerequisite 'main.w'.
     Looking for a rule with intermediate file 'main.w'.
      Avoiding implicit rule recursion.
      Trying pattern rule with stem 'main.w'.
      Trying implicit prerequisite 'main.w,v'.
      Trying pattern rule with stem 'main.w'.
      Trying implicit prerequisite 'RCS/main.w,v'.
      Trying pattern rule with stem 'main.w'.
      Trying implicit prerequisite 'RCS/main.w'.
      Trying pattern rule with stem 'main.w'.
      Trying implicit prerequisite 's.main.w'.
      Trying pattern rule with stem 'main.w'.
      Trying implicit prerequisite 'SCCS/s.main.w'.
     Trying pattern rule with stem 'main'.
     Rejecting impossible implicit prerequisite 'main.w'.
     No implicit rule found for 'main.c'.
     Finished prerequisites of target file 'main.c'.
    No need to remake target 'main.c'; using VPATH name 'src/main.c'.
   Finished prerequisites of target file 'main.o'.
  Must remake target 'main.o'.
gcc -Iinclude -o obj/main.o -c src/main.c
Putting child 0x60155b02e000 (main.o) PID 2558430 on the chain.
Live child 0x60155b02e000 (main.o) PID 2558430 
Reaping winning child 0x60155b02e000 PID 2558430 
Removing child 0x60155b02e000 PID 2558430 from chain.
  Successfully remade target file 'main.o'.
 Finished prerequisites of target file 'hello.out'.
Must remake target 'hello.out'.
gcc -o bin/hello.out obj/func.o obj/main.o
Putting child 0x60155b02e240 (hello.out) PID 2558433 on the chain.
Live child 0x60155b02e240 (hello.out) PID 2558433 
Reaping winning child 0x60155b02e240 PID 2558433 
Live child 0x60155b02e240 (hello.out) PID 2558436 
Target File => bin/hello.out
Reaping winning child 0x60155b02e240 PID 2558436 
Removing child 0x60155b02e240 PID 2558436 from chain.
Successfully remade target file 'hello.out'.

可以发现主要是目标路径的设置问题,比如:File ‘hello.out’ does not exist.等等,这你能受得了???

所以,改成这样就没毛病辣:

vpath %.h include
vpath %.c src

OBJS := func.o main.o
HEADERDIR = -Iinclude
OBJDIR = obj
BINDIR = bin

$(BINDIR)/hello.out : $(addprefix $(OBJDIR)/, $(OBJS))
    gcc -o $@ $^
    @echo "Target File => $(BINDIR)/$@"

$(OBJDIR)/%.o : %.c
    gcc $(HEADERDIR) -o $@ -c $<

.PHONY: clean

clean:
    -rm -rf $(OBJDIR)/*.o $(BINDIR)/hello.out    

所以说整Makefile的时候,目标和依赖都要仔细一点,当然了,写错了用make的debug也可以排查,但是如果Makefile文件比较大,最好是一步一回头。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值