当前位置: 首页 > 科技观察

Makefile-只修改了.h头文件,为什么编译不通?

时间:2023-03-12 12:48:28 科技观察

不知道大家有没有遇到过这样的情况:一个.c文件包含另一个.h头文件,使用Makefile构建(编译)应用程序。第一次编译执行是正常的!但此时如果.h头文件被修改,再次编译时就会出现问题:预期的执行过程是:make发现.h头文件的修改时间有更新,所以重新编译所有。包含此头文件的c文件。但实际结果是:make不识别.h头文件的修改。这里发生了什么?让我们来看看。简单代码示例头文件:hello.h#ifndef_HELLO_#define_HELLO_#defineNUM1#endif源文件:main.c#include#include"hello.h"intmain(intargc,char*agv[]){printf("NUM=%d\n",NUM);return0;}Makefile:OBJS:=main.oTARGET:=mainall:$(OBJS)gcc-o$(TARGET)$(OBJS)%.o:%.cgcc$<-c-o$@现在我们第一次执行make,编译:$makegccmain.c-c-omain.ogcc-omainmain.o执行:$./mainNUM=1我们现在把hello.h文件的NUM改了到2,当前文件修改时间为:$lltotal28-rw-rw-r--1rootroot58Jun720:52hello.h-rwxrwxr-x1rootroot8608Jun720:51main*-rw-rw-r--1rootroot122Jun720:51main.c-rw-rw-r--1rootroot1528Jun720:51main.o-rw-rw-r--1rootroot100Jun720:51Makefile然后执行make命令,编译:$makegcc-omainmain.o可以看到:make只执行Makefile中的链接命令(从目标文件main.o到可执行文件main),不执行编译指令gccmain.c-c-omain.o重新编译目标文件。换句话说:make不承认头文件hello.h被改变了,虽然从文件的修改时间“应该”能找到!为什么会这样?我们来看看Makefile中的规则:%。o:%.cgcc$<-c-o$@目标文件main.o只依赖main.c文件,不依赖hello.h文件。make的执行规则是:只有当目标文件不存在,或者依赖文件比目标文件新时,才会执行编译命令。因此,虽然修改了hello.h,但它并不是目标文件main.o的依赖。make发现:main.o在当前目录下已经存在,而且比main.c新,所以不会重新编译main.o。所以即使修改了hello.h也是不行的,因为make根本不把hello.h当成main.o的依赖!注意:所有操作不执行干净操作。最简单无脑的方法既然知道了原因,就好办了。我们手动将头文件hello.h添加到依赖中,不就可以了吗?!将Makefile中的最后几句改为:HEADERS:=hello.h%.o:%.c${HEADERS}gcc$<-c-o$@就是将.h文件添加到.o的依赖中文件。这样的话,每次修改.h文件后,执行make命令时,都可以重新编译.o目标文件。你可以试试,肯定没问题的。至此,问题已经解决,但是总觉得这种方式很粗鲁。想一想:如果.c和.h文件很多,总不能手动一个一个添加吧?更高级的方法是修改Makefile如下:OBJS:=main.oTARGET:=mainall:$(OBJS)gcc-o$(TARGET)$(OBJS)-include*.d%.o:%.cgcc$<-c-MMD-o$@有2个变化:1.添加了-include*.d指令;2.gcc在编译指令中,增加了-MMD参数;让我们先试试看。第一次编译:$ll//查看当前文件total12-rw-rw-r--1rootroot58Jun721:06hello.h-rw-rw-r--1rootroot122Jun720:51main.c-rw-rw-r--1rootroot119Jun721:05Makefile$$make//编译gccmain.c-c-MMD-omain.ogcc-omainmain.o$$ll//再次查看当前文件total32-rw-rw-r--1rootroot58Jun721:06hello.h-rwxrwxr-x1rootroot8608Jun721:06main*-rw-rw-r--1rootroot122Jun720:51main.c-rw-rw-r--1rootroot23Jun721:06main.d-rw-rw-r--1rootroot1528Jun721:06main.o-rw-rw-r--1rootroot119Jun721:05Makefile$$./main//执行NUM=1,有没有发现多了一个文件main.d,里面的内容是:main.o:main.chello.h这个文件是由于-MMD参数在Makefile生成了,它的内容正是我们需要的目标文件依赖信息。然后在Makefile中,包含这个.d文件,让make知道main.o文件依赖于main.c和hello.o这两个文件。这时候我们修改一下hello.h中的内容,例如:将NUM改为10,再次编译执行:$makegccmain.c-c-MMD-omain.ogcc-omainmain.o$$./mainNUM=10这篇文章是转载自微信公众号“IOT物联网小镇”,可通过以下二维码关注。转载本文请联系物联小镇公众号。