zoukankan      html  css  js  c++  java
  • makefile自动生成目标与依赖的关系

    有main.c:

    1 #include <stdio.h>
    2 #include "command.h" 
    3 
    4 int main(int argc, const char *argv[])
    5 {
    6         printf("run in main
    ");
    7         return 0;
    8 }

    commad.h:

    1 #ifndef __COMMAND_H__
    2 #define __COMMAND_H__
    3 
    4 #define PI 3.14159
    5 
    6 #endif

      之前写的makefile都是使用下面这种形式的静态规则:

    1 OBJ+=main.o
    2 
    3 $(OBJ):%.o:%.c
    4     $(CC) -c $(CFLAGS) $< -o $@

      这种方法有个比较致命的缺点,比如main.c如果包含了一个头文件commad.h,我改动了这个头文件,由于main.o的依赖中没包含commad.h,所以main.o不会重新编译,显然这不是我想要的结果,通常我的做法是如果我修改了commad.h里面的一个宏MY_MCRO,使用souce insight的搜索共功能

      将最后一个选项: Touch files and cause recompile勾选上,这样被搜索到的文件就被touch了,或者麻烦点自己用shell语句实现同样的功能。但是如果.h文件里面如果改动了很多地方,这种做法显然太麻烦了,如果gcc的-M或者-MM选项那么就可以完美解决这个问题。

      首先gcc -M main.c输出:

      main.o: main.c /usr/include/stdc-predef.h /usr/include/stdio.h
         /usr/include/features.h /usr/include/i386-linux-gnu/sys/cdefs.h
         /usr/include/i386-linux-gnu/bits/wordsize.h
         /usr/include/i386-linux-gnu/gnu/stubs.h
         /usr/include/i386-linux-gnu/gnu/stubs-32.h
         /usr/lib/gcc/i686-linux-gnu/4.8/include/stddef.h
         /usr/include/i386-linux-gnu/bits/types.h
         /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/libio.h
         /usr/include/_G_config.h /usr/include/wchar.h
         /usr/lib/gcc/i686-linux-gnu/4.8/include/stdarg.h
         /usr/include/i386-linux-gnu/bits/stdio_lim.h
         /usr/include/i386-linux-gnu/bits/sys_errlist.h command.h
     gcc -MM main.c输出:

      main.o: main.c command.h

      这就是目标与依赖的关系,利用gcc的预编译功能,找到目标依赖的.c .h文件,这个选项是专门为makefile准备的,-MM只输出非系统的.h文件,系统头文件不会变,所以一般用-MM。一个模板:

     1 objects = main.o
     2 
     3 CFLAGS:= -g
     4 
     5 main:$(objects)
     6     cc  $(objects) -o main
     7 
     8 -include $(objects:.o=.d)
     9 %.d:%.c
    10     @set -e; rm -f $@; 
    11             $(CC) -MM $< > $@.$$$$; 
    12             sed 's,($*).o[ : ]*,1.o $@ : ,g' < $@.$$$$ > $@; 
    13             rm -f $@.$$$$
    14 
    15 .PHONY:clean
    16 clean:
    17     @-rm main -f $(objects) *.d *.d.*

      整个makefile的执行过程,先include文件,发现main.d不存在,但是下面有main.d的生成规则, main.d:main.c, main.d依赖于main.c,通过下面的规则生成了main.d文件,main.d文件的内容是:

     1 main.o main.d : main.c command.h 

      因此执行完include,实际得到的makefile会是这个样子:

    objects = main.o
    
    CFLAGS:= -g
    
    main:$(objects)
        cc  $(objects) -o main
    
    main.o main.d : main.c command.h
    
    %.d:%.c
        @set -e; rm -f $@; 
                $(CC) -MM $(INCLUDE_DIRS) $< > $@.$$$$; 
                sed 's,($*).o[ : ]*,1.o $@ : ,g' < $@.$$$$ > $@; 
                rm -f $@.$$$$
    
    .PHONY:clean
    clean:
        @-rm main -f $(objects) *.d *.d.*

      这样以来,如果改动了main.c文件会导致 main.d文件和main.o文件重新编译或生成,改动command.h文件也会导致main.o main.d文件重新编译或生成。

      有一点需要稍微注意,就是include和生成.d文件那段最好放在终极目标的后面,否则生成终极目标的时候需要显示指明了,比如:make main, 因为如果include 和 %.d:%.c那段如果放终极目标之前,终极目标不是第一个目标了,makefile默认执行第一个目标。

  • 相关阅读:
    Codeforces Round #654 (Div. 2)A-E1
    android 学习receiver和发送广播,其中监听其他activity的启动demo;给activity加自定义权限只有指定有权限的app可以监听到
    任务栈Task的模式
    Activity生命周期学习笔记,和横竖切屏时候activity销毁时候保存数据和调用的方法
    Activity之间利用intent单个传递数据和批量传递数据
    Android学习-启动服务startActivityForResult调用activity并覆写onActivityResult()接收返回来的信息
    android学习之intent学习笔记
    android断点下载并显示进度,关于handler,和主线程不能联网采取子线程联网下载,和多线程下载学习
    Contentprovider学习笔记
    android学习之LayoutInflater的用法,在myAdapter getView()里将多个TextView组件压缩成一个View控件,并在listView里显示
  • 原文地址:https://www.cnblogs.com/thammer/p/4461733.html
Copyright © 2011-2022 走看看