首页 > 代码库 > 粗浅谈论makefile
粗浅谈论makefile
主要参考:跟我一起写makefile 点击打开链接
Makefile简介:
简单的说,一个大的工程中的源文件不计其数,其按照不同的类型,功能,模块放在了不同的目录之中,makefile则是定义了一些规则来指定,哪些文件需要先编译,哪些需要后编译,哪些需要重新编译,而makefile带来的好处就是,一旦写好,之后一个make命令 就可以搞定,极大的提高了软件的开发。
简述编译链接:
无论选择什么语言c,c++都需要将源文件编译成为中间代码文件,在windows下面是.obj文件,而unix则是.o文件,这就是编译(compile),然后将.o文件链接(link操作)形成可执行文件。但由于源文件太多,编译生成的中间文件太多,不太方便,此时需要给中间目标文件打包,在windows下成为库文件.lib(library file),而在unix称为.a(archivefile)文件。
一个简单的makefile样例:
Edit(最终目标可执行文件):main.otest.o start.o xd.o(依赖文件)
Cc –o edit main.o test.o start.o xd.o
Main.o: main.c defs.h
Cc –c main.c
Test.o : test.c defs.h
Cc –c test.c
Start.o: start.c defs.h
Cc –c start.c
Xd.o: xd.c defs.h
Cc –c xd.c
Clean:(伪目标) 依赖文件不执行,退出时可以显示执行 make clean
Rm –r edit main.o test.o xd.o start.o
Gund make很强大,有自动推导的功能,一个.o文件 会自动推导.c文件,于此同时还可以使用变量 来代替目标文件(过多很复杂),新的makefile:
Objects = main.o test.o start.o xd.o
Cc –c edit $(objects)
Main.o:defs.h
Start.o:defs.h
Xd.o:defs.h
Test.o:defs.h
所有.c文件可以自动推导。
下面是一个makefile的小知识点:
Tips:
Makefile:
1) 如果make执行,遇到-I或者是includedir的时候,操作按照参数指定的路径去寻找
2) 如果/usr/local/bin 或者是/usr/include存在是话 make也会去寻找,到最后如果还是找不到的话,make会报告一个致命的信息,如果想让make忽略这些信息的话,寻找在include的前面加上一个-号: -include <filename>或者使用sinclude命令和-的作用是一致的。
3) 不建议使用环境变量:MAKEFILES(主要就是包含其他的makeifile文件)
Make的工作方式:
1)读入所有的makefiles
2)读入include的其他makefiles
3)初始化文件中的变量
4)推到隐晦规则,分析规则
5)创建依赖关系
6)根据依赖关系,决定哪些目标文见需要重新生成。
7)执行命令
在初始化变量的时候,只有在生成目标文件的时候,变量才会被展开使用,否则并不会立即进行展开。
第一条规则中第一个目标将会是最终的目标。
Make的命令需要以Tab开始
通配符的使用:
但是 当objects = *.o时 并不是代表着所有的.o文件,而是真正是*.o,要是需要所有的.o文件,可以使用 object := $(wildcard *.o)关键字wildcard(自动全部扩展开)
$?:自动化变量(上一次程序的退出码)
VPATH这个特殊的变量是指明了需找的路径,是在make在当前目录找不到的情况下会按照指定的目录去寻找文件
:VPATH= src:../headers(:是分隔)
与此同时还有一个vpath 关键字,不是一个变量是一个make关键字。
vpath %.h ../headers 表示在../headers目录下搜索以.h结尾是文件
伪目标不是一个文件,只是一个标签:(一般放在命令的最后,并且需要显示的调用 make clean)
.PHONY: clean
clean:
-rm *.o temp
静态模式:
Objects = foo.obar.o
all:$(objects)
$(objects):%.o:%.c
$(cc) –c $(CFLAGS)$< -o $@ /*$<:所有依赖目标集 $@:目标集*/
自动寻找头文件和源文件:main.o: main.c defs.h
但是由于头文件过多的原因,需要自动寻找源文件和头文件,使用cc –M main.c
但是如果使用的是gnu的编译器,需要的是gcc –MM main.c 否则会将标准库的头文件一起包含进来。
Makefile的显示命令:
@echo xxxx 当make时会输出 echo xxxx 并不会执行命令
Make –n 或—just-print 只是显示命令 并不会执行
Make –s 或者是–slient 全面禁止命令的显示
嵌套执行make
在一些比较大的工程之中,我们会把不同模块或是不同功能的源文件放在不同的目录里面,可以在每个目录下面都写一个makefile文件,这样还会很简洁,但是也存在着缺陷,就是难以维护,嵌套执行make语句就体现出了很强大的好处。例如:
subsystem:
cd subdir&& $(make) – 意思是先进入subdir文件,之后执行make命令,这个是总控的makefile文件,总控文件里面的变量可以传递到下一级的makefile文件中,但是不会覆盖下一级makefile的变量,除非使用指定参数-e
传递变量:export variable = value
如果要是想传入所有的变量。只使用一个export即可。例外shell ,makeflags 变量都是需要传入下一级的变量。
变量的使用,使用$来表示变量,但是要想使用单独的$时候,需要使用$$来表示。
变量的使用,可以使用变量的变量,变量的值可以是后续变量的值:foo = $(bar)
bar = xd;
但是这样同时也会存在着弊端,就是递归定义,形成类似于死循环的样式。
解决:
使用:= 来限制,是前面的变量不可以使用后面的变量的值,只可以使用前面已经定义好的变量的值
y := $(x) bar
x := foo
其中y的值就是 bar ,而不是 foo bar
空格的定义:(先定义一个空的变量,在将这个空的变量在等号的右边使用)
nullstring :=
space :=$(nullstring)
?= 是否存在的意思
替换:
Foo := a.o b.o
Bar := $(foo: .o =.c)
Bar = a.c b.c
追加变量值 使用 += (好比java的那个字符串的拼接)
Makefile的函数使用:
subst替换函数
$(subst ee,EE,geet ont the feet)
patsubst:模式字符串替换函数
$(patsubst %.c,%.o,x.c.c bar.c)=>x.c.obar.o
strip: 去空格函数(去掉开头和结尾的空格)
findstring:$(findstring <find> ,<in>)在<in>查找<find>
$(findstring a, a b c)=>a
$(findstring a, b c)=>“”
filter: 按照条件过滤(过滤掉不符合条件的)
filter-out :反过滤函数
sort:给单词排序(升序)并且去掉相同的单词
word:取出单词
$(word <n> ,<text>)取出text中的第n个单词
wordlist:取单词串的函数
$(wordlist 2,3,<text>)取出text中的第2-3个单词
words:统计单词个数
firstword:取首个单词
文件名的操作函数:
dir:取目录函数 目录部分是/之前的 没有/ 返回“./”
$(dir src/foo.c hacks)=>src/./
notdir:取文件函数
$(notdir src/foo.c hacks)=>foo.c hacks
suffix:取后缀函数
basename:取前缀函数
addsuffix:添加后缀函数
addprefix:添加前缀函数
join:连接函数(对应链接)
$(join aaa bbb, 111 222 333)=>aaa111bbb222 333
foreach:用于循环的使用
$(foreach<var>,<list>,<text>)
name:= a b c d
files:= $(foreachn,$(name),$(n).o)就是将临时局部变量每次赋予一个值,之后转化为.o文件 临时变量出了函数 将会无效,类似于c++for函数中的i。
if函数:
$(if<condition>,<then-part>,<else-part>)
call:创建一个新参数化的函数
origin:主要是返回这个变量是从什么地方来的
$(origin <variable>) 返回值:
undefined:
default:
file
command line
override
automatic
控制make的函数:
Error:
$(error <text>) text是出错信息
Warning
$(warning <text>) text是警告信息
Make的退出码:
0---表示成功执行
1---出现任何错误,返回1
2--- 一些目标不需要更新
Makefile伪目标:
all:
所有的目标
clean:
删除所被make创建的文件
install:
安装已经编译好的程序,就是将目标执行文件拷贝到制定的目标中去
print:
列出改变过的源文件
tar:
将源文件打包备份
dist:
创建一个压缩文件
TAGS:
更新所有目标
check和test:
测试makefile的流程
粗浅谈论makefile