makefile 格式:
target(目标) ... : prerequisites (依赖)...
command
target 这一个或多个的目标文件依赖于prerequisites 中的文件,其生成规则定义在 command 中
prerequisites 中如果有一个以上的文件比 target 文件要新的话,command 所定义的命令就会被执行。这就是 Makefile 的规则。
Makefile:
edit : main.o kbd.o command.o display.o
cc -o edit main.o kbd.o command.o display.o
通过make edit 运行 cc -o edit main.o kbd.o command.o display.o
main.o(上面edit的依赖) : 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
如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者 target 不存在的话,那么,make 就会执行后续定义的命令
clean :
rm edit main.o kbd.o command.o display.o
clean 不是一个文件,它只不过是一个动作名字, 只会通过make clean执行
makefile 中使用变量
变量objects:
objects = main.o kbd.o command.o display.o
上面的makefile替换为:
edit : $(objects)
cc -o edit $(objects)
make 自动推导
GNU 的 make 很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令
上面makefile:
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
再次替换为:
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
main.o不需要添加main.c。编译器会自动找到main.c去和main.o配对
.PHONY : clean
clean :
rm edit $(objects)
“.PHONY”表示,clean 是个伪目标文件。
clean文件不要放在开头(开头为默认执行的目标)不成文的规矩是——“clean 从来都是放在文件的最后
同时,可以将相同的.h进行分类,使得makefile更加简单
$(objects) : defs.h (是指objects中所以目标都添加了defs.h文件)
kbd.o command.o files.o : command.h (kbd.o command.o files.o中包含command.h文件)
display.o insert.o search.o files.o : buffer.h
Makefile 的文件名
默认的情况下,make 命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件
可以使用别的文件名来书写 Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等
如果要指定特定的 Makefile,可以使用 make 的“-f”和“--file”,如:
make -f Make.Linux 或 make --file Make.AIX。
引用其它的 Makefile
在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来
include <filename>
filename 可以是当前操作系统 Shell 的文件模式
举个例子,你有这样几个 Makefile:a.mk、b.mk、c.mk,还有一个文件叫 foo.make,以及一个变量$(bar),其包含了 e.mk 和 f.mk
include foo.make *.mk $(bar) / include foo.make a.mk b.mk c.mk e.mk f.mk
编译器如何找到include中的makefile?
1. make 执行时,有“-I”或“--include-dir”参数
2.路径 /usr/local/bin 或/usr/include
如果你想让 make 不理那些无法读取的文件,而继续执行,你可以在 include 前加一个减号“-”。
-include <filename> :无论 include 过程中出现什么错误,都不要报错继续执行
书写规则
规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
targets : prerequisites
([TAP])command
targets : prerequisites ; command (分号隔开)
使用通配符
make 支持三个通配符:“*”,“?”和“[...]”
要让通配符在变量中展开,也就是让 objects 的值是所有[.o]的文件名的集合
objects := $(wildcard *.o)
文件搜寻
1.Makefile 文件中的特殊变量“VPATH”:
如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。
如果定义了这个变量,那么,make 就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers (不同目录由“冒号”分隔:src目录与../headers目录)
2.关键字 vpath
使用方法: pattern:文件名 directories:目录地址
1、vpath <pattern> <directories>
为符合模式<pattern>的文件指定搜索目录<directories>。
2、vpath <pattern>
清除符合模式<pattern>的文件的搜索目录。
3、vpath
清除所有已被设置好了的文件搜索目录。
vapth 使用方法中的<pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符:如,“%.h”表示所有以“.h”结尾的文件
vpath %.h ../headers (添加/headers目录下的所有.h文件)
伪目标
.PHONY : 伪目标
“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以 make 无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。
.PHONY : all clean
all : edit (通过make all 制定去执行edit,其他目标执行的标准为:后面的依赖比目标新)
clean:
....
多目标
多个目标同时依赖于一个文件
使用一个自动化变量“$@”:这个变量表示着目前规则中所有的目标的集合
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,这个函数是截取字符串的意思,后面的为参数
“$@”表示目标的集合,“$@”依次取出目标,并执于命令。
静态模式
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(objects): %.o -- 表示在objects获取所有以.o为结尾的参数 (目标)
依赖目标就是“foo.c bar.c”
$(CFLAGS)是一个变量
命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o bar.o”)。
自动生成依赖性
大多数的 C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。省去我们自己添加源文件的头文件依赖。
例如,如果我们执行下面的命令:
cc -M main.c
其输出是:
main.o : main.c defs.h
如果你使用 GNU 的 C/C++编译器,你得用“-MM”参数,“-M”参数会把一些标准库的头文件也包含进来。
GNU 组织建议把编译器为每一个源文件的自动生成的依赖关系放到一个文件中,为每一个“name.c”的文件都生成一个“name.d”的 Makefile 文件,[.d]文件中就存放对应[.c]文件的依赖关系。
显示命令
make 会把其要执行的命令行在命令执行前输出到屏幕上。当我们用“@”字符在命令行前,那么,这个命令将不被 make 显示出来
make 参数“-n”或“--just-print”,那么其只是显示命令,但不会执行命令
而 make 参数“-s”或“--slient”则是全面禁止命令的显示。
命令执行
第一条命令是 cd 命令,你希望第二条命令得在 cd 之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号;分隔
exit:
cd /home/user ; pwd
给 make 加上“-i”或是“--ignore-errors”参数,那么,Makefile 中所有命令都会忽略错误
嵌套执行 make
subsystem:
cd subdir && $(MAKE) (进入subdir 目录 执行make)
等价于:
subsystem:
$(MAKE) -C subdir
如果你要传递变量到下级 Makefile 中,那么你可以使用这样的声明:
export <variable ...>
export variable = value(将variable 参数传到下级makefile)
变量
用 make 中的另一种用变量来定义变量的方法。这种方法使用的是“:=”操作符
变量赋值:
1. a = b
这种方式b可以在a后面定义
2. a := b
这种方式b不能在a后面定义
注意:
dir := /foo/bar # directory to put the frobs in
dir 这个变量的值是“/foo/bar”,后面还跟了 4 个空格
操作符“?=”
FOO ?= bar
含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做
(自动变量: $@当前目标 $^当前目标的所有依赖 $<当前目标的第一个依赖)
(通配符“%”“*”如%.c 所有.c 文件, *.o,所有.o 文件)
define 关键字
-用于在 makefile 中定义多行变量
-多行变量的定义从变量名开始到 endef 结束
常用形式
ifxxx (arg1,arg2)
makefile 中函数的概念
-make 解释器提供了一系列的函数供 makefile 调用
-在 makefile 中支持自定义函数实现,并调用执行
-通过 define 关键字实现自定
define func1
@echo “My name is $(0)”
endef
函数调用:
Test :
$(call func1)
自定义函数是一个多行变量,无法直接调用
Makefile 常用系统函数