Makefile文件的编写方法


什么是Makefile?

一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令.

为什么要使用Makefile?

就像前面提到的,一个工程的源文件可能不计其数,编写makefile,使用make命令来构建工程,会使原本复杂繁琐的工作简化许多,极大地提高了效率

如何使用make命令?

Makefile 文件描述了整个工程的编译、连接等规则,make是一个命令工具,它解释Makefile中的指令(规则)。

一个基本的makefile主要由目标对象、依赖文件、变量和命令4部分组成。


命令行中执行makefile内容:

◆宏定义

◆ 源文件之间的相互依赖关系

◆ 可执行的命令

通常makefile文件中的一条规则的编写形式如下:

target ... : prerequisites ...
(tab)command
...
...

解释为:
目标:依赖文件
(制表符)执行指令 ...


下面来看一个具体的例子:

新建 三个文件:main.c, add.c, head.h

/*head.h*/
ifndef  _HEAD_H
#define _HEAD_H_
		
#include<sdtio.h>
#include<math.h>
int add(int a,int b)
#endif

/*add.c*/
#include"head.h"
int add(int a,int b)
{
	return a+b;
}
	
/*main.c*/
#include"test.h"
int main()
{
	int a=5,b=6,c=0;
	c=add(a,b);
	printf("%d+%d=%d\n",a,b,c);
	c=pow(a,b);						//c=a^b
	printf("%d^%d=%d\n",a,b,c);

	return 0;
}


下图体现了文件间的依赖关系:


我们先使用gcc 命令来构建这个工程:

gcc  -c  main.c  add.c

 查看当前文件目录:



文件夹中多了main.o 和 add.o这两个文件,接着在执行下面的命令:

gcc main.o  add.o  -o math  -l  m//用main.o add.o 进一步生成目标   ,最后两个参数 -l  m 为连接数学函数库



我们发现生成目标文件math需要两步,也就是要先生成main.o 和 add.o 这两个中间文件,这两个文件称为目标文件的直接依赖文件,那么main.c和add.c分别又是main.o和add.o的直接依赖文件。


makefile正事依据这样一层一层的的依赖关系和连接 依赖文件 和 目标文件 的命令 所构成的。


下面来看一个最基本的makefile文件:


以下makefile文件显示了各个目标与依赖文件直接的关系,以及生成它们的命令

#This is an example for describing make file  		//此行为makefile的注释
add:main.o add.o                              		//目标文件add的依赖文件为main.o、add.o
	gcc -o add main.o add.o -l m			//将目标文件连接为可执行文件,并连接数学函数库
	
main.o:main.c 						//main.o的依赖文件为main.c 
	gcc -c main.c					//将源文件main.c编译成目标文件main.o

add.o:add.c 
	gcc -c test.c

clean:							//清理中间文件
	rm main.o add.o add 



编写makefile文件中要注意的几点:

1、clean没有被第一个目标add直接或间接依赖,那么它后面的命令就不会被自动执行可以在make 命令后面跟clean目标作为参数来执行其后所定义的命令,

即执行"make clean"命令,用于清除make过程中生成的目标,以便重新编译


2、在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。


3、记住,make并不管命令是怎么工作的,他只管执行所定义的命令。make会比较目标文件和依赖文件的修改日期,即时间戳
如果依赖文件的日期要比目标文件的日期要新,或者目标不存在的话,那么,make就会执行后续定义的命令


先执行rm main.o add.o math 清除之前生成的中间文件和目标文件


然后用ls命令查看以下当前目录所包含的文件:



执行make命令,再用ls查看当前目录下的文件:



我们发现,make命令已经生成了add目标文件,还有依赖文件main.o, add.o


执行结果:



执行make命令时,可以通过参数为makefile文件的宏变量CC赋值,通过宏变量CC指定不同的编译器来编译源文件

#This is a example for describing makefile
CC=
add:main.o add.o
	$(CC) -o add main.o add.o
main.o:main.c
	$(CC) -c main.c
add.o:add.c
	$(CC) -c add.c

clean:
	rm main.o add.o add



下面,对makefile做一点小小的改动:

OBJS=main.o add.o						#使用了变量OBJS
CC=gcc
CFLAGS=-Wall -O -g

add:$(OBJS)
	$(CC)  $(OBJS)  -o  add
main.o:main.c
	$(CC)  $(CFLAGS)  -c main.c 
add.o:add.c
	$(CC)  $(CFLAGS)  -c  add.c

clean:
	rm *.o   add


这里使用到了变量,用CC代替了gcc, CFLAGS是makefile中预定义的变量,我们为将它初始化为-Wall -O  -g (开启警告信息、编译链接过程中执行优化处理、增加调试信息),这三个参数都是gcc参数的常用的值,关于gcc参数常用值,这里不做具体介绍。

Makefile中允许使用简单的宏指代源文件及其相关编译信息,在Linux中也称宏为变量。在引用宏时只需在变量前加$符号,
但值得注意的是,如果变量名的长度超过一个字符,在引用时就必须加圆括号()。
有效的宏引用
$(CFLAGS)
$Z
$(Z)


makefile中常见的预定义变量及其部分默认值

预定义变量
名称或选项
默认值
AR库文件维护程序的名称
ar
AS汇编程序名称的
as
CCC编译器的名称
cc
CPPC预编译器的名称
$(CC) –E
FCC++编译器的名称
f77
RMFORTRAN编译器的名称
rm  -f
ARFLAGS文件删除程序的名称
ASFLAGS库文件维护程序的选项
CFLAGS汇编程序的选项
CPPFLAGSC编译器的选项
CXXFLAGSC++编译器的选项
FFLAGSFORTRAN编译器的选项

我们先使用make clean 清除之前生成的目标文件,再执行make命令,得到的结果是一样的



下面再对makefile进行升级:

#Makefile
CC=gcc
CFLAGS=-Wall -O -g
OBJS=main.o add.o
add:$(OBJS)
	$(CC)  $^ -o $(OBJS)
main.o:main.c
	$(CC)   $(CFLAGS)   -c  $<  -o  $@
add.o:add.c
	$(CC)   $(CFLAGS)  -c  $<  -o  $@

clean:
	rm   -f   *.o 


这里使用了makefile 的自动变量,下表是makefile中常见的自动变量:

makefile中常见的自动变量

自动变量含义
$*不包含扩展名的目标文件名称
$+所有的依赖文件,以空格分开,并以出现的先后为顺序,可能包含重复的依赖文件
$<第一个依赖文件的名称
$?所有时间戳比目标文件完晚的依赖文件,并以空格分开
$@目标文件的完整名称
$^所有不重复的依赖文件,以空格分开
$%如果目标是归档成员,则改变量表示目标的归档成员名称

自动变量通常可以代表编译语句中出现的目标文件和依赖文件等,自动变量的使用进一步简化makefile的编写,自动变量的书写比较难记,但是在熟练了之后会非常方便。


下面是一个使用二进制作为目标文件的makefile模板:

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=main add					//这一行添加依赖文件的名称
all:$(BIN)
%.o:%.c
	$(CC) $(CFLAGS)	-c $< -o $@
clean:
	rm -f *.o $(BIN)

关于maefile的写法,其形式可能有很多种,makefile还支持带有条件语句的条件编译、函数、以及一些隐含规则等,这里不做深入介绍,只有多加练习、实践,才能真正掌握make这个强大的工具。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值