从0开始写一个通用的Makefile文件

  1.      什么是Makefile文件 

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

  2. Makefile三要素
        目标 条件 命令  
     

    3.现在让我们来编写第一个Makefile文件

我的电脑里面有如下几个文件

                                                

其代码如下

//add.c
#include"cal.h"
int add(int a,int b)
{
    return a+b;
}
//sub.c
#include"cal.h"
int sub(int a,int b)
{
    return a-b;
}
//mul.c
#include"cal.h"
int mul(int a,int b)
{
    return a*b;
}
//div.c
#include"cal.h"
int div(int a,int b)
{
    return a/b;
}
//cal.h
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
//mcal.h
#include"cal.h"
#include"stdio.h"
int main()
{
  int a=0;
  int b=0;
  scanf("a=%d,b=%d",&a,&b);
  printf("\n%d+%d = %d\n",a,b,add(a,b));
  printf("%d-%d = %d\n",a,b,sub(a,b));
  printf("%d*%d = %d\n",a,b,mul(a,b));
  printf("%d/%d = %d\n",a,b,div(a,b));
}

如果没有Makefile文件我们要编译就需要这么些 gcc add.c sub.c mul.c div.c mcal.c -o app

我们可以让Makefile替我们做这件事 ,在我们的项目目录里touch Makefile 注意Makefile第一个字母要大写

#目标       依赖
all:add.c sub.c mul.c div.c maal.c
#命令                                                                        
    gcc add.c sub.c mul.c div.c mcal.c -o app

all是个伪目标,是所有目标的目标,其功能是编译所有的目标。all 是目标要顶格写,all后面跟条件(依赖)  gcc ****是命令

实际上我们gcc首先要生存.o的目标文件(中间文件)然后再链接成可执行程序 因此我们将Makefile改成这样

all:add.o sub.o mul.o div.o mcal.o
	gcc add.o sub.o mul.o div.o mcal.o -o app

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

sub.o:sub.c
	gcc -c sub.c

mul.o:mul.c
	gcc -c mul.c

div.o:div.c
	gcc -c div.c

mcal.o:mcal.c
	gcc -c mcal.c

然后在shell中敲入make我们再看目录中的文件 如下

目录中多了*.o文件,由于gcc *.o依赖于 .o文件 而.o文件又依赖于.c文件 Makefile会去分析并处理这些依赖,先去生成.o文件 然后再gcc .o文件。在上面的Makefile中我们发现add.o sub.o mul.o div.o mcal.o 这一行出现了两次,像在c中一样,我们也可以在Makefile中设置变量去代表这个值,并且我们发现

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

和后面的sub....等只是名字不同而已,就像c++中写模版函数一样,我们也可以在Makefile中写一个通用的目标因此我们可以将Makefile改写成如下

obj = add.o sub.o mul.o div.o mcal.o
app:$(obj)
	gcc $(obj) -o app

%.o:%.c
	gcc -c $< -o $@

我们将add.o sub.o mul.o div.o mcal.o赋值给obj,然后通过$(obj)去取出obj的值, %是一个通配符,在Makefile中$@表示目标,$^表示所有依赖所有 $<表示依赖中的第一个。因此之前的四个目标可以简写成一个目标我们保存然后make发现一样可以生成.o文件和app执行文件,并且目录下所有的.c文件都会生成.o文件,因此无关紧要的代码不要放在工作目录下,我们发现

obj = add.o sub.o mul.o div.o mcal.o这一行还是出现了具体的文件名称,要想实现一个通用的Makefile我们就不能出现具体的文件名,因此我们可以通过使用函数wildcard 该函数的作用是查找当前目录下所有的符合指定规则的文件 我们原本的目录下只有.c文件,我们可以这么写src = $(wildcard  *.c),定义一个变量来接收这些文件名,细心的你一定发前面我们需要的是.o文件,这里找到的是.c文件,因此这里我们需要用到Makefile的字符串替换函数pathsubstr来把带.c字符串名改成带.o字符串名 我们可以这么写obj=$(patsubst %.c,%.o ,$(src)) 这样obj就跟前面的obj = add.o sub.o mul.o div.o mcal.o一样了,因此改过后的Makefile文件如下

src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
target = app
$(target):$(obj)
	gcc $(obj) -o $(target)

%.o:%.c
	gcc -c $< -o $@

此时我们发现我们的Makefile跟目录下的文件没有一点关系了,基本可以用于所有的项目,还有最后一步 为Makefile添加相应的配置

#预处理器表示一般指定头文件所在文件
CPPFLAGS =
#编译时候的参数 一般是-g -wall等
CFLAGS =
#指定共享库位置
LDFLAGS=
#指定编译器是啥
CC= gcc
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
target = app
$(target):$(obj)
	$(CC) $^ $(LDFLAGS) -o $@

%.o:%.c
	$(CC) -c $< $(CFLAGS) $(CPPFLAGS)-o $@
#.PHONY
#make clean即使当前目录有clean文件,执行make clean时依然会执行clean目标
.PHONY:clean
clean:
# 前面的-表示错误依然继续运行加@表示执行时屏幕上不显示此语句
	@-rm -rf *.o
	@-rm -rf $(target)

重新运行make前可以通过make clean删除生成的中间文件和目标文件。至此一个简单的通用Makefile写完了,原创,如有错误之处还望指出

   要想更具体的学习Makefile可以下载我上传到文档https://download.csdn.net/download/woshichaoren1/10838702

猜你喜欢

转载自blog.csdn.net/woshichaoren1/article/details/84928902