在前边的两个章节中,我们提到了makefile中的目标,并且知道这个目标存在且依赖没有更新,make就不再编译程序。
一般在默认的情况下
- make 认为目标对应着一个文件(可执行程序、so库等等)
- 比较目标文件和依赖的新旧关系,决定是否执行命令
- make以文件处理作为第一优先级
clean :
rm *.o hello.out
在上边的一个简单的makefile文件中,当我们执行make clean时,就会删除.o、hello.out文件,因为clean目标被make认为是文件,当目录下有一个文件叫clean时,make clean 下的命令便不会执行。所以我们希望clean 不对应文件,仅仅对应一个类似标签这样的东西。
解决方案:引入伪目标
- makefile中的伪目标通过 .PHONY关键字声明
- 伪目标不对应任何实际的文件,其下的命令总是执行
伪目标需要先声明后使用,声明语法为 .PHONY : clean
伪目标本质为.PHONY目标的依赖
.PHONY : clean #声明clean为伪目标
clean :
rm *.o hello.out
此时执行make clean,其他的命令总是被执行,不关注依赖是否有更新
一、伪目标的使用技巧1
我们在编译程序的时候,希望make包含的功能有删除现有文件、编译、重编译(先删除后编译),这时候可以使用伪目标,makefile文件如下
.PHONY clean rebuild all #声明3个伪目标
rebuild : clean all #伪目标 rebuild 依赖与伪目标 clean 与 all
all : main.o func.o
gcc -o hello.out main.o func.o
main.o : main.c
gcc -o main.o -c main.c
func.o : func.c
gcc -o func.o -c func.c
clean :
rm *.o hello.out
在如上的makefile中,我们定义了三个伪目标 clean、 rebuild、 all,并且将rebuild的伪目标依赖设为clean、all,所以当执行make rebuild时,就会先执行clean all 伪目标下的命令,这有点类似函数调用。
调用原理:当一个伪目标的依赖包含伪目标时,伪目标所定义的命令总是会被执行
执行make rebuild的结果如下(每次都是强制重编)
/home/delphi/myshare/makefile>make rebuild
rm *.o hello.out
gcc -o main.o -c main.c
gcc -o func.o -c func.c
gcc -o hello.out main.o func.o
/home/delphi/myshare/makefile>
二、伪目标的使用技巧2
绕开.PHONY关键字定位伪目标
在开始这个技巧之前,首先来看一个原理:
如果一个规则没有命令或者依赖,并且其目标不是一个存在的文件名,那么在执行此规则时,目标总是会被认为最新的
FORCE:
如上的规则只有一个目标FORCE,没有依赖、没有命令,只要makefile目录下没有文件名为FORCE的文件,那么make FORCE时,命令总是被执行(当然这里的命令为空),有了以上理解,来看下如下的makefile
clean : FORCE
rm -f *.o hello.out
FORCE:
clean依赖的目标FORCE既没有依赖也没有命令,那么FORCE这个目标总是被认为是最新的,所以每次执行make clean时,rm *.o hello.out 命令总是被执行,不管目录下有没有clean这个文件存在(因为其依赖FORCE总是被认为最新的),
/home/delphi/myshare/makefile>make clean
rm -f *.o hello.out
/home/delphi/myshare/makefile>make clean
rm -f *.o hello.out
/home/delphi/myshare/makefile>
小结:
- 默认情况下,make认为目标对应着一个文件
- .PHONY用于声明一个伪目标,伪目标不对应实际的文件
- 伪目标的本质是make中特殊目标.PHONY的依赖
- 使用伪目标可以模拟"函数调用"
以上内容参考《狄泰软件学院》操作系统篇之 - makefile专题