19.华清嵌入式--Makefile
一. make (工程管理器)
1.make概述
1> 自动编译管理器,之前我们想编译一个较大的项目需要手动的执行很多个指令才能生成可执行文件,这么多指令我哪记得住啊,这个时候就出现了Makefile.
2> Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳
自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作
3>Make 只编译改动的代码文件,而不用完全编译。
注意:命令行前面必须是一个”TAB键”,否则编译错误为:*** missing separator. Stop.
扩展:
初次一看Makefile,感觉和我们之前写的脚本没什么区别啊。
个人理解,从功能上
shell脚本时一种编程语言(解释型语言),易于开发,多用于系统维护
makefile 主要是为了简化编译过程。
makefile中能够调用脚本
从本质上来说:
可以认为makefile是shell脚本“派生”出来的。最朴素的makefile可以完全通过gcc等
语句实现,在这种情况下也就是shell脚本了。但是为了方便,makefile引入了大量的语法用来使编译链接变得简单。
2.Makefile 基本结构(理清依赖关系)
生成什么?由谁生成?怎么生成?
例1:
hell.o : hell.c hello.h
gcc -c hello.c -o hello.o
例2:
新建了f1.c f2.c main.c
test:fl.o f2.o main.o
gcc f1.o f2.o main.o -o test
f2.o:f2.c
gcc -c -Wall f2.c -o f2.o
f1.o:f1.c
gcc -c -Wall f1.c -o f1.o
main.o:main.c
gcc -c -Wall main.c -o main.o
clean:
rm *.o test
以依赖为原则,理清文件间的依赖关系。
比如我们想清理一下目标文件直接make clean
但是如果我们在项目中也建立了同名的clean文件,这个时候make clean,就不起作用了,
希望clean目标永远被执行,我们加一个伪目标
.PHONY:clean
3.我们在项目中有很多个文件,一个.c就要写多个重复的命令
这时候用到变量,通过变量来代替一个文本字符串:
1>系列文件的名字
2> 传递给编译器的参数
3> 需要运行的程序
4> 需要查找原码的目录
5> 需要输入信息的目录等
4.变量的定义:
递归展开方式 VAR =var //直接=号
简单方式 VAR:=var
$(VAR)
类似于编程语言中的宏定义
有了变量可以将上边的例子进行一个转换
OBJS=f1.o f2.o
OBJS+=main.o
CFLAGS=-c -Wall
test:$(OBJS)
gcc $(OBJS) -o test
f1.o:f1.c
gcc $(CFLAGS) f1.c -o f1.o
f2.o:$<
gcc $(CFLAGS) f1.c -o [email protected]
5.
为了进一步的简化,还提供了很多自动变量
例:[email protected] 目标文件的完整名称
gcc $(CFLAGS) f1.c -o f1.o //可替代为gcc $(CFLAGS) f1.c -o [email protected]
($* $+ $< $? S^ S%等)
命令格式 |
含义 |
$* |
不包含扩展名的目标文件名称 |
$+ |
所有的依赖文件,以空格分开,并以出现的先后为序,可能包含 重复的依赖文件 |
$< |
第一个依赖文件的名称 |
$? |
所有时间戳比目标文件晚的依赖文件,并以空格分开 |
目标文件的完整名称 |
|
$^ |
所有不重复的依赖文件,以空格分开 |
$% |
如果目标是归档成员,则该变量表示目标的归档成员名称 |
6.
make的使用(自身还有一些选项)
例:
make -C makedemo1/ //执行makedemo1目录下的makefile文件
(-f -i -I -n -p -s -w等)
命令格式 |
含义 |
-C dir |
读入指定目录下的 Makefile |
-f file |
读入当前目录下的 file 文件作为 Makefile |
-i |
忽略所有的命令执行错误 |
-I dir |
指定被包含的 Makefile 所在目录 |
-n |
只打印要执行的命令,但不执行这些命令 |
-p |
显示 make 变量数据库和隐含规则 |
-s |
在执行命令时不显示命令 |
-w |
如果 make 在执行过程中改变目录,则打印当前目录名 |
比如我的依赖文件不在同一级目录,这时候编译是会报错的,此时要加-I命令
gcc -c -Wall -I include f1.c -o f1.o
在有的文件中没有makefile,但是有makefile.debug(当时方便调试修改的)
此时可以使用
make -f makefile.debug //把.debug的文件名当作makefile来使用
工程很大,但是由于makefile某个地方写错,导致编译过程中报错,此时几个小时的编译时间就浪费掉了。
make -i //遇到错误先忽略错误,其他的.o可以不受影响编译出来
7.
makefile 中的隐含规则
1>.
.o的目标的依赖目标会自动推到为.c。
$(cc) -c $(CPPFLAGS) $(CFLAGS)
例:
f2.o:f2.c
gcc -c -Wall f2.c -o f2.o //此句可直接省掉
2>
链接object文件隐藏规则
a.c 自动生成 a.o ,a.o自动生成a
例:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc x.o y.o -o x
可以直接简化为:x:x.o y.o
注:你的执行文件名必须是某一个目标文件的名字,否则隐式规则不成立
有了上面的变量和隐式规则,可简化很多步骤,优化后的命令
CFLAGS=-c -Wall -I include //有部分文件在include目录下
f2:f1.o f2.o main.o
.PHONY:clean
clean:
rm *.o test
8.VPATH用法(虚路径)
大项目中,源文件通常分类存放在不同的目录。make需要寻找文件的依赖关系时,可以在文件前加路径,但最好方法是把路径告诉make,让make自己去找。
如果没有指明变量,make只会从当前目录寻找,加上VPATH后,在当前目录找不到的情况下,到指定的目录中去寻找文件。
VPATH = src:../headers
定义了两个目录,会按照这个顺序进行搜索,目录间用:分隔。
9.Makefile 嵌套
make -n //看make的执行过程
最外层makefile
起到总体控制编译的作用,进入到各层目录,各层目录中又有自己的makefile
export 将当前的变量传递给下层目录makefile来使用