makefile文件的编写

makefile文件

makefile的使用场景

makefile用于编译大量的.c文件 或者是分文件编写的(包含多个 .h 多个.c文件 和主文件 ) 将其转换为可执行文件 。 makefile的作用正是简化了上面的步骤,makefile的使用前提是掌握gcc 然后循序掌握其他内容

1 - 从简单的gcc 操作 到 转换为makefile

如我们要将 main.c 变为可执行文件 main

需要经历 gcc -E gcc -S gcc -C

当然对于单个.c文件转变为可执行文件 我们可以直接使用

gcc -C main.c -o main      

在makefile中

main : main.c
	gcc -c main.c -o main

main 是目标文件 ,main.c是依赖文件 下面必须用tab键 开头书写命令(若命令不存在的话则无需)

说明 : makefile中 目标文件一定要有 ,但依赖文件 和命令列表 可以没有

目标 :就是你要产生的文件,可以是 obj 文件

执行顺序

编写一个makefile 文件

binggo :test test2
	echo "hello all"
test:
	echo "hello test"
test2:
	echo "hello test2"

makefile 默认会以文件中的第一个目标为最终目标 也就是 这里的 binggo, binggo 目标有两个依赖,test 和test2 .同样test 和test2 也作为目标 ,但他们不存在依赖文件。

执行顺序: 先执行依赖 test ,再执行依赖 test2 ,在依赖满足后 执行目标文件

可以使用 make makefile -n 来看一下执行过程

echo "hello test"
echo "hello test2"
echo "hello all"

再看多个.c文件编写的情况

提供 add.c mul.c sub.c add.h mul.h sub.h test.c 要求 将他们变为可执行文件

其中的函数形式为:

/*add.c*/
#include"add.h"
int add (int x,int y)
{
return x+y;
}
/*mul.c*/
#include"mul.h"
int mul (int x,int y)
{
return x*y; 
}
/*sub.c*/
#include"sub.h"
int sub (int x,int y)
{
return x-y; 
}

/*test.c*/
#include "add.h"
#include "sub.h"
#include "mul.h"
#include<stdio.h>

int main(void)
{

int x=2;
int y=4;

printf("%d",add(x,y));
printf("%d",sub(x,y));
printf("%d",mul(x,y));

printf("hello");
return 0;
}
/*add.h*/
#ifndef __ADD_H__
#define __ADD_H__
int add (int x,int y);
#endif /*__ADD_H__*/

/*mul.h*/
#ifndef __MUL_H__
#define __MUL_H__
int mul (int x,int y);
#endif /*__MUL_H__*/

/*sub.h*/
#ifndef __SUB_H__
#define __SUB_H__
int sub (int x,int y);
#endif /*__SUB_H__*/

使用gcc 的方式:

gcc add.c sub.c mul.c test.c -o test

说明:由于这里头文件和 多个c文件在同一个 目录下,所以不需要使用 -I 指定头文件

使用 makefile的方式

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

此时 目标文件test依赖 test: add.c sub.c mul.c test.c 所有c文件

首先确保程序已经执行一次(产生test可执行文件),然后我们对 add.c做一下修改(比如 使用touch add.c 更新一下时间戳)

然后再执行一下 make -n 执行顺序如下

gcc add.c sub.c mul.c test.c -o test

可见他会把所有的 .c文件全部在执行一次。

解决办法

当存在多个 c文件时,我们需要借助 c 文件生成的 obj文件(.o文件)

修改makefile

test:add.o sub.o mul.o test.o
	gcc add.o sub.o mul.o test.o -o test


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

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

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


test.o:test.c
	gcc -c test.c -o test.o 
clean:
	rm *.o

当我们的 add.c被修改之后, 目标 add.o 就会重新被执行 ,重新被执行的命令也就只有被修改的那部分

同样的我们在已经执行过一次的前提下,touch add.c ,表示add.c 被更新

然后使用 make -n展示编译过程

gcc -c add.c -o add.o
gcc add.o sub.o mul.o test.o -o test

(可见:我们使用.o 文件的目的是为了:当存在多个 . c文件时 , 我们若针对特定几个 .c文件 修改 ,make只会重新编译我们修改过后的那几个.c文件 ,并不会全部编译 ,这样就能节省时间 ,后续会谈到)


变量的介绍

变量是为了减少复杂代码的复写(方便程序引用)

定义变量

变量名=变量值

引用变量

( 变 量 名 ) 或 者 (变量名) 或者 (){变量名}

makefile的改进

OBJS=add.o sub.o mul.o test.o		#test:add.o sub.o mul.o test.o注释掉
TARGET=test								#	gcc add.o sub.o mul.o test.o -o test

$(TARGET)=OBJS
	gcc $(OBJS) -o $(TARGET)

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

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

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


test.o:test.c
	gcc -c test.c -o test.o 
clean:
	rm -f $(OBJS)				#rm *.o 注释掉

除了这些我们自己所定义的变量名 ,系统提供了一些变量提供给用户赋值,

  1. CC = gcc #相当是gcc, 使用前 也要加 $(CC)

  2. CPPFLAGS # c预处理的选项 -I 引用头文件等

  3. CFLAGS # C编译器的选项 如-Wall -g -c 等

  4. LDFLAGS #链接器的选项 -L -I 等

    注明 : 这些只需要明白 他们只是是特定的名字 ,用来被一类的命令所赋值, 赋值前本身不作为任何原值

自动变量

  • $@ 表示规则中的目标
  • $< 表示规则中第一个依赖 如果将该变量应用在模式规则里,它可将依赖条件列表中的依赖依次取出,套用模式规则。
  • $^ 表示规则中所有的依赖

使用自动变量我们可以进一步简化makefile 代码

OBJS=add.o sub.o mul.o test.o		
TARGET=test							

$(TARGET)=OBJS
	gcc $^ -o $@

add.o:add.c
	gcc -c $^ -o $@

mul.o:mul.c
	gcc -c $^ -o $@

sub.o:sub.c
	gcc -c $^ -o $@


test.o:test.c
	gcc -c $^ -o $@
clean:
	rm -f $(OBJS)	$(TARGET)		

我们发现 gcc -c $^ -o $@ 重复多次

模式匹配 形式如下

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

表示.o文件依赖 .c文件 ,也就是将 .c文件转换成 .o文件

这里的% 是通配符号 ,与 * 不同 ,在同一次使用中

比如 存在 add.c sub.c mul.c div.c

我们使用 %.o :%.c 这里表示将 以.c 为后缀的文件转换为 .o文件 但他每次就只能实现

add.c 转换为 add.o sub.c 转换为 sub.o div.c 转换为 div.o mul.c 转换为 mul.o

也就是说 .o的前缀 和 .c 的前缀是绑定的关系。

通配符 %的意思是

  1. 我要找test1.o的构造规则,看看Makefile中那个规则符合。
  2. 然后找到了%.o:%.c,
  3. 来套一下来套一下:
  4. %.o 和我要找的 test1.o 匹配
  5. 套上了,得到%=test1。
  6. 所以在后面的%.c就表示test1.c了。
  7. OK进行构造

而通配符*的意思是:

我不知道目标的名字,系统该目录下中所有后缀为.c的文件都是我要找的。
然后遍历目录的文件,看是否匹配。找出所有匹配的项目

针对上面的解释 修改一下makefile文件

OBJS=add.o sub.o mul.o test.o		
TARGET=test							

$(TARGET)=OBJS
	gcc $^ -o $@

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

clean:
	rm -f $(OBJS)	$(TARGET)		

说明 这里的 %.o %.c 依次会被 test.o sub.o add.o test.o 匹配到

当匹配到test.o 时

% =test
test.o:test.c
	gcc -c test.c -o test.o

当匹配到add.o 时

% =add
add.o:add.c
	gcc -c add.c -o add.o

如此下去,通配符是在带着目的(如“寻找test1.o”)的时候才会把他要寻找的目标套用通配符%中。

静态模式匹配 是为了指定这个目标采取哪种模式匹配(当存在多个模式匹配规则时)

<target>%.o%.c
	gcc -c $< -o $A

比如: 新增add.s sub.s mul.s test.s

此时 .o文件的转换就不止是从 .c文件到 ,o 文件了 ,也可以是从 .s 文件到 .o文件

由于存在两种模式匹配规则,所以防止二义 加上<目标>

OBJS=add.o sub.o mul.o test.o		
TARGET=test							

$(TARGET)=OBJS
	gcc $^ -o $@

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

#%.o:%s     #为使用静态匹配之前的
<OBJS>%.o:%.s  #加上目标之后
gcc -S $< -o $@

clean:
	rm -f $(OBJS)	$(TARGET)		

两个函数与伪目标

观察上面改进的makefile 我们发现 我们仍然需要 写出所有的 .o文件

make 提供了 两个函数 $(wildcard ./*.c) 和 ( p a t s u b s t , (patsubst,%.c,%.o, (patsubst,(SRC))

$(wildcard ./*.c)

是获取指定目录下所有的以 c结尾的文件 (当然这里的路径可以自己改变)

( p a t s u b s t , (patsubst,%.c,%.o, (patsubst,(SRC)) 匹配替换

是将 SRC中所有出现 .c的文件替换为 .o

对此 将makefile 进一步修改

SRC=$(wildcard ./*.c)
OBJS= $(patsubst,%.c,%.o,$(SRC))
TARGET=test							

$(TARGET)=OBJS
	gcc $^ -o $@

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

#%.o:%s     #为使用静态匹配之前的
<OBJS>%.o:%.s  #加上目标之后
gcc -S $< -o $@

clean:
	rm -f $(OBJS)	$(TARGET)		

伪目标

我们的makefile通常含有 目标 clean;这个目标没有依赖项

在 执行完成make 之后使用 ,用于清除中间文件 ( .o .test 最终文件 等)

倘若makefile 同级目录中存在同名clean文件则不会执行,

解决方案

伪目标声明 .PHONY:clean

声明目标为伪目标后,makefile将不会判断该目标是否存在,是否为最新的。

SRC=$(wildcard ./*.c)
OBJS= $(patsubst,%.c,%.o,$(SRC))
TARGET=test							

$(TARGET)=OBJS
	gcc $^ -o $@

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

#%.o:%s     #为使用静态匹配之前的
<OBJS>%.o:%.s  #加上目标之后
gcc -S $< -o $@
.PHONY:clean

clean:
	rm -f $(OBJS)	$(TARGET)		

clean 命令中的特殊符号 :

  • ‘’ - ‘’ 此条命令出错,make 也会执行后续的命令
  • “@ ” 不显示命令本身,只显示结果
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁金金

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值