第11课 - 自动生成依赖关系(上)

1. 值得思考的问题

(1)目标文件(.o)是否只依赖于源文件(.c)?--------------源文件和头文件

(2)编译器如何编译源文件和头文件

    

 

2. 编译行为带来的缺陷

(1)预处理器头文件中的代码直接插入源文件

(2)编译器只通过预处理后源文件产生目标文件

综合上面两点规则中只以源文件为依赖,命令可能无法执行

 

3. 下面的 makefile 有没有问题?

该篇博客中涉及的三个源文件,func.h、func.c、main.c

func.h头文件

#ifndef FUNC_H
#define FUNC_H

#define HELLO "hello scott"

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"

int main()
{
    foo();

    return 0;
} 

 

 

原始的makefile.1

OBJS := func.o main.o

hello.out : $(OBJS)
    @gcc -o $@ $^
    @echo "Target File ==> $@"
 
$(OBJS) : %.o : %.c 
    @gcc -o $@ -c $<

运行结果:

  

 

  

分析:

    

       main.cfunc.c 都包含了 func.h

这个makefile乍一看是没有问题的,但是仔细想一下,当更改 func.h 头文件中的内容时由于目标文件比依赖文件要新,所以程序不会重新编译

  

makefile中,只有当依赖文件目标文件更新时(依赖文件的时间 > 目标文件的时间),才能触发目标对应命令的执行

 

解决方案:

  在依赖中添加 func.h 头文件,之后再去更改 func.h头文件中的内容,make会重新编译生成新的hello.out。

OBJS := func.o main.o

hello.out : $(OBJS)
    @gcc -o $@ $^
    @echo "Target File ==> $@"
    
$(OBJS) : %.o : %.c func.h
    @gcc -o $@ -c $<

 

4. 实验中解决方案的问题

(1)头文件作为依赖条件出现在每个目标对应的规则中

(2)当头文件改动任何源文件都将被重新编译(编译低效)

(3)当项目中头文件数量巨大时,makefile 将很难维护

 

5. 疯狂的想法

(1)通过命令自动生成对头文件的依赖

(2)将生成的依赖自动包含进makefile

(3)当头文件改动后,自动确认需要重新编译的文件

 

6. 预备工作(原材料)

  — Linux 命令 sed

  — 编译器依赖生成选项 gcc  -MM (gcc  -M)

6.1 Linux 中的 sed 命令

(1)sed 是一个流编辑器,用于流文本的修改增/删/查/改

(2)sed 可用于流文本中的字符串替换

(3)sed 字符串替换方式为:sed  'ssrcdesg'

    

 

6.2 sed 的正则表达式支持

(1)在 sed 中可以用正则表达式匹配替换目标

(2)并且可以使用匹配的目标生成替换结果

     

 

6.3 gcc 关键编译选项

 生成依赖关系

  • 获取目标完整依赖关系

      gcc  -M  test.c

  • 获取目标部分依赖关系  

      gcc  -MM  test.c

      gcc  -MM -E test.c

 

gcc -M main.c

  

 

 

gcc -MM main.c

  

 

 

gcc -MM main.c | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g'

  

 

 

7. 小技巧:拆分目标的依赖 

 将目标完整依赖拆分为多个部分依赖

   

编程实验:

.PHONY : test a b c

test : a b

test : b c

test : 
    @echo "$^"

 

运行结果:

  

 

posted @ 2018-09-05 23:55  梦心之魂  阅读(204)  评论(0编辑  收藏  举报