Makefile用于多文件工程的编译
例如一个简单的工程
1.add.h
#ifndef _ADD_H
#define _ADD_H
extern int add_int(int a,int b);
extern float add_float(float a, float b);
#endif
add_int.c
int add_int(int a, int b)
{
return a+b;
}
float add_float(float a, float b)
{
return a+b;
}
2.main.c
#include <stdio.h>
#include "add.h"
int main()
{
int a = 1, b = 2;
float c = 2.1, d = 3.1;
printf("add_int: %d + %d = %d\n",a,b,add_int(a,b));
printf("add_float: %f + %f = %f\n",c,d,add_float(c,d));
return 0;
}
对于多文件工程,当需要频繁的修改源文件或者项目中文件比较多,关系比较复杂时,用命令行直接进行编译就会变得十分困难。
使用make进行项目管理,需要一个Makefile文件。make在进行编译的时候,从Makefile文件读取设置情况,进行解析后运行相关的规则。make程序查找当前目录下的文件Makefile或者makefile,按照其规则运行。
1)为上面的程序建立如下Makefile文件。
在命令行输入
vi makefile
#把程序命名为testmakefile, :右边为目标
testmakefile:add_int.o add_float.o main.o
gcc -o testmakefile add_int.o add_float.o main.o
#生成add_int.o的规则
add_int.o:add_int.c add.h
gcc -c -o add_int.o add_int.c #注意前面的空白是Tab键
add_float.o:add_float.c add.h
gcc -c -o add_float.o add_float.c
main.o:main.c add.h
gcc -c -o main.o main.c
#清理的规则
clean:
rm -f testmakefile add_int.o add_float.o main.o
2) 多文件的编译
在上面的Makefile文件编写完成后,运行make命令
执行命令: make clean 会调用clean相关规则,清楚编译出的目标文件及testmakefile。
Makefile的规则
Makefile的框架是由规则构成的。make命令执行时现在Makefile文件中查找各种规则,对各种规则进行解析后,运行规则。 规则的基本格式为:
TARGET... : DEPENEDS...
COMMAND
...
...
TATGET: 规则所定义的目标。 通常规则是最后生产的可执行文件的文件名或者为了生产可执行文件而依赖的目标文件的文件名,也可以是一个动作,称之为“伪目标”
DEPENDEDS:执行此规则所必须的依赖条件,例如生成可执行文件的目标文件。
COMMAND: 规则所执行的命令,即规则的动作,例如编译文件,生产库文件,进入目录等。动作可以是多个,每个命令占一行
规则书写时要注意COMMAND的位置,COMMAND前面的空白是一个Tab键,不是空格! Tab告诉make这是一个命令行,make执行相应的动作
执行的规则:
在调用make命令编译时,make程序会查找Makefile文件中的第一个规则,分析并执行相关的动作。 上面的makefile中第一个规则是
testmakefile, 所以make程序执行testmakefile规则。 其包含3个依赖项, 第一个为add_int.o,分析其依赖项,当add_int.c ,add.h存在时,执行如下命令
gcc -c -o add_int.o add_int.c
当命令执行完毕时,按照顺序执行第二个依赖项。。。。
Makefile中使用变量
在上面的makefile中,生成testmakefile的规则如下
testmakefile:add_int.o add_float.o main.o
gcc -o testmakefile add_int.o add_float.o main.o
生成testmakefile时,多次使用同一组.o目标文件。 在DEPENDEDS中出现一次,生产testmakefile执行文件时又出现一次。 如果文件很多的话,直接使用文件名进行书写的方法不仅书写起来麻烦,而且进行增加或者删除文件容易遗忘。 例如增加一个haha.c文件,需要修改依赖项和命令行两个部分。
可以使用Makefile中的用户自定义变量, 例如用OBJS变量表示目标文件
OBJS = add_int.o add_float.o main.o
调用OBJS时前面加上$,并且将变量的名称用括号扩起来。
testmakefile:
gcc -o testmakefile $(OBJS)
用CC变量表示gcc, RM表示rm -f, TARGET表示最终生产的testmakefile, 则之前的Makefile可简化成如下方式
CC = gcc
TARGET = testmakefile
OBJS = add_int.o add_float.o main.o
RM = rm -f
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS)
$(OBJS):%.o:%.c #将OBJS中所有扩展名为.o的文件替换成扩展名为.c的文件
$(CC) -c $< -o $@ #编译生成目标文件
clean:
-$(RM) $(TARGET) $(OBJS) #$前面的-表示当操作失败时不报错,命令继续执行。 例如当前目录不存在testmakefile时,它会继续删除其他的目标文件
上面的$< 和 $@是Makefile中常见的自动变量 , 具体含义百度