(1)make及makefile 概念和作用
在大型的开发项目中,通常有几十到上百个的源文件,如果每次均手工键入gcc命令进行编译的话,则会非常不方便。
利用make工具来自动完成编译工作,包括:a)如果仅修改了某几个源文件,则只重新编译这几个源文件;b)如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。make工具通过makefile文件来实现自动化编译。Make工具不仅应用于编程,也可以用于描述一些文件改变时,需要自动更新另一些文件的任务。
make机制的运行需要一个命令行程序make和一个名为makefile或Makefile的文本文件。make是一个命令工具,具体来说是一个解释makefile或Makefile中的指令的命令工具。
make程序执行时,若不通过“-f”选项明确指定,它会在当前目录下先搜索名为makefile的文件,若找不到,就查找名为Makefile的文件。按照传统,许多Linux选择文件名Makefile,这样的话,若Makefile所在目录下其他的文件名均为小写,则在显示该目录的文件列表时,Makefile会出现在第一个。(参数‘-f name’或‘--file=name’)
(2)以下是一个简单的makefile使用示例:
程序功能:用户输入一个字符串,内有若干个字符,然后再输入一个字符,要求程序将字符串中的该字符删去,最后打印显示处理后的字符串。为演示make工具编译多个源程序文件的方法,将程序分为4个源文件:main.c、f1.c、f2.c、f3.c。f1.c实现字符串的输入;f2.c负责删除字符串中的某个特定字符(该字符由用户输入),f3.c输出处理后的字符串;main.c负责对各个程序模块的调用。源程序如下图:
为了使用make自动编译这些源文件,程序员需要编写make工具所需遵循的编译规则,即Makefile文件。Makefile文件内容如:
all: main.c foo1.c foo2.c foo3.c(冒号与main.c及各.c文件之间有空格)
gcc main.c foo1.c foo2.c foo3.c -o all
注意,4个.c源程序文件及Makefile文件应存放在同一个目录下,当使用make进行自动编译时,它会在该目录下找到Makefile文件,并按照Makefile文件中的内容(编译规则的集合)进行自动编译。用make自动编译。在前面提及的目录下输入make命令,产生的输出结果如下:
Make命令后面带参数(-s cc=gcc all等等),其中cc=gcc属于外部全局变量赋值,在这里这个全局变量是一个命令行宏定义且具有最高优先级的,(命令行宏定义->makefile定义->shell定义->C文件中预定义)。
此外,该例使用另两种写法的makefilez<最好先看完步骤(3)>
(3)再通过一个示例讲解Makefile文件的书写规则,以及make命令如何遵循Makefile的内容来进行编译工作。事实上,我们可以把以下几个源代码文件想象成任何可行的代码。
在前面所示的Makefile文件中,目标(target)包含以下内容:最终的可执行文件edit以及8个中间目标(*.o文件);依赖文件(prerequisites)即每个冒号后面的那些文件,每个.o文件都有一组依赖文件(.c文件和.h文件),而这些.o文件又是最终目标edit的依赖文件。注意:代表清除动作的目标clean(清除可执行文件及所有目标文件)没有依赖文件。
依赖关系的实质是说明目标文件由哪些文件生成,定义了依赖关系后,后续的代码定义了生成目标文件的有关命令(即生成目标的方法),注意这些命令一定要以一个Tab键作为它的开头。
make命令会比较target文件和prerequisites文件的修改日期,如果prerequisites文件的日期比target文件的日期要新,或者target不存在,make就会执行后续定义的命令。
make命令会比较target文件和prerequisites文件的修改日期,如果prerequisites文件的日期比target文件的日期要新,或者target不存在,make就会执行后续定义的命令。
显式规则:makefile的书写者显式地指出要生成的目标文件、目标文件的依赖文件以及生成目标文件的命令。
隐式规则:make有自动推导的功能,会选择一套默认的方法进行make,所以隐式的规则可以让开发者比较简略地书写Makefile,这是由make所支持的。
(4)变量的定义:在Makefile中我们可以定义一系列的变量,变量的值一般都是字符串,像C语言中的宏,当Makefile被执行时,其中的变量就会被扩展到相应的引用位置上。
文件指示:makefile的书写者显式地指出要生成的目标文件、目标文件的依赖文件以及生成目标文件的命令。包括三个部分:
a)在一个Makefile中引用另一个Makefile,就像C语言中的#include一样包含进来;
b)根据某些情况指定Makefile中的有效部分,就像C语言中的预编译宏#ifdef一样;
c)定义一个多行的命令。
注释:Makefile中只有行注释,注释以“#”字符开头。
Makefile中的变量,就像是C/C++语言中的宏一样,代表文本字符串,在Makefile中执行的时候会自动原样地展开在所使用的地方。
其与C/C++的宏所不同的是可以在Makefile中改变其值。在Makefile中,变量可以使用在目标、依赖目标、命令或是Makefile的其它部分中。
变量的命名可以包含字符、数字、下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空白字符(空格、回车等)。
变量名对大小写敏感,传统的变量名是全大写的命名方式。
变量的定义格式
变量名 赋值符号(可数字开头) 变量的值
赋值符号有三种:
(空格)=(空格)直接将后面的字符串赋给变量
(空格):= (空格)后面跟变量,将它的内容赋给变量
(空格)+=(空格)变量原来的值+空格+后面的字符串=>新的变量值。如:cc = gcc \ dd = arm \ cc += $(dd)
变量引用的三种格式:
a)$(变量名) b)${变量名} c)当变量名为单个字符时,可以省略括号
make处理变量时会扫描一遍整个Makefile,确定所有变量的值,因此变量的使用可以在定义之后,而且使用的是最后一次赋予的值。
例: objects = program.o foo.o utils.o
program : $(objects)
gcc -o program $(objects)
变量的定义可以出现在三个地方
在makefile中定义;在make命令行中定义;使用shell环境中的定义。优先级:见(1)
(5)make有许多预定义的变量,这些变量具有特殊的含义,可在规则中直接使用。 重点掌握下表中红圈标注。
(6)两个常用函数:
a)wildcard函数(通配符函数),其形式是:
$(wildcard _pattern)
通过该函数可得到当前工作目录中满足_pattern模式的文件或目录名列表。如:
SRCS:=$(wildcard *.c)
b) patsubst函数,格式为:
$(patsubst
查找
OBJS:=$(patsubst %.c, %.o, x.c.c bar.c)
函数返回结果为:x.c.o bar.o
例:srcs = $(wildcard *.c) #所有.c文件
dd = $(patsubst %.c, %.o, $(src)) #src中.c文件生成.o文件
#其中%.c, %.o代表任意.c,.o文件;
(7)伪目标.PHONY(见下例)
注:行前加 ’-‘或 ’@’;加 ’-’表示编译时即使该行有错误也会被忽略,加 ’@’表示编译时该行若有错误则只编译到该行就不再往下继续编译了。