Make是一个工具程序,用来管理工程如何编译。
在许多软件的开发中,集成开发环境已经取代Make,但是在UNIX环境中,任然有许多工程师使用Make来协助软件开发。
文件在编译时分为4个阶段:预处理、编译、汇编、链接 。
单文件编译
预处理: gcc -E test.c -o test.i
编译: gcc -S test.i -o test.s
汇编: gcc -c test.s -o test.o
链接: gcc test.o -o test
单文件的编译可以将预处理、编译、汇编三合一 ,再去链接 ,生成可执行文件
gcc test.c -o test.o
gcc test.o -o test
也可以将预处理、编译、汇编、链接四合一 ,生成可执行文件
gcc test.c -o test
多文件编译
gcc 所有源文件名 -o 可执行文件名
对于大型项目,每个目标文件由于头文件的引入而依赖于一些其他的目标文件,如果每次编译的时候都需要编译整个项目,则需要浪费较多的时间。我们希望只编译对那些发生变化的文件重新编译,没有变化的文件就不在编译。于是引入了Make工程管理器,它是通过编写makefile文件制定编译规则的。
makefile命名可以是Makefile,也可以是makefile,在执行make的时候编译器会在当前路径下去寻找Makefile/makefile文件
makefile文件编写
makefile执行时通过依赖文件生成目标文件
makefile文件编写格式:
目标文件:依赖文件
[tab]依赖文件 如何生成目标文件
# 例如多文件编译
# test是目标文件
# test1.o test2.0 test3.o是依赖文件
test:test1.o test2.0 test3.o
gcc test1.o test2.o test3.o -o test
注意点:
在以上格式中第二行必须是tab,不能是空格。在生成目标文件前,必须准备好依赖文件。在makefile文件中这些命令可以通过使用变量进行简化
makefile中的变量
预定义变量
CC : c编译器的名称,默认为cc
CFALGS : c编译器的选项,无默认值
RM : 文件删除程序的名称,默认为rm -rf
简单说CC就是编译器,CFLAGS就是参数。
自动变量
$@ : 表示目标文件,包含扩展名
$^ : 表示所有的依赖文件,以空格隔开,不重复
$+ : 表示所有的依赖文件,以空格隔开。可能含有重复的文件
$< : 表示第一个依赖文件
$* : 表示目标文件的名称,不包含扩展名
$? : 依赖项中,所有比目标文件新的依赖文件
自定义变量
OBJ : 用于存放可执行文件的名字
OBJS:用于存放所有的目标文件
变量定义的两种方式
递归展开方式 VAR=var
后面的值会影响前面的结果
简单方式 VAR:=var
在make管理工程是通过嵌套Makefile来进行管理的。
嵌套Makefile
1.创建目录,include(.h文件)、src(.c文件)、obj、bin(可执行文件)
2.编写总控Makefile,书写自定义变量或者预定义变量
APP: 可执行文件
CC: 编译器
CFLAGS: 编译选项
OBJS :过程文件
将这些变量用export传递到下一级
3.进入src目录,编写Makefile(将所有的.c文件编译生成.o文件,并移动到obj目录中)
目标文件(ALL):源文件(OBJS 所有.o文件)
[tab] 将目标文件移动到obj目录下
目标文件(.o文件):源文件(.c文件)
4.进入obj目录,编写Makefile(将所有的.o文件编译生成可执行文件,并移动到bin目录中)
目标文件(ALL):源文件(可执行文件)
[tab] 将源文件(可执行文件)移动到bin目录下
目标文件(可执行文件):源文件(.o文件)
5.编辑总控Makefile(先执行src中的makefile(make -C src)),然后再执行obj中的Makefile(make -C obj)
每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”。一般的风格都是:
那么此时完整的主控Makefile为:
此时在工程文件夹下执行make