嵌入式Linux开发之Makefile

时间:2021-06-02 17:23:23   收藏:0   阅读:0

makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

makefile的好处就是:

—“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。二、节约编译时间(没改动的文件不编译)。

make是一个命令工具,是一个解释makefile中指令的命令工具。

一、Makefile规则

1.1 基本规则

一个简单的Makefile文件包含一系列的规则,其样式如下:

target:prerequisites
    command
    ...
    ...
=====================
目标 : 依赖文件
[tab键] 命令
      ...
      ...

这是一个文件依赖关系,也就是说target是由一个或多个目标文件依赖于prerequisites中的文件,其生成规则定义在command中,而且只要prerequisites中有一个以上的文件比target文件更新的话,command所定义的命令就会被执行,这是makefile的最基本规则,也是makefile中最核心的内容。

1.2 示例

我们仍然以hello.c文件为例:

#include <stdio.h>
int main(int argc,char *argv[])
{
  printf("Hello World!\n");
  return 0;
}

然后编写Makefile(这里使用的是gcc、而不是arm-linux-gcc):

ALL: hello.o

hello.o: hello.c
        gcc hello.c -o hello.o

编译并执行:

make
./hello.o

技术图片

二、Makefile函数 

2.1 获取匹配模式文件名函数wildcard

例如:

SRC = $(wildcard ./*.c)

匹配目录下所有的 .c 文件,并将其赋值给 SRC 变量。

2.2 模式替换函数patsubst

pat 是 pattern 的缩写,subst 是 substring 的缩写。

参数 “TEXT ”单词之间的多个空格在处理时被合并为一个空格,并忽略前导和结尾空格。

例如:

OBJ = $(patsubst %.c, %.o, $(SRC))

这个函数有三个参数,意思是取出 SRC 中所有的值,然后将 “.c” 替换为 “.o”,最后赋值给 OBJ 变量。

2.3 foreach 函数

函数“foreach ”不同于其它函数。它是一个循环函数。类似于 Linux 的 shell 中的for 语句:

2.4 过滤函数 -filter

“filter”函数可以用来去除一个变量中的某些字符串, 我们下边的例子中就是用到了此函数。

1).找出符合PATTERN 格式的值

2).找出不符合PATTERN 格式的值

假如我们目录下有很多个 “.c” 后缀的源文件,就不需要写很多条规则语句了,

2.5 示例

我们修改我们的Makefile文件:

SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))

ALL: hello.out

hello.out: $(OBJ)
        gcc $(OBJ) -o hello.out

$(OBJ): $(SRC)
        gcc -c  $(SRC) -o $(OBJ)

这里我们先将所有的 “.c” 文件编译为 “.o” 文件,这样后面更改某个 “.c” 文件时,其它的 “.c” 文件将不再编译,而只是编译有更改的 “.c” 文件,可以大大节约大项目中的编译速度。

需要注意的是:

三、makefile通配符

Makefile 中也有一些已经定义好的常用变量,这里介绍其中常用的3个。

3.1 $@

表示规则中目标,例如 hello.out

3.2 $<

表示规则中的第一个依赖条件,例如 hello.c

3.3 $^

表示规则中的所有依赖条件,由于我们示例中都只有一个依赖条件,这种情况下 $^ 和 $< 区别不大

3.4 示例

我们修改我们的Makefile文件:

SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))
 
ALL: hello.out
 
hello.out: $(OBJ)
        gcc -o $@ $<
 
$(OBJ): $(SRC)
        gcc -c -o $@ $<

四、其它常用功能

4.1 代码清理clean

我们可以编译一条属于自己的 clean 语句,来清理 make 命令所产生的所有文件。例如

SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))

ALL: hello.out

hello.out: $(OBJ)
        gcc -o $@ $<

$(OBJ): $(SRC)
        gcc -c -o $@ $<
clean:
        rm -rf $(OBJ) *.out

这样我们就可以使用make clean 命令来清理生成的文件了:

技术图片

提示:make命令是可以带上目标名的,如果make后面不跟目标名字的话,默认生成第一个目标,当带上目标名的话,生成指定的目标。

4.2 伪目标 .PHONY

上面我们写了一个 clean 语句,使得我们执行 “make clean” 命令的时候,可以清理我们生成的文件。

但是假如还存在一个文件名就是 clean 文件,那么我们再执行 “make clean” 命令的时候就只是显示:

make clean
make: `clean is up to date.

为什么?我们看一看Makefile的核心规则:

但是现在目录中有名为clean的文件,那目标文件存在,那就取决于依赖,但是在Makefile中clean目标没有依赖,所以没有办法通过判断依赖的的时间去更新clean目标,所以clean目标文件一直都是目录中那么clean文件。所以说,如果目录中有何clean同名文件时就没有办法执行clean操作了。

解决方法就是我们使用伪目标,把这个目标定义为假想目标这样就可以避免出现上面的问题了,例如:

SRC = $(wildcard *.c)
OBJ = $(patsubst %.c, %.o, $(SRC))
 
ALL: hello.out
 
hello.out: $(OBJ)
        gcc -o $@ $<
 
$(OBJ): $(SRC)
        gcc -c -o $@ $<
 
clean:
        -rm -rf $(OBJ) hello.out
 
.PHONY: clean ALL

通常,我们也会把 ALL 也设置为伪目标。 

五、Makefile变量

变量的种类分为:

比如我们编写Makefile文件:

A:=$(C)

B=$(C)

C=123

ALL:
        @echo A=$(A)
        @echo B=$(B)

技术图片

C赋值给A、但是C现在的值为空,B是延时变量,等到用到时才确定,所以执行到C=123才会显示B的值,也就是123.

参考文章

[1] Makefile简单使用实例

[2] Makefile 语法入门

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!