解决C文件包含的头文件修改了,但C文件不重新编译的问题

对于Makefile,有位大神写得由浅到深,非常好,如下是链接
https://blog.csdn.net/weixin_42462202/article/details/88584668

当我们仅仅只修改了project中的头文件时,如果引用头文件的.c文件对应的目标文件都已经生成了,直接编译,make并不能发现头文件的修改,所以我们有如下的解决办法
1、把修改的头文件的对应的已经存在的目标文件删掉,重新生成目标文件,我们通常是直接make clean。但是这种方法有个不好的问题,如果我们project非常庞大,比如我们只是修改了内核中的某个文件的头文件,重新编译非常耗费时间,所以我们需要一种更好的办法
2、指明每一个目标文件的依赖关系

  1 CC = gcc
  2 
  3 OBJS := a.o
  4 OBJS += b.o
  5 
  6 all: $(OBJS)
  7         $(CC) -o test $^
  8 
  9 %.o:%.c %.h
 10         $(CC) -c -O2 -o $@ $< 

我的这个测试程序里a.o和b.o都依赖头文件a.h,所以我在%.o:%.c后面指定 依赖 %.h。
同样如果一个工程非常庞大,而每个.c文件可能会依赖很多个.h文件,所以这也不是最好的解决办法
3、在介绍这种办法之前,我们先了解一下要用到的两个函数
foreach 函数和wildcard函数,我不讲解这个两个函数
回到我们的问题上来,我们面临的问题是make工具在生成目标文件时,只能找到和它同名的.c文件作为依赖,而对于头文件的依赖则不清楚,如果头文件改变了,对应的目标文件已经存在,而我们没有告诉make这其中的依赖关系,目标文件就会忽略头文件的改变。
怎么解决这一问题呢?
gcc知道其中的依赖关系

book@www.100ask.org:~/learning/Makefilelearning$ gcc -M a.c
a.o: a.c /usr/include/stdc-predef.h a.h /usr/include/stdio.h \
 /usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-linux-gnu/5/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
 /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
book@www.100ask.org:~/learning/Makefilelearning$ gcc -MM a.c
a.o: a.c a.h

所以我们应该想办法在Makefile中生成依赖文件,然后告诉make

 CROSSCOMPILE :=
 CC = $(CROSSCOMPILE)gcc
 
 objs := a.o
 objs += b.o
 
 all:$(objs)
         $(CC) -o test $^
 #Makefile通常把看到的第一个目标视为终极目标
 depfile := $(foreach f,$(objs),.$(f).d)
 depfile := $(wildcard $(depfile))
 
 ifneq ($(depfile),)
         include $(depfile)
 endif
 
 %.o:%.c
         $(CC) -Wp,-MD,.$@.d -c -o $@ $<
 
 .PHONY:clean
 clean:
         rm *.o
         rm test

碰到第一个目标后,会执行 $(CC) -o test $^
$^代表全部依赖,也就是objs,然而它还没有生成。如是会往下找
首先看到的是

 depfile := $(foreach f,$(objs),.$(f).d)
 depfile := $(wildcard $(depfile))
 #第一行foreach从objs中取出来每一个元素,在这里就是a.o和b.o,将它们一次视作f,然后执行.$(f).d这条指令
 #所以第一条的结果就是 depfile := .a.o.d .b.o.d  这两个并不是真的生成文件,而只是一个符号
 #第二条指令则是。。。
 ifneq ($(depfile),)
         include $(depfile)
 endif
 #如果depfile对于的不是空,我们就包含,因为第一次编译的时候,在这里还没有依赖文件,所以我们必须要这样条件判断
 #同时,第一次编译的时候也不要头文件依赖的指定。
 #但是当第一次编译过了,不仅生成了头文件,还生成了依赖文件,所以就可以找到头文件变更

接着有

%.o:%.c
         $(CC) -Wp,-MD,.$@.d -c -o $@ $<
#除了生成了$@,还通过-Wp,-MD,标志位生成了名为.$@.d的依赖文件
#如下是执行的结果
book@www.100ask.org:~/learning/Makefilelearning$ make
gcc -Wp,-MD,.a.o.d -c -o a.o a.c
gcc -Wp,-MD,.b.o.d -c -o b.o b.c
#当objs产生了,就可以执行
all:$(objs)
         $(CC) -o test $^
这个过程是链接,如果有动态库就在这里链接

4、我们模仿内核的Makefile体系架构给一个工程写一个Makefile

一个通用型Makefile至少需要三个部分
1、顶层目录的Makefile
2、顶层目录的Makefile.build
3、各个子目录下的Makefile
各个子目录下的Makefile是最容易写的
参考内核的模板,写了一个,如下

obj-y += disp_manager.o
obj-y += fb.o
obj-y += test/
#/test的Makefile
obj-y += test.o

顶层目录的Makefile
内核顶层目录的Makefile用到了如下的gnu工具

 283 AS              = $(CROSS_COMPILE)as
 284 LD              = $(CROSS_COMPILE)ld
 285 CC              = $(CROSS_COMPILE)gcc
 286 CPP             = $(CC) -E
 287 AR              = $(CROSS_COMPILE)ar
 288 NM              = $(CROSS_COMPILE)nm
 289 STRIP           = $(CROSS_COMPILE)strip
 290 OBJCOPY         = $(CROSS_COMPILE)objcopy
 291 OBJDUMP         = $(CROSS_COMPILE)objdump


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值