嵌入式学习笔记之Makefile规则和一些语法

在Linux下开发裸板程序的时候,我们一般用Makefile来组织管理这些程序和一些文件,本篇文章主要讲Makefile最基本的规则.

目录

简单引入:   

Makefile语法:

统配符:

变量:

Makefile函数

函数foreach:遍历

函数filter/filter-out:筛出

函数wildcard 寻找

函数patsubst 替换

综合实例



简单引入:   

这里从一个简单的例子来引入Makefile

    main.c:

   

    Func_b.c

   

    我们可以 gcc -o test main.c func_b.c 来生成可执行文件,最后 ./test输出结果:

    C程序à可执行程序需要经过四个步骤:

    预处理->编译->汇编->链接

    一般吧前三个步骤统称为编译,于是这条gcc -o test main.c func_b.c需要经过下面几个步骤

    1)对main.c执行: 预处理 编译 汇编的过程,main.c->xxx.s->xxx.o文件

    2)对func_b.c执行: 预处理 编译 汇编的过程,func_b.c->yyy.s->yyy.o文件

    3)最后讲1)和2)生成的.o文件链接在一起生成test可执行程序

这条语句有一个缺点,当.c文件多起来的时候,当我们修改其中一个.c文件的时候,其他所有的.c文件都需要经过预处理,编译,汇编过程,这是没有必要的,从上面步骤可以看出是先编译文件,最后将他们链接一起,所以只需要编译已经更改过的文件即可.

那如何确定哪些文件被修改?只需要比较文件的时间即可,被修改的文件的时间是新的,这里引入一个简单的Makefile最基本的规则

目标: 依赖1 依赖2 ….

[TAB]命令

当依赖比目标文件新的时候,或者目标文件不存在,就会执行下面的命令,注意命令前面是一个TAB键,不能用空格代替,将前面的例子用Makefile重写:

先新建一个Makefile文件

test:a.o b.o

    gcc -o test a.o b.o


a.o : a.c

    gcc -c -o a.o a.c


b.o : b.c

    gcc -c -o b.o b.c

 

/这里只需要输入make命令就可以生成可执行文件test了

Makefile语法:

统配符:

    $.o: 表示所有的.o文件

    %.c: 表示所有的.c文件

    $@: 表示目标

    $<: 表示第一个依赖文件

    $^: 表示所有的依赖文件

    于是上面的Makefile也可以写成:

   

后面的.PHONY是假想目标:

clean也是一个目标,但是一般直接make只是执行Makefile里面的第一个目标.但是它没有依赖,(所以只能是目标文件不存在的情况下才会执行命令)也就没有办法判断其依赖文件和clean的时间,所以如果文件里出现clean文件,我们又执行make clean命令的时候,就会提示:

clean is up to date

于是将clean确定为假象目标,这样就不会判断名为clean的存在了.

变量:

    Makefile中有俩个变量:

1. 简单变量(即时变量) :=

即值在定义的时候就被确定

2. 延时变量   =

其值需要在使用的时候才能被确定

?= 延时变量,如果是第一次定义就起效,如果前面已经对该变量定义则忽略这句

+= 附加

    下面用一个简单的例子来说明

注: 想使用这些变量的时候使用“$”来引用,如果不想看到命令是,可以在命令的前面加上"@"符号,就不会显示命令本身。当我们执行make命令的时候,make这个指令本身,会把整个Makefile读进去,进行全部分析,然后解析里面的变量。

  

make后输出:

分析:

  1. A := $(C) A是即时变量,在定义时就确定,但是此时C的值未空,所以A的值为空.

  2. B = $(C) B是延时变量,只有在使用到它的时候才确定,当执行make的时候,会解析makefile中所使用的变量, 先解析 C = abc 再去解析 C+= 123 ,此时C = abc123,故执行 @echo B = $(B)时,B的值为abc123

  3. D ?= dog 由于D变量在之前定义了,所以D = book, 如果将第四行去掉,D就等于dog了

Makefile函数

    Makefile里面可以包含很多函数,下面介绍几个常用的函数,引用一个函数用 “$”

函数foreach:遍历

    语法如下:

    $(foreach var, list, text)

    Var是一个局部变量,list是一个文件列表,test 是对var进行操作

    网上看到的介绍比较难理解,我个人理解是将list中的元素作为var取出,然后再用text对其做操作

    实例:

    Make后输出:

函数filter/filter-out:筛出

    语法如下:

    $(filter pattern, list) # 在list中取出符合pattern格式的值

    $(filter-out pattern, list) #在list中取出不符合pattern格式的值

    实例:

   

Make后结果:

  

%可以看作是代指

函数wildcard 寻找

    语法如下:

    $(wildcard pattern) # paterrn定义了文件名的格式,wildcard取出其中存在的文件

    (和filter/filter-out不同这是对当前目录下文件进行操作)

    返回存在文件的名字

    实例:

    在Makefile存在的目录下创建三个文件: a.c b.c c.d d.c

    Makefile:

    Files 是寻找出目录下所存在的 *.c文件

    File3 是在当前目录下寻找是否存在列表中的文件

    Make后结果

   

函数patsubst 替换

    语法如下:

    $(patsubst pattern, replacement, $(var))

    Patsubst函数是从vat变量中取出每一个值,如果符合pattern格式,就将其替换成replacement格式

    实例:

结果:

   

 

综合实例

    前面讲了makefile的一些语法和函数,下面做一个实例:

    建立 main.c a.c a.h文件

a.c中定义一个函数:

///

#include<stdio.h>

#include"a.h"

void func_A(void)

{

    printf("A is %d\n",A);

}

a.h对这个函数进行声明,并定义一个宏

#define A 200

void func_A(void);

main.c中调用这个函数

#include<stdio.h>

#include"a.h"

int main(void)

{

  func_A();

  return 0;

}

Makefile中:

test:main.o a.o

gcc -o test a.o main.o

%.o : %.c

gcc -c -o $@ $<

    编译可以正常输出 A is 200

    然后修改A的宏定义为600

    再次编译发现,输出还为200,并未改变,这是因为a.o依赖a.c和a.h但是在makefile中却并没有说明,所以我们更新a.h并不能导致a.o的更新,

    于是需要添加:

a.o:a.c a.h

这样每次修改a,h都可以使得Makefile识别到更新动作,从而输出正确的文件

但是对于一些较大的文件,其中的头文件成百上千,不可能一一写出,于是需要使用gcc命令使其自动生成依赖

可以参考文章:https://blog.csdn.net/qq1452008/article/details/50855810

这里用里面的几个选项:

gcc –M a.c //打印出依赖

gcc –M –MF a.c a.d //将上面的依赖写入文件a.d中

gcc -c –o a.o a.c –MD –MF a.d //编译生成a,o,并将依赖写入文件c.d中

修改后的Makefile如下:

1 –> 将objs变量将.o文件放在一起,

3 –> 利用前面讲到的替换函数将里面的文件(%就是将里bojs 里的全部文件)替换成 .%.d格式,(.%.d类似于隐藏文件)

4 -> 用寻找函数,将目录中已经存在的 .%.d文件都寻找出来,

6 -> test目标文件依赖于objs 也就是%.o文件

8 -> 这个语句可以理解为这个变量里的头文件全都包含起来

9 –> 所有的.o文件都依赖于.c文件

10 –> 通过gcc命令生成.d依赖文件,

于是我们修改任何.h文件,最终都会影响最后生成的文件,不用手工添加.h,文件,完成了头文件的依赖

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值