Makefile介绍
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
通俗点来说,假如在一个工程当中有很多文件,在没有makefile的情况下,需要几百行才能完成整个工程的编译,但是有了Makefile,只需一个指令就能完成整套功能的编译,极大的提高了工作的效率。
基本的语法规则
目标 ... : 依赖 ...
命令1
命令2
. . .
- 目标——即为要生成的文件,依靠依赖文件和命令才能生成目标文件,在默认情况下,第一个目标即为终极目标
- 依赖文件——即目标文件需要依赖哪些文件才能生成。
- 命令——即通过执行命令由依赖文件生成目标文件。 注意每条命令之前必须有一个tab ,这是语法要求。
举例:
main:main.c
gcc -c main.c -o main
Makefile中的变量
系统变量
- $* 不包括扩展名的目标文件名称
- $+ 所有依赖文件,以空格分隔
- $< 表示规则中的第一个条件
- $? 所有时间戳比目标文件晚的依赖文件,以空格分隔
- $@ 目标文件的完整名称
- $^ 所有不重复的依赖文件,以空格分隔
- $% 如果目标是归档成员,则该变量表示目标的归档成员名称
举例:
- $^ 所有不重复的依赖文件,以空格分隔
add.o:add.c
gcc -c $^ -o add.o
//原型:gcc -c add.c -o add.o
- $@ 目标文件的完整名称
add.o:add.c
gcc -c $^ -o $@
//原型:gcc -c add.c -o add.o
系统常量
- AS ——汇编程序名称,默认为as
- CC—— C编译器名称 默认cc
- CPP——C预编译器名称 默认cc -E
- CXX——C++编译器名称 默认g++
- RM——文件删除程序别名 默认rm -f
举例
clean:
$(RM) *.o main.out
//原型:rm -f *.o main.out
main.o:main.c
$(CXX) -c $^ -o $@
//原型:g++ -c main.c -o main.o
自定义变量
定义:变量名 = 变量值
使用:$(变量名)或者${变量名}
举例
OBJ = add.o sub.o main.o
TARGET = main.out
$(TARGET):$(OBJ)
gcc $(OBJ) -o $@
//原型
main.out:add.o sub.o main.o
gcc add.o sub.o main.o -o main.out
伪目标
使用为目标的意义是什么呢?
答案是: 避免同名文件冲突,例如,如果有一个名为 clean 的目标,而系统中也存在一个名为 clean 的文件,执行 make clean 命令时,可能会误删除同名文件。使用伪目标则可以避免这种问题,因为伪目标不对应真正的文件,执行伪目标的命令并不会对其他同名文件有任何影响。
伪目标的使用
先声明 , 后使用。用 # 表示注释。如下所示:
# 声明一个 clean 的伪目标
.PHONY : clean
clean :
rm *.o hello.out
伪目标的规则的调用
当一个目标的依赖包含伪目标时,伪目标所定义的命令总是会被执行.,如下所示,
hello.out : func.o main.o
gcc -o hello.out func.o main.o
func.o : func.c
gcc -o func.o -c func.c
main.o : main.c
gcc -o main.o -c main.c
#声明了rebuild clean all三条伪目标
.PHONY : rebuild clean all
rebuild : clean all
all : hello.out
clean :
rm *.o hello.out
rebuild 伪目标 依赖于 clean 和 all, 所以要 执行 rebuild 目标时,要先去执行 clean 和 all命令。相当于函数的调用。
绕开 .PHONY关键字定义伪目标
如果 一个规则没有命令 或者依赖,并且它的目标不是一个存在的文件名,则 在执行此规则时,目标总是被认为是最新的,命令就会总是执行。相当于 伪目标.PHONY的使用。
clean : FORCE
rm *.o hello.out
FORCE :
FORCE 目标没有命令 ,依赖。那么在执行此规则时,总是被认为是最新的,命令就会总是执行。
模式匹配
使用模式匹配可以使代码量更加简短,具体使用方法可以参考:Makefile中的伪目标和模式匹配