Makefile中3个常用自动化变量

 在Makefile,有三个常用也很好用的自动化变量:$@、$^、$<,所谓自动化变量是在模式规则中定义的一系列文件自动挨个的去除,直至所有的符合模式的文件都取完。这么说可能比较绕,我们可以简单直白的理解,我们写的应用程序,稍微简单的也要有几个文件(.c、.h等),那么复杂的可能有几百,几千,甚至几十万(kernel),我们在编写Makefile时,如果逐个文件去编译,链接,那是绝不可能的,所以我们需要一种自动规则,一条命令就能干很多重复的事儿,在C编程里,我们有各种循环操作,比如for、while、do等等。那么自动化变量就是用于Makefile中能够自动循环执行命令的变量,而且这些自动化变量还特别“智能”,会自动识别、切换。

    先简单的说明一下这3个自动化变量的含义:

    $@

    表示目标集,“集”的意思就是组合,全部,有多个目标,$@就是目标集合。

    $^

    所有依赖目标的集合,注意,这里说的是“依赖”,也就是目标的组成元素。

   $<

    依赖目标中的第一个目标名字,也就是上面说的$^中的第一个元素。

   特别注意:我们可能会有一个疑惑,这个自动化变量的应用范围是什么?是整个Makefile吗?答案是:不是!

   我简单的认为:自动化变量的应用范围是当前目标,Makefile中可以有很多的目标,但是终极目标只有1个,就是第一个,而其他的组成目标,也是需要编译的,所以我们在使用自动化变量时,它的应用范围只限于当前目标,这一点我们详细举例来说:

假设我们有一个应用工程,包含5个文件,分别为 main.c    func1.c  func1.h   func2.c   func2.h,代码如下:

    /*------------------- main.c    ---------------------*/
    #include "func1.h"
    #include "func2.h"
     
    int main(int argc, char **arcv)
    {
     
        func1("hello");
        
        func2("hello");
    }
     
    /*------------------- func1.c    ---------------------*/
    #include "func1.h"
    #include <stdio.h>
     
    void func1(char *print_str)
    {
        printf("this is func1 %s \n", print_str);
    }
     
    /*------------------- func1.h    ---------------------*/
    void func1(char *print_str);
     
    /*------------------- func2.c    ---------------------*/
    #include "func2.h"
    #include <stdio.h>
     
    void func1(char *print_str)
    {
        printf("this is func2 %s \n", print_str);
    }
     
    /*------------------- func2.h    ---------------------*/
    void func2(char *print_str);
     

 Makefile编写如下:

    main : main.o func1.o func2.o
        gcc main.o func1.o func2.o -o  main
     
    main.o : main.c func1.h func2.h
        gcc -c main.c
     
    func1.o : func1.c func1.h
        gcc -c func1.c
     
    func2.o : func2.c func2.h
        gcc -c func2.c
     
    .PHONY : clean
    clean :
        rm *.o

   这么编写是比较中规中矩的,如果考虑到Makefile的隐晦规则(潜规则),只需要前两行就行了,因为make会自动推导。

  如果文件不是5个,而是50、500个或者更多,我们很显然不能这么干,这个时候就需要自动化变量了,我们可以使用这3个自动化变量先把上面的Makefile初步简化一下,如下所示:

    main : main.o func1.o func2.o
        gcc $^ -o  $@
     
    main.o : main.c func1.h func2.h
        gcc -c $<
     
    func1.o : func1.c func1.h
        gcc -c $<
     
    func2.o : func2.c func2.h
        gcc -c $<
     
    .PHONY : clean
    clean :
        rm *.o main

   看到这里,可能会疑惑,这叫哪门子简化,不就是符号替换吗,别着急,上面的代码只是为了说明这3个自动化变量代表什么,因为能替代,恰恰就说明了他们的作用,这里再重复,分析下:

     $@ —— 目标集,首先必须是“目标”,其次这是个集,可以是1个,也可以是多个。

     $^—— 所有的依赖对象集,如果觉得拗口,可以理解为,所有的组成元素,这是个集,可以是1个,也可以是多个。

    $< —— 依赖对象集中的第一个,这里要说明一下,gcc只能编译*.c和.S文件,不能编译*.h头文件的,所以上面的

    gcc -c $<  表示的是 gcc -c  *.c,如果我们写成  gcc -c  $^,会报错,因为这个展开来变成了gcc -c  *.c  *.h

  从这里也可以验证之前说的话,自动化变量很智能,其应用范围仅限于当前目标,不是全范围,如果是全范围就乱套了。所以每个目标都可以使用这些自动化变量。

    那么我们进一步简化Makefile,如下:

    main : main.o func1.o func2.o
        gcc $^ -o $@
     
    .c : .o
        gcc -c $<
     
    .PHONY : clean
    clean :
        rm *.o main

   第一个目标的命令中$^代表所有依赖元素集,也就是main.o func1.o  func2.o,$@代表最终的目标集,这里只有一个:main

   .c : .o命令是Makefile中 静态模式的用法,这个名字我觉得翻译的不够形象,还不如叫自动循环命令呢,这里简单的说下,就是告诉make,所有的.o文件有对应名字的.c文件编译获得,所以下面的命令中 $<表示第一个依赖元素,到这里才会豁然开朗,

.c:.o会执行很多次(取决于有多少个.c文件),每一次执行,“$<”都代表第一个元素,也就是所谓的.c文件。非常灵活、智能。

所以这条命令还可以修改如下:

    .o : .c
        gcc -c $< -o $@

  看到了把,原来是.c : .o,现在反过来了,变成了 .o : .c,但是对应命令也变了,展开来就是 gcc -c xx.c  -o  xx.o,这条命令的逻辑仍然是对的,到这里应该就能理解自动化变量的“自动”二字了,所谓自动,就是智能,管你写的什么顺序,我万变不离其宗,只按照它的理解去做,只去第一个($<)、所有依赖元素($^)、所有目标集($@),而且应用范围仅限于当前命令行对应的目标依赖关系,下一个目标会再智能转换。
————————————————
版权声明:本文为CSDN博主「猪哥-嵌入式」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012351051/article/details/88594616

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值