首页 > 代码库 > 粗浅谈论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