Makefile入门
规则

target ... : prerequisites ...
command

edit : main.o kbd.o command.o display.o
insert.o : search.o files.o utils.o

cc -o main.o kbd.o comand.o display.o
insert.o search.o files.o utils.o

clean :
rm edit main.o kbd.o command.o display,o
insert.o search.o files.o utils.o

工作方式
  • 在目录中中找Makefile或makefile文件
  • 找第一个目标文件,并作为最终目标
  • 如果依赖文件不存在或所依赖的文件比较新,会执行后面所定义的命令
  • 执行终极文件
变量和隐藏规则

objects

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

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

必须以[Tab]键开始

文件名

默认为Makefile,其他文件名如Make.Solars,Make.AIX需要添加-f指定

引用其他Makefile

在Makefile使用include关键字可以把别的Makefile包含进来,被包含的文件会放在当前文件的包含位置
include filename可以是当前操作系统的Shell文件模式(可以包含路径和通配符)在include前面可以
有一些空字符,但是绝不能是[Tab]键开始

规则
  1. 如果make执行时,有"-I"或"--include-dir"参数,那么make就会在这个参数的指定目录下去寻找
  2. 如果目录/include(一般是:/usr/local/bin或/usr/include)存在的法,make也会去寻找
环境变量 MAKEFILES

如果当前环境中定义了环境变量MAKEFILESS,那么make会把这个变量中的值做一个类似于include的动作。
不建议使用这个环境变量,因为一旦这个变量定义,使用make时,所有的Makefile都会受它的影响。

make的工作方式
  1. 读入所有的Makefile
  2. 读入被include的其他Makefie
  3. 初始化文件中的变量
  4. 推导隐晦式规则,并分析所有的规则
  5. 为所有的目标文件创建依赖关系链
  6. 根据依赖关系,决定哪些目标要重新生成。
  7. 执行生成命令
规则通配符

make支持三种通配符:"*","?"和[...],和Unix的B-Shell是相同的

文件搜索

VPATH = src:.../headers
上面的定义是指定两个目录,"src"和".../headers",make会按照这个顺序进行搜索。目录由"冒号"分割(当前目录永远是最高优先搜索的地方)
另一个设置文件搜索路径的方法是使用make的"vpath"关键字和VPATH变量很类似,但是更灵活。

  1. vpath 为符合模式的文件指定搜索目录
  2. vpath 清除符合模式的文件搜索目录
    pattern需要包含"%"字符。"%"的意思是匹配零或若干字符
    例如:"%.h"表示所有以".h"结尾的文件,指定了要搜索的文件集指定了文件集的搜索目录
伪目标

为了避免和文件重名的这种情况,可以使用一个特殊的标记".PHONY"来显示指明一个目标是伪目标

多目标

bigoutput litteoutput: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 ...>::<prereq-pattern ...>

...

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

objects = foo.o bar.o

all : $(objects)

(objects) : %.o : %.c (CC) -c (CFLAGS) < -o $@

在这个例子中,指明了目标从object中获取,"\%.o"表明要所有以"\%.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 %.o,(files))表示调用Makefile的filter函数,过滤"$filter“集中”%.o“的内容

自动生存依赖

大多数C/C++编译器都支持一个"-M"选项,即自动找源文件中包含的头文件,并生存一个依赖关系
cc -M main.c
其输出是:
main.o : main.c main.h

%.d: %.c
@set -e; rm -f @;\ (CC) -M (CPPFLAGS) < > @.$$$$; \ sed 's,\().o[:],\1.0 @:,g' <@.> $@; \ rm -rf $@.