zoukankan      html  css  js  c++  java
  • linux驱动学习(二) Makefile高级【转】

    转自:http://blog.csdn.net/ghostyu/article/details/6866863

    版权声明:本文为博主原创文章,未经博主允许不得转载。
    
    在我前一篇写的【 linux驱动学习(一)Makefile基础】中,Makefile写的中规中矩,其实Makefile写法很灵活,可以写得很简洁,而且减少出错的可能,现在就把之前写的Makefile改进一下。
    
    [plain] view plain copy
    
        main: main.o hello.o word.o  
            gcc main.o hello.o word.o -o main  
          
        main.o:main.h hello.h word.h  
        hello.o:hello.h  
        word.o:word.h  
          
        clean:  
            echo "cleanning project"  
            -rm main *.o  
            echo "clean completed"  
          
        .PHONY:clean  
    
    
    这是不是比以前简单多了,但是main.o hello.o word.o这三个目标的编译命令都没有,怎么会编译呢,执行make试试看
    
    [plain] view plain copy
    
        <localhost.localdomain:/data/ghostyu/linuxc> make  
        cc    -c -o main.o main.c  
        cc    -c -o hello.o hello.c  
        cc    -c -o word.o word.c  
        gcc main.o hello.o word.o -o main  
        <localhost.localdomain:/data/ghostyu/linuxc>  
    
    
    cc是什么呢,执行下which cc
    [plain] view plain copy
    
          
    
    [plain] view plain copy
    
        <localhost.localdomain:/data/ghostyu/linuxc> which cc  
        /usr/bin/cc  
    
    事实上cc指向的也是gcc
    
    其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。
    
    [plain] view plain copy
    
        # default  
        OUTPUT_OPTION = -o $@  
          
        # default  
        CC = cc  
          
        # default  
        COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c  
          
        %.o: %.c  
        #  commands to execute (built-in):  
                $(COMPILE.c) $(OUTPUT_OPTION) $<  
    
    以上是内建规则中关于隐含规则的部分
    
    ‘#’为注释符,跟‘//’一样
    
    ‘CC’为Makefile变量
    
    '$@'与‘$<’为特殊变量,'$@'的取值为规则的目标,‘$<’取值为规则的第一个条件。
    
    %.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。
    CFLAG CPPFLAG TARGET_ARCH未定义,展开为空,
    
    
    现在来分析一下,隐含规则是怎样解析Makefile的。
    
    
    首先,OUTPUT_OPTION是一个变量,
    
    [plain] view plain copy
    
        OUTPUT_OPTION = -o $@  
    
    这边变量展开为:“-o main.o”
    
    
    其次,展开COMPILE变量
    
    [plain] view plain copy
    
        # default  
        COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c  
    
    为:“cc    -c”。中间有四个空格。
    
    
    然后
    
    [plain] view plain copy
    
        %.o: %.c  
    
    这就相当于 main.o:main.c
    
    
    最后
    
    [plain] view plain copy
    
        $(COMPILE.c) $(OUTPUT_OPTION) $<  
    
    注意开头的空白为tab键,8个字符,这是Makefile规定的,gcc命令等必须tab开头识别
    
    展开为:
    
    [plain] view plain copy
    
        cc    -c -o main.o main.c  
    
    完整的:
    
    [java] view plain copy
    
        main.o:main.h hello.h word.h  
        main.o:main.c  
                cc    -c -o main.o main.c  
    
    这就隐含的包含了各个条件的编译
    
    注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:
    
    比如下列:
    
    [plain] view plain copy
    
        main.o: main.c main.h hello.h word.h  
            gcc -c main.c  
    
    可以写成:
    
    [java] view plain copy
    
        main.o:main.h hello.h word.h  
        main.o:main.c  
            gcc -c main.c  
    
    
    写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。
    
    ****************************Makefile 变量**************************
    [plain] view plain copy
    
        var = $(gho)  
        gho = yu  
          
        all:  
                @echo $(var)  
    
    make all时,输出 yu
    [plain] view plain copy
    
        <localhost.localdomain:/data/ghostyu/linuxc/test> make all  
        yu  
    
    这就是Makefile中的变量,与TCL脚本的变量很类似
    之所以输出yu 而非 gho,是因为‘=’不用立即展开,若果在第一等号前加‘:’,试试。
    [plain] view plain copy
    
        <pre name="code" class="plain" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">var := $(gho)  
        gho = yu  
          
        all:  
                @echo $(var)</pre>  
        <pre></pre>  
        <pre></pre>  
        <pre></pre>  
    
    这样make all 后输出为空,这是因为var:=$(gho),遇到‘:’将立即展开,gho此时又为定义,因此输出空,若gho=yu放在前面,则依然输出yu
    
    还有一个比较有用的赋值运算符是?=,例如var ?= $(gho)的意思是:如果var没有定义过,那么?=相当于=,定义var的值是$(gho),但不立即展开;如果先前已经定义了var,则什么也不做,不会给var重新赋值。
    
    +=运算符可以给变量追加值
    [plain] view plain copy
    
        var = main.o  
        var += $(gho)  
        gho = hello.o word.o  
    
    这是var的值为 main.o hello.o word.o
    
    常用的特殊变量有四个,出去之前用的$@与$<,还有$? 和$^
    
        $@,表示规则中的目标。
    
        $<,表示规则中的第一个条件。
    
        $?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
    
        $^,表示规则中的所有条件,组成一个列表,以空格分隔。
    
    因此
    [plain] view plain copy
    
        main: main.o hello.o word.o  
            gcc main.o hello.o word.o -o main  
    
    可以改写为:
    [plain] view plain copy
    
        main: main.o hello.o word.o  
            gcc $^ -o $@  
    
    这样的好处是,即使以后又往条件里加了新的目标,编译命令也不需要修改,既省事,又减少出错。
    
    $?也很有用,有时候希望只对更新过的条件进行操作。
    
    
    之前我们看到make的隐含规则数据库中用到了很多变量,有些变量没有定义(例如CFLAGS),有些变量定义了缺省值(例如CC),我们写Makefile时可以重新定义这些变量的值,也可以在缺省值的基础上追加。以下列举一些常用的变量。
    
    AR
    
        静态库打包命令的名字,缺省值是ar。
    ARFLAGS
    
        静态库打包命令的选项,缺省值是rv。
    AS
    
        汇编器的名字,缺省值是as。
    ASFLAGS
    
        汇编器的选项,没有定义。
    CC
    
        C编译器的名字,缺省值是cc。
    CFLAGS
    
        C编译器的选项,没有定义。
    CXX
    
        C++编译器的名字,缺省值是g++。
    CXXFLAGS
    
        C++编译器的选项,没有定义。
    CPP
    
        C预处理器的名字,缺省值是$(CC) -E。
    CPPFLAGS
    
        C预处理器的选项,没有定义。
    LD
    
        链接器的名字,缺省值是ld。
    LDFLAGS
    
        链接器的选项,没有定义。
    TARGET_ARCH
    
        和目标平台相关的命令行选项,没有定义。
    OUTPUT_OPTION
    
        输出的命令行选项,缺省值是-o $@。
    LINK.o
    
        把.o文件链接在一起的命令行,缺省值是$(CC) $(LDFLAGS) $(TARGET_ARCH)。
    LINK.c
    
        把.c文件链接在一起的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)。
    LINK.cc
    
        把.cc文件(C++源文件)链接在一起的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)。
    COMPILE.c
    
        编译.c文件的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c。
    COMPILE.cc
    
        编译.cc文件的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c。
    RM
    
        删除命令的名字,缺省值是rm -f。
    
    
    ***************************自动处理头文件的依赖关系*************************
    
    [plain] view plain copy
    
        all:main  
        main: main.o hello.o word.o  
            gcc main.o hello.o word.o -o main  
          
        main.o:main.h hello.h word.h  
        hello.o:hello.h  
        word.o:word.h  
          
        clean:  
            echo "cleanning project"  
            -rm main *.o  
            echo "clean completed"  
          
        .PHONY:clean  
    
    
    现在Makefile写成上面的形式,默认make all,这样有个确定,写Makefile时要查个每个源文件,确定其包含的头文件,很容易出错,为了解决这个问题,可用用gcc -M查看源文件的依赖关系,-M选项会把系统头文件也找出来,如果不需要,可以用-MM选项。
    [plain] view plain copy
    
        <localhost.localdomain:/data/ghostyu/linuxc> gcc -MM *.c  
        hello.o: hello.c hello.h  
        main.o: main.c main.h hello.h word.h  
        word.o: word.c word.h  
    
    
    
    现在的问题是怎样将上述依赖包含在Makefile中。
    GNUlinux建议这样:
    [plain] view plain copy
    
        all:main  
        main: main.o hello.o word.o  
            gcc main.o hello.o word.o -o main  
          
        sources = main.c hello.c word.c  
          
        include $(sources:.c=.d)  
          
        %.d: %.c  
            set -e; rm -f $@;   
            $(CC) -MM $(CPPFLAGS) $< > $@.
        ;   
            sed 's,$∗.o[ :]*,1.o $@ : ,g' < $@.
         > $@;   
            rm -f $@.
          
  • 相关阅读:
    Docker 系列(九):docker-compose
    Docker实践:部署Mysql
    Linux 查看端口占用情况
    Docker实践:部署Rabbitmq容器
    VS遇到的一些问题及解决办法(持续更新)
    vue-cli2.0引入nprogress 进度条
    ElmentUI全局禁止点击遮罩层关闭el-dialog弹窗
    mongodb基础教程
    C# Socket网络编程精华篇
    MySQL 日期计算
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/7211748.html
Copyright © 2011-2022 走看看