1.make和makefile的介绍
1.1 make和makefile的概念
//多文件联合编译举例,
//若有成百上千的文件,编译起来是非常麻烦的一件事,既要考虑编译规则,又要考虑依赖关系
gcc -o test1.o -linclude test1.c
gcc -o test2.o -linclude test2.c
gcc -o test test1.o test2.o
make引入的原因
- 一个软件工程中的原文件不计其数,其按类型、功能、模块分别放在若干个目录中,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,这就需要一个工具来全面地、系统地进行处理。
make和makefile
- Linux/Unix系统有一个非常强大的实用程序,成为make,可以用它来管理多模块程序的编译和链接,直至生成可执行程序。
- make实用程序读取一个说明文件,也就是makefile文件。makefile文件描述了整个软件工程的编译规则及各个文件之间的依赖关系。
- makefile就像一个shell脚本,其中也可以执行操作系统的命令。它打来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个软件工程完全自动编译,极大的提高了软件开发的效率。
- male是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,visual C++的nmake,linux下GNU的make。
- make使重新编译的次数达到最小化
- makefile实质上是一种脚本语言
1.2 make的发展
make的来源
- make 程序最初来源于steve Johnson的一个拜访,那天他风风火火的闯进我的办公室,诅咒命运之神让他浪费了一个早上来调试一个正确的程序(bug修改了,但是没有编译,因此gcc*.o无效)。而我也花了前一个晚上的部分时间在我参与的项目中解决同样的灾难,这样编写一个工具来解决这个问题的想法诞生了。最开始是精细的依赖关系分析器,浓缩为更简单的东西后,周末就出炉了make.新兴工具的使用也是unix文化的一部分。Make文件都是文本的,不是神秘的二进制编码,因为就是unix的精神:可打印,可调试,可理解。 ----stuart Feldman
2.make和makefile(上)
2.1 make的使用语法
make的使用语法:make [选项] [目标] [宏定义]
常用选项 | 特性 |
---|---|
-d | 显示调试信息 |
-f <文件> | 指定从哪个文件中读取依赖关系信息。默认文件是“Makefile”或“makefile”,“-”表示从标准输入 |
-h | 显示所有选项的简要说明 |
-n | 不运行任何Makefile命令,只显示它们 |
-s | 安静的方式运行,不显示任何信息 |
2.2 makefile的编写原则和使用规则
makefile的编写原则
- 当make命令不带选项运行时,它从makefile中读取制定规则
- 当制定规则在不同于makefile(或Makefile)的其他文件中,就要运行带有-f选项的make命令,比如make.fray.Makefile
makefile的编写规则一
目标列表:关联性列表
<TAB>命令列表
- 目标列表:是一个或多个空格分开的目标文件的清单
- 关联性列表(也成先决条件):同样是用一个或更多个空格分开的目标文件,是目标列表所依赖的多个目标文件的清单。
- 命令列表:用于创建目标文件的将要执行的命令清单,这些命令被换行符分开。命令列表中的每个命令必须以<Tab>字符开始。
makefile的编写规则二
目标列表:关联性列表;命令列表
- 命令列表是一系列被分号隔开的命令。一个很长的命令行要续行时可以用反斜线符号。
- 命令列表示例
cd /home/test/bin; rm filel file2 \
lab2 lab3\
prog1.c prog2.c prog5.c
等同于
cd /home/test/bin; rm filel file2 lab2 lab3 prog1.c prog2.c prog5.c
- Makefile中可使用shell中的一些通配符:注释(#),连接符(\),关联列表和命令列表中可使用shell通配符? 、*、%等
- Makefile示例1(power可执行文件的生成依赖于power.c)
#Sample Makefile for the power program
#Remember: echo command line starts with a TAB
power:power.c
gcc -o power power.c
- Makefile示例2(power.c分为两个文件)
power:power.o compute.o
gcc -o power power.o compute.o
power.o:power.c
gcc -o power.o -c power.c
compute.o:compute.c
gcc -o compute.o -c compute.c
- Makefile示例2依赖关系如下图所示(依赖关系树可以帮助我们梳理思路):
- make执行时,会检查文件是否更新,若没有更新,不会重复编译
- make -d :显示相关调试信息,类似日志
- make -s :隐藏执行过程,不在终端显示执行过程
- make -h :显示及所有可用选项
3.make和makefile(下)
3.1 Makefile的变量使用
简单变量
- 定义:变量名:=[文本] //这类变量的实质就是一组字符串
- 添加:变量名+=[文本] 等价于 变量名:=[文本] [文本]
引用变量
- $(变量名)
- $单字符变量:eg:G:=gcc $G -o power power.c //注意等号两边不要加空格
-
CC:=gcc CFLAGS:=-Iinclude CFLASS+=-c power:power.o compute.o $(CC) -o power power.o compute.o power.o:power.c $(CC) -o power.o $(CFLASS) power.c compute.o:compute.c $(CC) -o compute.o $(CFLASS) compute.c
内置变量
- make中有几个内置变量,使用这些变量您的工作会更简单。常用的内建(内部)变量和它们的意义:
变量名 | 意义 |
---|---|
$@ | 当前目标的名称 |
$? | 比当前目标更新的已修改的依赖性列表 |
$< | 依赖性列表中的第一个文件 |
$^ | 用空格分开的所有依赖性列表 |
CC:=gcc
CFLAGS:=-Iinclude
CFLASS+=-c
power:power.o compute.o
$(CC) -o $@ $^
power.o:power.c
$(CC) -o $@ $(CFLASS) $^
compute.o:compute.c
$(CC) -o $@ $(CFLASS) $^
3.2 虚目标
- 不存在的文件,而且也无需创建他们
- 允许你强制执行某些事件,而这些事件在正常规则中是不会发生的。
- 虚目标不是真正的文件,make命令可以使用针对它们的任意规则
- 虚目标总是使与之有关的命令被执行
- 常见虚目标列表
目标 | 意义 |
---|---|
all | 生成工程中所有可以执行者,通常是Makefile的第一个生成目标 |
test | 运行程序的自动测试套件 |
clean | 删除make all生成的所有文件 |
install | 在系统目录中安装工程项目生成的可执行文件和文档 |
uninstall | 删除make insatll安装的所有文件 |
CC:=gcc
CFLAGS:=-Iinclude
CFLASS+=-c
DEPEND:=power.o
DEPEND+=compute.o
power:$(DEPEND)
$(CC) -o $@ $^
power.o:power.c
$(CC) -o $@ $(CFLASS) $^
compute.o:compute.c
$(CC) -o $@ $(CFLASS) $^
#通过make clean执行Makefile文件中的clean下面的命令
clean:
rm -rf $(DEPEND)
3.3 特殊目标
make中有一些预定义的目标,这些预定义目标被make以一种特殊的方式进行处理,这些目标成为特殊目标。
特殊目标 | 目的 |
---|---|
.DEFAULTS | 如果make找不到生成目标的任何makefile入口或后缀规则,它就执行与目标相关的命令 |
.IGNORE | 如果某一行makefile包含该目标,make忽略错误代码并继续执行,如果一个命令不正常存在,make自然会停止。带有-i选项的make命令可以执行相同的任务 |
.PHONY | 允许您指定一个不是文件的目标,所以您能指示make调用一系列makefile中的命令,即使在您的当前目录中有一个具有目标名称的文件 |
.SILENT | make执行这些命令但不现实这些命令,带有-s选项的make可以执行相同的任务,如前面所讨论的,在该命令前放置一个@符号就可以执行一个特别命令 |
.SUFFIXES | 为目标指定的前提(后缀)可以与后缀规则相关联,如果与目标没有相关联的前提,已存在的后缀列表就会被删除 |
CC:=gcc
CFLAGS:=-Iinclude
CFLASS+=-c
DEPEND:=power.o
DEPEND+=compute.o
power:$(DEPEND)
$(CC) -o $@ $^
power.o:power.c
$(CC) -o $@ $(CFLASS) $^
compute.o:compute.c
$(CC) -o $@ $(CFLASS) $^
#把clean看做虚目标,而不会被shell目录下的同名文件干扰
.PHONY:clean
#通过make clean执行Makefile文件中的clean下面的命令
clean:
rm -rf $(DEPEND)
3.4 默认模式规则
- make中有许多预定义的制定规则也成为后缀规则,它可以让make自动执行许多任务,
- make中已经内建许多其他语言的规则和Unix实用程序(包括SCCS、RCS、ar、lex和yacc)的规划。
- 为了建立一个目标,make会遍历一连串的依赖关系,这是为了决定从何处开始建立(或重建)。如果没有找到目标文件,make就按照优先顺序查找源文件。
- 为了生成目标文件,它首先查找带.c、.f和.s后缀的文件,如果一个都没有找到,它会继续寻找带.c后缀的文件并继续搜索,直至找到一个源文件。如果没有找到一个源文件,make就会报告一个异常。
- 默认模式规则(GNU make)
%.o:%.c:
$(CC)$(CFLASS) -c $<
%.o:%.s
$(AS)$(ASFLAGS) -o $@ $<
CC:=gcc
CFLAGS:=-Iinclude
CFLASS+=-c
DEPEND:=power.o
DEPEND+=compute.o
power:$(DEPEND)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ $(CFLASS) $^
#把clean看做虚目标,而不会被shell目录下的同名文件干扰
.PHONY:clean
#通过make clean执行Makefile文件中的clean下面的命令
clean:
rm -rf $(DEPEND)
- 默认的后缀规则(一般不用)
SUFFIXES:.o.c.s
.c.o:
$(CC)$(CFLASS) -c $<
.s.o:
$(AS)$(ASFLAGS) -o $@ $<