前言
规则主要是分为三种:模式规则 隐含规则 静态模式规则
具体规则:就是指定需要更新的工作目标,如果存在的依赖的时间戳在目标的后面就是对目标进行更新。这是最常见的规则类型。
模式规则:使用的是通配符(wildcard)不是明确的文件名
隐含规则:可以是模式规则也可以是内置于make的后缀规则,这会使得makefile编写的更加容易
具体规则
需要写好目标和它们所需要的依赖,如果两个目标的依赖是一样的,那么在依赖被修改之后,两个目标要分别生成
vpath.o variable.o : make.h getopt.h
//输出
vpath.o: make.h getopt.h
variable.o : make.h getopt.h
通配符
- ~ 后面接的如果是用户名就代表当前用户的主目录,否则就代表是当前目录的用户
- * 代表这全部符合某一特点的项
- ? 代表着单一字符
- […] 代表一个字符集 比如[abcd] 可以和 "apple"里面的a匹配
- [^...] 字符集的补集 比如[^asd] 可以和"call" 里面的c匹配
注意使用通配符可能导致的一些错误,如果在执行某一个目标之前,这个目标用通配符查询之后发现不存在,就会造成错误。
所以在使用通配符查询当前应该生成的各项文件的信息之前,首先要做的就是生成你所需的.o目标文件。
注意一点:在使用通配符进行模式匹配的时候,如果模式匹配出现在目标文件里面,则是make来展开,如果出现在命令里面则是subshell来展开。make会在读取makefile之后直接展开匹配结果,但是subshell只有在执行的时候才会展开,在编写大工程的时候会造成影响。
假想工作目标 (phony target)
假想工作目标的含义:
在makefile里面你会发现有一些目标不代表文件,而是代表一些指令的执行。比如说clean是用来清理工程,那么clean就是一个比较典型的假想工作目标。
clean:
rm -f *.o $@
make不会区分假想工作目标和工作目标的区别,所以如果同一文件内部有同名的文件,就会出现一些错误.
所以make里面提供了一个特殊的目标.PHONY用来告诉make这不是一个真正的目标。
假想目标总是尚未更新的,所以每次都可以被执行。并且还会告诉makefile不要生成相应的文件。
并且假想目标可以用来改善用户接口,比如打印一些调试信息等。
变量
如果你想定义一个变量和应用变量,大致的用法如下
TARGET = main
OBJ = main.o public.o
SRC = main.cpp public.c
INCLUDE = public.h
CC = g++
${TARGET} : $(OBJ)
$(CC) $(OBJ) -o ${TARGET}
public.o: public.cpp
$(CC) -c public.cpp
自动变量
记住七个核心的就可以了
- $@ 代表的是工作目标的文件名
- $^ 所有需要生成目标文件的必要条件的文件名
- $? 代表的是时间戳在当前目标文件之后的所有文件,并且以空格分割
- $< 第一个必要条件的文件名,一般就是下面需要生成的.o文件名
- $% 档案文件成员内部的变量
- $* 工作目标的主文件名
- $+ 功能和$^差不多,但是可能会包含重复的文件名
使用VPATH以及Vpath来查找文件
在使用makefile进行编程的时候我们通常会将我们的一些文件分别村犯这样是为了整个项目更加好管理,如果不分开目录写一旦工程量大了就会造成麻烦。
在编程的时候我们一般将makefile放在上层,之后将头文件放在include文件夹里面,源码就放在src文件夹里面。
但是在编译的时候Make会找不到相应的文件,因为它们被放在了下一级的文件夹里面。
我们使用Vpath和VPATH来指定文件的目录进行查找。
#指定路径给VPATH搜索
VPATH = src
main: main.o public.o
g++ $^ -o $@
main.o: main.cpp include/public.h
g++ -c $< -o $@
public.o: public.cpp include/public.h
g++ -c $< -o $@
编译结果,自动包含.cpp文件的路径src,并且在makefile里面做出了调整使得输出更加明确。
如果出现找不到头文件的错误那就需要指定头文件的文件夹
CPPFLAGS = -I include
#使用的时候 g++ $(CPPFLAGS) -c $< -o $@
But VPATH有一个特性就是如果在不同的目录里面有重名的选项的话就只会找到第一个文件就不会再去找了。
所以,可以使用vpath来指定什么文件夹里面找什么文件。
vpath %.c src
vpath %.h include
模式规则
使用匹配来简化Makefile的书写量
采用假设的方式,如果依赖是.o文件的话那么c编译器默认是将从c文件里面编译生成新的.o文件,简化成以下
#指定路径给VPATH搜索
VPATH = src include
main: main.o public.o
main.o: main.cpp public.h
public.o: public.cpp public.h
模式
模式规则里面的百分比符号(%)等效于Unix shell里面的*号的作用,可以代表任意多个字符。
百分比以外的文字将会被按照字面进行匹配,一个模式里面可以包含一个前缀或者一个后缀,或者都包含。
在前缀和后缀之间的部分是词干(stem),匹配的时候就是在提取词干。
#前缀
lib*
#后缀
*.cpp *.h
#前后缀
lib*.a stl_*.h
静态模式规则
只可以用在特定的工作目标上面,开头多了一个object,表示指定了相应的目标
$(OBJECT): %.0:%.c
$(CC) -c $(CPPFLAGS) $< -o $@