以前在windows上学习单片机、ARM的时候都是用IDE去管理编译代码,很多时候都不知道各个程序之间是怎么编译成可执行文件的,只要点下鼠标就可以了。虽然自己也有学习linux以及uboot 但都是看看改改程序。对于makefile认识也是单文件小工程的。认为makefile就是个编译工具,没必要深究。随着阅读的代码量的增多,发现,对于理解一些源码框架比如u-boot、inux 、andriod,要是看不懂makefile理解起来比较困难。而且在嵌入式系统开发中,考虑功能的模块化和可移植性,makefile是一个绕不过的东西。最近一次工作经历深深地刺激了我。是这样,我之前已经完整编译了整个工程,后面修改了某个配置文件,执行make 总是提示那个配置的东西不存在。即使make clean后再make还是会报一堆不知名的错误,我意识到makefile某些编译项用的是未改前的配置,现在有冲突了,当然会报错,这个系统是我们公司开发的有十几万个文件,每次编译都要二十多分钟,我当天一直查这个问题到11:00,伤心地回了家。第二天我默默地从服务器上重新下载新的code,直接修改配置文件,直接make正如我所料一次性编译通过。
果然是该死的makefile第一次编译ok,修改配置文件,第二次编写就把代码编坏了。这种情况我相信很多搞程序的都遇到过,其实在此前就发现makefile不怎么完美,我经常添加模块还要去修改多个makefile才能使得添加的模块编译进去。跟进的项目终于接近尾声,决心好好研究下。
makefile 其实也是编程语言,他只是编译工具语言,也有语法,个人觉得我们实际应用中掌握常用的语法就好了下面是我总结的常用的Makefile语法。
一、Makefile 中的赋值方法
= 递归赋值 可以向后引用变量
:= 简单扩展 只能引用前面的变量
?= 如果没有赋值 则赋值一次
+= 在原来的基础上添加赋值变量
一个例子说明
x = before
y = $(x)
x = later
xx = before
yy := $(xx)
xx = later
xxx = before
xxx ?= later
yyy ?= before
yyy = later
x += last
all :
@echo "x=" $(x)
@echo "y=" $(y)
@echo "xx=" $(xx)
@echo "yy=" $(yy)
@echo "xxx=" $(xxx)
@echo "yyy=" $(yyy)
输出是
x= later last
y= later last
xx=later
yy=before
xxx=before
yyy=later
二、Makefile 自动变量
$@ 目标
$< 所以的依赖文件
$^ 第一个依赖文件
test.o : test1.c test2.c
@echo $@
@echo $<
@echo $^
结果为
test.o
test1.c test2.c
test1.c
三、Makefile中的常用函数
1、文本替换 函数 $(subst ma, wo ,hello world!!)
将hello world!! 中间的wo 替换成ma
结果为 hello marld!!
2、格式替换函数 $(patsubst %.c ,%.o , test.c test1.c test2.c)
将.c 的格式替换成.o
结果为 test.o test1.o test2.o
3、去掉空格函数 $(strip a b c)
结果 a b c
4、字符串查找函数
$(findstring a,a b c d)
在字符串a b c d 中查找 a ,找到就返回查到的值 ,否则为 " "
上面结果为 a
5、格式匹配过滤函数 $(filter %.c %.s , mod1.c mod2.o mod3.s mod4.h)
查找格式是%.c 和 %.s 的文件
结果为 mod1.c mod2.s
6、格式不匹配函数 $(filter-out %.c %.s, mod1.c mod2.o mod3.s mod4.h)
它的和filter相反
结果为 mod2.o mod4.h
7、$(sort hello world branck)
按字母排列
结果为 branck hello world
8 、抽取文件目录函数$( dir source/hello.c inc/hello.h mksh)
结果: source/ inc/ ./
9、抽取文件名函数 $(nodir source/hello.c inc/hello.h mksh)
结果: hello.c hello.h mksh
10、提取文件名后缀函数 $(suffix source/hello.c inc/hello.h mksh)
结果: .c .h
11、去除后缀名函数 $(basename sourc/hello.c inc/hello.h mksh)
结果: source/hello inc/hello mksh
12、添加后缀名函数 $(addsuffix .c ,hello fun)
结果: hello.c fun.c
13、添加前缀函数 $(addprefix source/ , mod1.c mod2.c mod3.c)
结果: source/mod1.c source/mod2.c source/mod3.c
14、格式匹配函数 $(wildcard source/*.c)
查找source 目录下所有.c 文件
15、格式匹配用法
SRCS = mod1.c mod2.c mod3.c
$(SRCS : %.c = %.o)
结果为mod1.o mod2.o mod3.o
16、目录循环搜索
dirs := dir1 dir2 dir3 dir4
files := $( foreach dir ,$(dirs) ,$(wildcard $(dir)/*)
查找 目录 dir1 dir2 dir3 dir4 目录下所有的文件。
17、在Makefile 中执行shell 脚本的方法
$(shell command)
SRCS := $(shell ls *.c)
则srcs 中所有的c程序。
四、Makefile 中的编译基础知识
1、编译时 指定头文件路径 用 -I
2、编译时 指定库路径用 -L 指定函数库名 用 -l (小写L )
3、在Makefile 指定宏定义 配置到程序中 -D
五、条件判断语句
1、ifdef/ifndf (param)
endif
# param 是否定义
2、ifeq/ifneq (a,b)
endif
# a和b是否相等
我想Makefile 的基础知识掌握这些就ok了,关键是应用