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

不知道各位小伙伴是否碰到过这样的情况:

在富源等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站设计制作、成都网站制作 网站设计制作按需策划设计,公司网站建设,企业网站建设,成都品牌网站建设,全网营销推广,成都外贸网站建设,富源网站建设费用合理。

一个 .c 文件 include 另一个 .h 头文件,使用 Makefile 来构建(编译)应用程序。

第一次编译、执行,很正常!

但是此时,如果修改了 .h 头文件,再次编译时,就出现问题了:

预期的执行流程是:make 发现 .h 头文件的修改时间更新,于是重新编译包含这个头文件的所有 .c 文件。

可实际的结果却是:make 并没有识别出 .h 头文件的修改。

这是怎么回事呢?让我们一一道来。

简单的代码示例

一个头文件:hello.h

  
 
 
 
  1. #ifndef _HELLO_ 
  2. #define _HELLO_ 
  3.  
  4. #define  NUM    1 
  5.  
  6. #endif 

一个源文件:main.c

  
 
 
 
  1. #include  
  2. #include "hello.h" 
  3.  
  4. int main(int argc, char *agv[]) 
  5.     printf("NUM = %d \n", NUM); 
  6.     return 0; 

Makefile 文件:

  
 
 
 
  1. OBJS := main.o  
  2. TARGET := main 
  3.  
  4. all : $(OBJS)  
  5.     gcc -o $(TARGET) $(OBJS) 
  6.  
  7. %.o: %.c  
  8.     gcc $< -c -o $@ 

现在我们来第一次执行 make,编译一下:

  
 
 
 
  1. $ make 
  2. gcc main.c -c -o main.o 
  3. gcc -o main main.o 

执行一下:

  
 
 
 
  1. $ ./main  
  2. NUM = 1 

我们现在把 hello.h 文件中的 NUM 改成 2,现在的文件修改时间是:

  
 
 
 
  1. $ ll 
  2. total 28 
  3. -rw-rw-r-- 1 root root   58 Jun  7 20:52 hello.h 
  4. -rwxrwxr-x 1 root root 8608 Jun  7 20:51 main* 
  5. -rw-rw-r-- 1 root root  122 Jun  7 20:51 main.c 
  6. -rw-rw-r-- 1 root root 1528 Jun  7 20:51 main.o 
  7. -rw-rw-r-- 1 root root  100 Jun  7 20:51 Makefile 

然后再执行 make 指令,编译一下:

  
 
 
 
  1. $ make 
  2. gcc -o main main.o 

可以看到:make 只执行了 Makefile 中的链接指令(从目标文件 main.o 到可执行文件 main),并没有执行 gcc main.c -c -o main.o 这条编译指令来重新编译目标文件。

也就说明:make 并没有识别出 hello.h 这个头文件已经被改动了,尽管它“应该”可以从文件的修改时间上发现!

为什么会这样?

我们来看一下 Makefile 中的这个规则:

  
 
 
 
  1. %.o: %.c  
  2.     gcc $< -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 的依赖!

注意:所有的操作过程没有执行 clean 操作。

最简单、无脑的方法

既然知道了原因,那就好办了,我们手动把头文件 hello.h 加到依赖中,不就可以了吗?!

把 Makefile 中最后面几句修改成下面这样:

  
 
 
 
  1. HEADERS := hello.h 
  2. %.o: %.c ${HEADERS} 
  3.     gcc $< -c -o $@ 

也就是把 .h 文件,也加入到 .o 文件的依赖中,这样的话,每次修改 .h 文件后,再执行 make 指令时,就可以重新编译 .o 目标文件了。

您可试一下,这样做肯定是没有问题的。

到此,问题是被解决了,但是总觉得这样的方式比较粗鲁。

想一下:如果有很多的 .c 和 .h 文件呢,总不能手动一个一个添加吧?

高级一点的方法

修改 Makefile 为下面这样:

  
 
 
 
  1. OBJS := main.o  
  2. TARGET := main 
  3.  
  4. all : $(OBJS)  
  5.     gcc -o $(TARGET) $(OBJS) 
  6.  
  7. -include *.d 
  8. %.o: %.c  
  9.     gcc $< -c -MMD -o $@ 

改动部分有 2 处:

1. 添加了 -include *.d 指令;

2. gcc 编译指令中,添加了 -MMD 参数;

我们先执行一下试试。第一次编译:

  
 
 
 
  1. $ ll      // 查看当前文件 
  2. total 12 
  3. -rw-rw-r-- 1 root root  58 Jun  7 21:06 hello.h 
  4. -rw-rw-r-- 1 root root 122 Jun  7 20:51 main.c 
  5. -rw-rw-r-- 1 root root 119 Jun  7 21:05 Makefile 
  6. $  
  7. $ make    // 编译 
  8. gcc main.c -c -MMD -o main.o 
  9. gcc -o main main.o 
  10. $  
  11. $ ll      // 再次查看当前文件 
  12. total 32 
  13. -rw-rw-r-- 1 root root   58 Jun  7 21:06 hello.h 
  14. -rwxrwxr-x 1 root root 8608 Jun  7 21:06 main* 
  15. -rw-rw-r-- 1 root root  122 Jun  7 20:51 main.c 
  16. -rw-rw-r-- 1 root root   23 Jun  7 21:06 main.d 
  17. -rw-rw-r-- 1 root root 1528 Jun  7 21:06 main.o 
  18. -rw-rw-r-- 1 root root  119 Jun  7 21:05 Makefile 
  19. $  
  20. $ ./main  // 执行 
  21. NUM = 1 

有没发现:多出了一个文件 main.d,该文件内容是:

  
 
 
 
  1. main.o: main.c hello.h 

这个文件正是因为 Makefile 中的 -MMD 这个参数导致生成的,而它的内容正是我们需要的目标文件依赖信息。

然后在 Makefile 中,include 这个 .d 文件,从而让 make 知道:main.o 文件依赖于 main.c 和 hello.o 这 2 个文件。

这个时候,我们再来修改 hello.h 中的内容,例如:把 NUM 改成 10,再次编译、执行:

  
 
 
 
  1. $ make 
  2. gcc main.c -c -MMD -o main.o 
  3. gcc -o main main.o  
  4. $ ./main 
  5. NUM = 10 

本文转载自微信公众号「IOT物联网小镇」,可以通过以下二维码关注。转载本文请联系IOT物联网小镇公众号。

本文标题:Makefile-只修改了.h头文件,编译为什么不起作用?
当前URL:http://www.mswzjz.com/qtweb/news48/175298.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联