c语言笔记 -- Makefile

##1、Makefile介绍

把Makefile 文件和源代码放在同一个目录。make 命令会自动读取当前目录下的 Makefile 文件。

Makefile 由一组规则(Rule)组成,第一条规则的目标称为缺省目标,只要缺省目标更新了就算完成任务了,其它工作都是为这个目的而做的。如果在 make 的命令行中指定一个目标(例如 clean),则更新这个目标,如果不指定目标则更新 Makefile 中第一条规则的目标(缺省目标)。
每条规则的格式是:

target ... : prerequisites ...
    command1
    command2
    ...

例如:

main: main.o stack.o maze.o
    gcc main.o stack.o maze.o -o main

main 是这条规则的目标(Target), main.o、 stack.o 和 maze.o 是这条规则的条件(Prerequisite)。目标和条件之间的关系是: 欲更新目标,必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个 Tab 开头,注意不能是空格, Makefile 的格式不像 C 语言的缩进那么随意,对于 Makefile 中的每个以 Tab 开头的命令, make 会创建一个 Shell 进程去执行它。

如果修改了某个源文件,make 会自动选择那些受影响的源文件重新编译,不受影响的源文件则不重新编译。

2、执行一条规则 A 的步骤如下:
1)检查它的每个条件 P

  • 如果 P 需要更新,就执行以 P 为目标的规则 B。之后,无论是否生成文件 P,都认为 P 已被更新。
  • 如果找不到规则 B,并且文件 P 已存在,表示 P 不需要更新。
  • 如果找不到规则 B,并且文件 P 不存在,则报错退出。

2) 在检查完规则 A 的所有条件后,检查它的目标 T,如果属于以下情况之一,
就执行它的命令列表:

  •  文件 T 不存在。
  •  文件 T 存在,但是某个条件的修改时间比它晚。
  •  某个条件 P 已被更新(并不一定生成文件 P)

3、clean规则

clean规则如下所示:

clean:
    @echo "cleanning project"
    -rm main *.o
    @echo "clean completed"

执行这条规则,结果如下图所示

$ make clean
cleanning project
rm main *.o
clean completed

 clean 目标不依赖于任何条件,并且执行它的命令列表不会生成 clean 这个文件。只要执行了命令列表就算更新了目标,即使目标并没有生成也算。在这个例子还演示了命令前面加@和-字符的效果:如果make 执行的命令前面加了@字符,则不显示命令本身而只显示它的结果;通常make 执行的命令如果出错(该命令的退出状态非 0)就立刻终止,不再执行后续命令,但如果命令前面加了-号,即使这条命令出错, make 也会继续执行后续命令。通常 rm 命令和 mkdir 命令前面要加-号,因为 rm 要删除的文件可能不存在,mkdir 要创建的目录可能已存在,这两个命令都有可能出错,但这种错误是应该忽略的。

如果当前目录下存在 clean 这个文件, clean 目标又不依赖于任何条件, make 就认为它不需要更新了。而我们希望把 clean 当作一个特殊的名字使用,不管它存在不存在都要更新,可以添一条特殊规则,把 clean 声明为一个伪目标

.PHONY: clean

这条规则写在 clean:规则的后面也行,也能起到声明 clean是伪目标的作用。

4、Makefile的处理过程

Makefile的处理过程分为两个阶段。

1)首先从前到后读取所有规则,建立起一个完整的依赖关系图,例如:

2)从缺省目标或者命令行指定的目标开始,根据依赖关系图选择适当的规则执行,执行 Makefile 中的规则和并不是从前到后按顺序执行,也不是所有规则都要执行一遍,例如 make 缺省目标时不会更新 clean 目标,因为从上图可以看出,它跟缺省目标没有任何依赖关系。

5、隐含规则和模式规则

一个目标在 Makefile 中的所有规则都没有命令列表, make 会尝试在内建的隐含规则(Implicit Rule)数据库中查找适用的规则。有可能触发%.o: %.c规则来编译得到目标文件。 make 的隐含规则数据库可以用 make -p 命令打印。

# default
OUTPUT_OPTION = -o $@
# default
CC = cc
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
%.o: %.c
# commands to execute (built-in):
    $(COMPILE.c) $(OUTPUT_OPTION) $<

#号在 Makefile 中表示单行注释。 CC 是一个 Makefile变量,用 CC = cc 定义和赋值,用$(CC)取它的值,其值应该是 cc。 Makefile 变量像 C 的宏定义一样,代表一个字符串,在取值的地方展开。 cc 是一个符号链接,通常指向 gcc。

CFLAGS 、CPPFLAGS 、TARGET_ARCH 这些变量没有定义, 所以$(CFLAGS)、$(CPPFLAGS )、$(TARGET_ARCH )展开是空。这样$(COMPILE.c)展开应该是 cc␣ 空␣ 空␣ 空␣ -c,去掉所有的“空”
得到 cc␣ ␣ ␣ ␣ -c,注意中间留下 4 个空格,所以%.o: %.c 规则的命令$(COMPILE.c)␣ $(OUTPUT_OPTION)␣ $<展开之后是 cc␣ ␣ ␣ ␣ -c␣ -o␣ $@␣$<

$@和$<是两个特殊的变量, $@的取值为规则中的目标, $<的取值为规则中的第一个条件。 %.o: %.c 是一种特殊的规则,称为模式规则(Pattern Rule)。假设在 Makefile 中以 main.o 为目标的规则都没有命令列表,所以 make 会查找隐含规则,发现隐含规则中有这样一条模式规则适用, main.o符合%.o 的模式,现在%就代表 main(称为 main.o 这个名字的 Stem),再替换到%.c 中就是 main.c。所以这条模式规则相当于:

main.o: main.c
    cc    -c -o main.o main.c

6、多目标规则

多目标的规则, make 会拆成几条单目标的规则来处理,例如

target1 target2: prerequisite1 prerequisite2
    command $< -o $@

这样一条规则相当于:

target1: prerequisite1 prerequisite2
    command prerequisite1 -o target1
target2: prerequisite1 prerequisite2
    command prerequisite1 -o target2

注意两条规则的命令列表是一样的,但$@的取值不同。

7、变量

1)运算符

=运算符 定义变量 会把变量的值推迟到后面定义

:=运算符 定义变量 会立即展开

?=运算符,例如 foo ?= $(bar)的意思是:如果 foo没有定义过,那么?=相当于=,定义 foo 的值是$(bar),但不立即展开;如果先前已经定义了 foo,则什么也不做,不会给 foo 重新赋值。

+=运算符可以给变量追加值,例如

objects = main.o
objects += $(foo)
foo = foo.o bar.o

object 是用=定义的, +=仍然保持=的特性, objects 的值是 main.o $(foo)(注意$(foo)前面自动添一个空格),但不立即展开,等到后面需要展开$(objects)时会展开成 main.o foo.o bar.o。

再如:

objects := main.o
objects += $(foo)
foo = foo.o bar.o

object 是用:=定义的, +=保持:=的特性,objects 的值是 main.o $(foo),立即展开得到 main.o (这时 foo 还没定义),注意 main.o 后面的空格仍保留。

如果变量还没有定义过就直接用+=赋值,那么+=相当于=。

2)常用的特殊变量有:

  • $@,表示规则中的目标。
  • $<,表示规则中的第一个条件。
  • $?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
  • $^,表示规则中的所有条件,组成一个列表,以空格分隔

3)定义一个变量的值是一个空格

可以这样:

nullstring :=
space := $(nullstring) # end of the line

nullstring 的值为空, space 的值是一个空格,后面写个注释是为了增加可读性,如果不写注释就换行,则很难看出$(nullstring)后面有个空格。
 




 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值