makefile

Makefile 介绍

Makefile 文件,告诉make命令需要怎么样的去编译和链接程序

一、Makefile的规则

target ... : prerequisites ...
command
...
...
  • target也就是一个目标文件,
  • 生成那个target所需要的文件
  • command也就是make需要执行的命令

二、一个示例

edit : main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o
	cc -o edit main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o
main.o : main.c defs.h
	cc -c main.c
kbd.o : kbd.c defs.h command.h
	cc -c kbd.c
command.o : command.c defs.h command.h
	cc -c command.c
display.o : display.c defs.h buffer.h
	cc -c display.c
insert.o : insert.c defs.h buffer.h
	cc -c insert.c
search.o : search.c defs.h buffer.h
	cc -c search.c
files.o : files.c defs.h buffer.h command.h
	cc -c files.c
utils.o : utils.c defs.h
	cc -c utils.c
clean :
	rm edit main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o

make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,make就会执行后续定义的命令
clean不是一个文件,要执行其后的命令,就要在make命令后明显得指出这个lable的名字

三、make是如何工作的

make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件
对于所定义的命令的错误,或是编译不成功,make根本不理

四、makefile中使用变量

makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好

objects = main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o

我们就可以很方便地在我们的makefile中以$(objects)的方式来使用

五、让make自动推导

make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中 [推导相同文件名的依赖]

objects = main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o
edit : $(objects)
	cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
	rm edit $(objects)

.PHONY表示,clean是个伪目标文件------>记住这个名词,后续介绍

六、清空目标文件的规则

一般的风格都是:

clean:
	rm edit $(objects)

稳健做法:

.PHONY : clean
clean :
	-rm edit $(objects)

.PHONY意思表示clean是一个“伪目标”
在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事.
clean从来都是放在文件的最后

Makefile 总述

一、Makefile里有什么?

  1. 显示规则: 如何生成一个或多的的目标文件;书写者明显指出,要生成的文件,文件的依赖文件生成的命令
  2. 隐晦规则: 自动推导的功能导致写的语义更简略,但是你是知道的
  3. 变量的定义: 定义一系列的变量,变量一般都是字符串
  4. 文件指示: 1. 在一个Makefile中引用另一个Makefile(c include ) 2. 根据某些情况指定Makefile中的有效部分(c #if) 3. 定义一个多行的命令
  5. 注释: #

二、Makefile的文件名

Makefile

三、引用其它的Makefile

include foo.make *.mk $(bar)
include foo.make a.mk b.mk c.mk e.mk f.mk

  1. 如果make执行时,有“-I”或“–include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
  2. 如果目录/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找

四、环境变量 MAKEFILES

定义了环境变量MAKEFILES,,make会把这个变量中的值做一个类似于include的动作
这个变量中的值是其它的Makefile,用空格分隔
建议不要使用这个环境变量

五、make的工作方式

  • 阶段一
    1、读入所有的Makefile。
    2、读入被include的其它Makefile。
    3、初始化文件中的变量。
    4、推导隐晦规则,并分析所有规则。
    5、为所有的目标文件创建依赖关系链。
  • 阶段二
    6、根据依赖关系,决定哪些目标要重新生成。
    7、执行生成命令

第五章 书写规则

规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么
第一条规则中的目标将被确立为最终的目标

一、规则举例

foo.o : foo.c defs.h # foo模块
	cc -c -g foo.c

文件的依赖关系,foo.o依赖于foo.c和defs.h的文件
目标:生成foo.o这个文件

二、规则的语法

targets : prerequisites
	command
...
或是这样:
targets : prerequisites ; command
	command
...

targets是文件名,以空格分开,可以使用通配符
command是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔
prerequisites也就是目标所依赖的文件
make会以UNIX的标准Shell,也就是/bin/sh来执行命令。

三、在规则中使用通配符

make支持三各通配符:*?[...]。这是和Unix的B-Shell是相同的
波浪号(“~”)字符在文件名中也有比较特殊的用途

如果是“~/test”,这就表示当前用户的$HOME目录下的test目录
“~hchen/test”则表示用户hchen的宿主目录下的test目录。(这些都是Unix下的小知识了,make也支持)

eg:
目标print依赖于所有的[.c]文件

print: *.c
lpr -p $?
touch print

如果你要让通配符在变量中展开,也就是让objects的值是所有[.o]的文件名的集合

objects := $(wildcard *.o)

这种用法由关键字“wildcard”指出,关于Makefile的关键字,我们将在后面讨论。

四、文件搜寻

当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找

  1. Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件.
    如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
    VPATH = src:../headers
    上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索,使用:分隔目录
  2. 使用make的“vpath”关键字(注意,它是全小写的)
    这不是变量,这是一个make的关键字,这和上面提到的那个VPATH变量很类似,但是它更为灵活
    三种使用方法:
1、vpath <pattern> <directories>
为符合模式<pattern>的文件指定搜索目录<directories>。
2、vpath <pattern>
清除符合模式<pattern>的文件的搜索目录。
3、vpath
清除所有已被设置好了的文件搜索目录。

vpath使用方法中的需要包含“%”字符,
“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件
指定了要搜索的文件集,而则指定了的文件集的搜索的目录

vpath %.h ../headers

该语句表示,要求make在“…/headers”目录下搜索所有以“.h”结尾的文件(在当前目录没找到的情况下)
如果连续的vpath语句中出现了相同的,或是被重复了的,那么,make会按照vpath语句的先后顺序来执行搜索

vpath %.c foo
vpath % blish
vpath %.c bar

其表示“.c”结尾的文件,先在“foo”目录,然后是“blish”,最后是“bar”目录。

五、伪目标

“伪目标”并不是一个文件,只是一个标签
为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。

.PHONY : clean

可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性

all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
	cc -o prog1 prog1.o utils.o
prog2 : prog2.o
	cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
	cc -o prog3 prog3.o sort.o utils.o

我们声明了一个“all”的伪目标,其依赖于其它三个目标。由于伪目标的特性是,总是被执行的,所以其依赖的那三个目标就总是不如“all”这个目标新。所以,其它三个目标的规则总是会被决议。也就达到了我们一口气生成多个目标的目的。“.PHONY : all”声明了“all”这个目标为“伪目标”。

六、多目标

多个目标的生成规则的执行命令是同一个,这可能会可我们带来麻烦,不过好在我们的可以使用一个自动化变量$@(关于自动化变量,将在后面讲述),这个变量表示着目前规则中所有的目标的集合

bigoutput littleoutput : text.g
	generate text.g -$(subst output,,$@) > $@
bigoutput : text.g
	generate text.g -big > bigoutput
littleoutput : text.g
	generate text.g -little > littleoutput

-$(subst output,,$@)中的“$”表示执行一个Makefile的函数,函数名为subst,后面的为参数。

$@表示目标的集合,就像一个数组,$@依次取出目标,并执于命令。

七、静态模式

静态模式可以更加容易地定义多目标的规则

<targets ...>: <target-pattern>: <prereq-patterns ...>
	<commands>
...

targets定义了一系列的目标文件,可以有通配符。是目标的一个集合
target-parrtern是指明了targets的模式,也就是的目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义
eg:

objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

我们的目标从 o b j e c t 中获取,“ object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量 object中获取,object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。
命令中的“ < ”和“ <”和“ <@”则是自动化变量,“ < ”表示所有的依赖目标集(也就是“ f o o . c b a r . c ”),“ <”表示所有的依赖目标集(也就是“foo.c bar.c”),“ <表示所有的依赖目标集(也就是foo.cbar.c),@”表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:

foo.o : foo.c
	$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
	$(CC) -c $(CFLAGS) bar.c -o bar.o
files = foo.elc bar.o lose.o
$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<

$(filter %.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。其的它内容,我就不用多说了吧。这个例字展示了Makefile中更大的弹性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值