文章目录
1. Makefile是什么?
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,也可以执行操作系统的命令。
2. gcc编译流程
会用Makefile首先要知道gcc编译流程
方法1:
-
预处理: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 (与其它的机器代码文件和库文件汇集生成一个可执行文件)
方法2:
- 将前四步和四为一:gcc test.c -o test
3. Make工程管理器
make:工程管理器
make会在当前路径下找一个叫做Makefile的文件(注意:M大小写都可以,一般大写)。
3.1 Makefile的命名规范
目标文件1:依赖文件1
(Tab键)依赖文件1是如何生成目标文件1的
目标文件2:依赖文件2
(Tab键)依赖文件2是如何生成目标文件2的
注意:
- Tab键不能用空格代替
- 一个Makefile可以有多个目标文件
- 当目标文件1和目标文件2没有联系的时候,只会执行目标文件1,不会执行目标文件2
- 在调用make时,需要指定我们运行的目标是什么,如果没有执行,默认执行目标文件1
3.2 预定义变量和自定义变量
预定义变量:
- CC:c编译器的名称,默认为cc
- CFLAGS:c编译器的选项,无默认值
- RM:文件删除默认名称,默认为rm -rf
自定义变量:
- OBJ:存放可执行文件
- OBJS:存放目标文件
3.3 自动变量
- $@:目标文件
- $<:第一个依赖文件
- $^:所有的依赖文件
3.4 变量定义的两种方式
- 递归方式 VAR=var
注意:后面的值会影响前面的结果 - 简单方式 VAR:=var
3.5 假目标
make clean指令是清除我们的.o文件,当我们的目录下有一个clean文件就会发生错误,所以我们要用.PHONY:clean
来解决假目标的问题
案例:
下面是一个可以输入输出学生的姓名,年龄,成绩的简单程序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// 定义一个结构体,包含学生的姓名,年龄,成绩
typedef struct student
{
char name[30];
int age;
float scorce;
} stu;
//输入函数,实现简单的输入功能
stu *input(stu *p)
{
printf("请输入学生的姓名,年龄,成绩:\n");
scanf("%s",p->name);
scanf("%d",&p->age);
scanf("%f",&p->scorce);
printf("输入成功\n");
}
//输出函数,实现输出功能
stu *output(stu *p)
{
printf("学生的姓名是:%s,年龄是:%d,成绩是:%.1f\n",p->name,p->age,p->scorce);
}
int main()
{
int n;
//申请一个结构体大的空间
stu *p = (stu *)malloc(sizeof(stu));
//判断申请的空间是否成功
if(NULL == p)
{
perror("malloc error");
return -1;
}
//将申请的空间清0
memset(p,0,sizeof(stu));
while(1)
{
printf("1. 输入\n");
printf("2. 输出\n");
printf("4. 退出\n");
scanf("%d",&n);
if(4 == n)
{
break;
}
switch(n)
{
case 1:
input(p);
break;
case 2:
output(p);
break;
}
}
//释放空间
free(p);
return 0;
}
接下来使用Makefile
CC:=gcc
CFLAGS=-c
OBJ=sort
OBJS=sort.o
$(OBJ):$(OBJS)
$(CC) $< -o $@
sort.o:sort.c
$(CC) $(CFLAGS) $< -o $@
.PHONY:clean
clean:
$(RM) *.o
实现成功!
简单工程确实很麻烦,但是当我们工程大的时候,就会方便很多
4. 嵌套Makefile
- 创建文件夹
include(存放头文件.h
),src(存放.c
文件),obj(存放.o
文件),bin(可执行文件) - 编写总控Makefile,先书写自定义文件变量或预定义变量
CC:=gcc
CFLAGS=-c
OBJ=sort
OBJS=sort.o
export CC CFLAGS OBJ OBJS
- 编写src中的Makefile,将所有的.c文件编译生成.o文件,并移动到obj目录中
ALL:$(OBJS)
mv $^ ../obj
sort.o:sort.c
$(CC) $(CFLAGS) $< -o $@
- 编写src中的Makefile,将所有的.c文件编译生成.o文件,并移动到obj目录中
ALL:$(OBJ)
mv $^ ../bin
$(OBJ):$(OBJS)
$(CC) $< -o $@
- 编写总控文件Makefile,先执行src中的Makefile文件(make -C src),再执行obj中的Makefile(make -C obj)
ALL:
make -C src
make -C obj
clean:
$(RM) obj/*.o bin/*
总结:Makefile其实提供了非常非常多的功能由于本人是个初学者,只把学到的知识分享了出来,还有很大的空间让我们去探索,要先把基础知识吃透再去延伸Makefile的其它知识。