make 识别不出 .h 头文件的修改,怎么回事?

道哥分享

    不知道各位小伙伴是否碰到过这样的情况:
    一个 .c 文件 include 另一个 .h 头文件,使用 Makefile 来构建(编译)应用程序。
    第一次编译、执行,很正常!
    但是此时,如果修改了 .h 头文件,再次编译时,就出现问题了:
    预期的执行流程是:make 发现 .h 头文件的修改时间更新,于是重新编译包含这个头文件的所有 .c 文件。
    可实际的结果却是:make 并没有识别出 .h 头文件的修改。
    这是怎么回事呢?让我们一一道来。
    简单的代码示例
    一个头文件:hello.h
    #ifndef _HELLO_
    #define _HELLO_
    #define  NUM    1
    #endif
    一个源文件:main.c
    #include <stdio.h>
    #include "hello.h"
    int main(int argc, char *agv[])
    {
        printf("NUM = %d ", NUM);
        return 0;
    }
    Makefile 文件:
    OBJS := main.o
    TARGET := main
    all : $(OBJS)
     gcc -o $(TARGET) $(OBJS)
    %.o: %.c
     gcc $< -c -o $@
    现在我们来第一次执行 make,编译一下:
    $ make
    gcc main.c -c -o main.o
    gcc -o main main.o
    执行一下:
    $ ./main
    NUM = 1
    我们现在把 hello.h 文件中的 NUM 改成 2,现在的文件修改时间是:
    $ ll
    total 28
    -rw-rw-r-- 1 root root   58 Jun  7 20:52 hello.h
    -rwxrwxr-x 1 root root 8608 Jun  7 20:51 main*
    -rw-rw-r-- 1 root root  122 Jun  7 20:51 main.c
    -rw-rw-r-- 1 root root 1528 Jun  7 20:51 main.o
    -rw-rw-r-- 1 root root  100 Jun  7 20:51 Makefile
    然后再执行 make 指令,编译一下:
    $ make
    gcc -o main main.o
    可以看到:make 只执行了 Makefile 中的链接指令(从目标文件 main.o 到可执行文件 main),并没有执行 gcc main.c -c -o main.o 这条编译指令来重新编译目标文件。
    也就说明:make 并没有识别出 hello.h 这个头文件已经被改动了,尽管它“应该”可以从文件的修改时间上发现!
    为什么会这样?
    我们来看一下 Makefile 中的这个规则:
    %.o: %.c
     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 操作。
    
    
    1  2  下一页>