文章目录
Linux-开发与管理 P4 Makefile基础
简介
Makefile是一个工具程序,它是一种转化文件形式的工具,转换的目标称为target
而对于Makefile另一个重要的内容就是目标间的依赖关系
编译与链接
不过在讲Makefile之前,要先来回顾一下GCC编译的内容,对于GCC中讲解的5个步骤,这里可以将其简单的看成两个步骤
第一个就是将.c文件编译(compile)成.o文件
然后是通过链接各个.o文件链接成可执行文件或者.out文件
编译
进行编译时,会判断语法是否正确,函数与变量的声明是否正确,还要告诉编译器头文件所在的位置;判断所有的编译的结果都正确时,编译器就会编译出中间目标文件.o文件
链接
链接时,链接所有的.o文件,链接里面的函数和全局变量,然后通过链接它们生成可执行文件
Makefile介绍
什么是Makefile呢?
Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为Makefile就像一个shell脚本一样,其中也可以自行操作系统的命令
Makefile工作流程
这里通过一个栗子来看看Makefile的简单工作流程
首先创建一个Makefile文件(这里注意文件名必须是Makefile,M必须大写)
然后进入到Makefile里面进行编程(记住echo前必须使用Tab键)
main:
echo "Hello World!"
使用make来查看效果,这里显示了代码段和执行结果
然后这里做一点扩展
main:
@echo "Hello World!"
cage:
@echo "Hello Cage!"
查看效果
这里使用了@之后,指令就不会在make的时候出现,然后cage目标只有在指定的时候才会显示结果,所以在执行make指令时,会默认执行第一个目标,那如何也执行cage目标呢?
这里做进一步的改进
main:cage
@echo "Hello World!"
cage:
@echo "Hello Cage!"
查看效果
这样就是一个简单的Makefile的基本结构,下面会详细讲解,这里cage写在main:后面,表明了cage与main之间的依赖关系
基本规则
基本规则
Makefile编辑的基本规则
target:prerequisites
command
target:目标文件,可以是.o文件,也可以是执行文件,还可以是标签
prerequistes:生成目标文件所需要的文件或目标
command:是目标所执行的命令
编译单个文件
首先编写一个.c文件的栗子,然后对其进行Makefile的方式进行编译
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("Hello Cage!\n");
return 0;
}
然后编写Makefile
main:main.o
gcc main.o -o main
main.0:
gcc -c main.c -o mian.o
clean:
rm *.o
查看效果
这里通过clean目标可以对.o文件进行清理,也看到了程序的执行结果
对多个文件编译
好的,对于一个文件进行编译后,发现并没有比直接进行gcc要简单多少,但是当我增加编译的文件数量增加时,就会发现Makefile的优点了
同样,这里编写一个多文件结构
all.h
#ifndef __ALL_H__
#define __ALL_H__
#include <stdio.h>
int my_add(int a,int b);
int my_sub(int a,int b);
#endif
myadd.c
#include <stdio.h>
#include "all.h"
int my_add(int a,int b){
int s;
s = a + b;
return s;
}
mysub.c
#include <stdio.h>
#include "all.h"
int my_sub(int a,int b){
int s;
s = a - b;
return s;
}
main.c
#include <stdio.h>
#include "all.h"
int main(int argc, const char *argv[])
{
int x = 100,y = 50;
int s1,s2;
s1 = my_add(x,y);
s2 = my_sub(x,y);
printf("x+y=%d\nx-y=%d\n",s1,s2);
return 0;
}
Makefile
main:main.o myadd.o mysub.o
gcc -o main main.o myadd.o mysub.o
main.o:main.c all.h
gcc -c main.c
myadd.o:myadd.c all.h
gcc -c myadd.c
mysub.o:mysub.c all.h
gcc -c mysub.c
clean:
rm *.o
然后就可以开始进行测试了
Makefile工作原理
以上面的栗子来看看Makefile到底是怎么工作的
1.当输入make的时候,会在当前目录下寻找名字叫做Makefile的文件
2.找到Makefile文件之后,找到文件里的第一个目标,也就是mian目标
3.然后寻找第一个目标对象的依赖的目标或者内容,也就是mian.o、myadd.o、mysub.o
4.分别找到对应mian.o、myadd.o、mysub.o,并根据依赖文件进行后面的指令,生成对应的目标文件,然后传回第一个目标进行最最的指令,完成Makefile工作
5.然后就生成了main可执行文件,然后通过make clean来清理.o中间文件
变量
为了方便使用,Makefile中也有变量,可以在Makefile中通过使用变量来使得它更简洁、更具可维护性
自动变量
对于很多目标和文件会在Makefile中多次出现,所以可以使自定义变量
变量 | 功能 |
---|---|
$@ | 用于表示一个规则中的目标;当一个规则中有多个目标时,则指的是其中任何造成命令被运行的目标 |
$^ | 表示的是规则中的所有选择条件 |
$< | 表示的是规则中的第一个先决条件 |
包括这些还能进行自行定义变量
CC = gcc
通过
$(CC)
来调用
这里对上面的栗子进行简化和修改
CC = gcc
RM = rm
OBJ = main
OBJS = main.o myadd.o mysub.o
$(OBJ):$(OBJS)
$(CC) -o $@ $^
main.o:main.c all.h
$(CC) -c $^
myadd.o:myadd.c all.h
$(CC) -c $^
mysub.o:mysub.c all.h
$(CC) -c $^
clean:
$(RM) $(OBJS)
重新来测试程序运行的效果
预定义变量
Makefile预定义变量包含了常见编译器、汇编器的名称及其编译选项
预定义变量表
命令格式 | 功能 |
---|---|
AR | 库文件维护程序的名称,默认值为ar |
AS | 汇编程序的名称,默认值为as |
CC | C汇编器的名称,默认值为cc |
CPP | C预编译器的名称,默认值为$(CC)-E |
CXX | C++编译器的名称,默认值为g++ |
FC | FORTARAN编译器的名称,默认值为f77 |
RM | 文件删除程序的名称,默认值为rm -f |
ARFLAGS | 库文件维护程序的选项,无默认值 |
ASFLAGS | 汇编程序的选项,无默认值 |
CFLAGS | C编译器的选项,无默认值 |
CPPFLAGS | C预编译的选项,无默认值 |
CXXFLAGS | C++编译器的选项 |
FFLAGS | Fortran编译器的选项,无默认值 |
自动推导和隐含规则
这里将会在Makefile进阶里做进一步讲解
结构与工作方式
这里将会在Makefile进阶里做进一步讲解