MakeFile详解

最近初学Linux上的动态库和静态库问题,然后不可避免的碰到了makefile文件,看来是时候学一波了

先放一个原作者的连接,感觉写的很好
http://ruanyifeng.com/blog/2015/02/make.html

一、什么是makefile?

之前接触过make命令,但只停留在使用但阶段,就是make ****输完之后,程序就自己编译起来了,对其中的细节一点都不清楚。
首先是make命令,常见的是

make 1.txt

make是制作的意思,这个指令的目的是制造出一个1.txt文件,但是,程序并不知道这个1.txt要如何创建,也不知道这里面有啥。比如1.txt是由2.txt和3.txt连接得到的,那么程序就需要知道这个规则

1.txt: 2.txt 3.txt
	cat 1.txt 2.txt > 3.txt

也就是说,make a.txt 这条命令的背后,实际上分成两步:第一步,确认 2.txt 和 3.txt 必须已经存在,第二步使用 cat 命令 将这个两个文件合并,输出为新文件。
把这些规则写在一起,就形成了makefile文件,Make命令依赖这个文件进行构建。

二、makefile的规则格式

Makefile文件由一系列规则(rules)构成。每条规则的形式如下。

<target> : <prerequisites> 
	[tab]  <commands>

上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。
"目标"是必需的,不可省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。
每条规则就明确两件事:构建目标的前置条件是什么,以及如何构建。下面就详细讲解,每条规则的这三个组成部分。

可能到现在还是有点云里雾里的,我也是,接着往下写

1.目标(target)

一个目标(target)就构成一条规则。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 a.txt 。目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。除了文件名,目标还可以是某个操作的名字,这称为"伪目标"(phony target)。例如:

clean:
	rm *.o

这个clean就是一个伪目标,他声明了某种操作,有点类似于函数,而rm *.o 则是这个函数的实现方式,也就是这个操作的具体内容,他的作用我可以瞎猜一波应该是删除某些文件
makefile文件有了这条规则之后,我们就可以试着使用了,比如这样

make clean

但是假如这时候,当前目录下也有一个clean文件怎么办?程序会不知道要干什么,它觉得这个clean文件已经存在,就不会执行这个makefile指令了。为了避免这个情况,我们可以把clean规则声明为伪目标,这点我觉得又跟虚函数有点像,可以这样声明

.PHONY: clean
clean:
        rm *.o temp

这样声明之后的clean就是一个地地道道的伪目标了。
而很显然,一个makefile文件中会有很多这样的目标(target),我们可以在make后面加上对应的目标来执行它,但是假如不加任何指令,比如这样呢?

make

如果不加任何指令,则默认执行第一个目标(target)

2.前置条件(prerequisites)

前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建。比如这样的规则

result.txt: source.txt
    cp source.txt result.txt

这条规则的作用是复制 source.txt 为 result.txt ,那么按照原文的意思,当source.txt文件不存在,或者说source.txt有更新的时候,这个目标就会重新构建。 但是我试了一下,当前目录如果没有source.txt,那么这个指令也不会执行,可能是我理解错了吧。。。。。
我们需要另一条规则来创建这个sources.txt文件,实测这样可以运行

 source.txt:
 	echo "this is the source" > source.txt
3.命令(commands)

命令(commands)表示如何更新目标文件,由一行或多行的Shell命令组成。它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件。
每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。像这样

.RECIPEPREFIX = >
all:
> echo Hello, world

上面代码用.RECIPEPREFIX指定,大于号(>)替代tab键。所以,每一行命令的起首变成了大于号,而不是tab键。

需要注意的是,每行命令在一个单独的shell中执行。这些Shell之间没有继承关系。

var-lost:
    export foo=bar
    echo "foo=[$$foo]"

上面代码执行后,取不到foo的值。因为两行命令在两个不同的进程执行。一个解决办法是将两行命令写在一行,中间用分号分隔。

var-kept:
    export foo=bar; echo "foo=[$$foo]"

另一个解决办法是在换行符前加反斜杠转义。

var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"

最后一个方法是加上.ONESHELL:命令。

.ONESHELL:
var-kept:
    export foo=bar; 
    echo "foo=[$$foo]"

三、makefile的语法

1.注释

井号(#)在Makefile中表示注释。

#这是注释
result.txt: source.txt
    #这是注释
    cp source.txt result.txt # 这也是注释
2.回声

正常情况下,make会打印每条命令,然后再执行,这就叫做回声(echoing)。

test:
    # 这是测试

执行上面的规则,会得到下面的结果。

$ make test
# 这是测试

在命令的前面加上@,就可以关闭回声。

test:
    @# 这是测试

现在再执行make test,就不会有任何输出。
由于在构建过程中,需要了解当前在执行哪条命令,所以通常只在注释和纯显示的echo命令前面加上@。

3.通配符

通配符用来指定一组符合条件的文件名。Makefile 的通配符与 Bash 一致,主要有星号(*)、问号(?)和 […] 。比如, *.o 表示所有后缀名为o的文件。

clean:
        rm -f *.o
4.模式匹配

Make命令允许对文件名,进行类似正则运算的匹配,主要用到的匹配符是%。比如,假定当前目录下有 f1.c 和 f2.c 两个源码文件,需要将它们编译为对应的对象文件。

%.o: %.c

等同于下面的写法。

f1.o: f1.c
f2.o: f2.c

使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。

未完。。。今天累了先休息

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值