【Makefile】Makefile入门

用途

  1. 项目代码编译管理
  2. 节省编译项目的时间
  3. 一次编写终身受益

命名规则

  1. Makefile
  2. makefile

基本规则

规则中的三要素:目标、依赖、命令。

目标 --> 要生成的目标文件
依赖 --> 生成目标文件需要的一些文件
命令 --> 借助依赖文件生成目标文件的手段

格式

目标:依赖条件
	命令

Makefile会把规则中的第一个目标作为终极目标。

工作原理

若想生成目标,检查规则中的依赖条件是否存在,如果不存在,寻找是否有规则用来生成该依赖文件

检查规则中的目标是否需要更新,必须检查它的所有依赖,依赖中有任意一个被更新,则目标必须更新。如果依赖文件比目标文件时间晚,则需要更新。

执行

make --> 通过makefile生成目标文件。

  1. 直接 make (使用makefile文件)
  2. make -f mm (指定一个名字不为makefile的文件)

make clean --> 清除编译生成的中间.o文件和最终目标文件
如果当前目录下有同名clean文件,则不能执行clean对应的命令。因为涉及到了比较文件新旧决定是否重编译。解决方案 --> 伪目标声明:.PHONY:clean

特殊符号
- :表示此条命令出错,make也会继续执行后续的命令。如:“-rm a.o b.o”

变量

普通变量

变量定义及赋值:obj = a.o b.o c.o
变量取值:foo = $(obj)

由 Makefile 维护的一些变量。通常格式都是大写。有些有默认值,有些没有。如

CC:默认值 cc(即gcc)
CPPFLAGS : 预处理器需要的选项 如:-I
CFLAGS:编译的时候使用的参数 –Wall –g -c
LDFLAGS :链接库使用的选项 –L -l

用户可以修改这些Makefile维护的变量的默认值,如

CC = gcc
自动变量

变量
$@ --> 规则中的目标
$< --> 规则中的第一个依赖条件
$^ --> 规则中的所有依赖条件

模式规则
在规则的目标定义中使用 %
在规则的依赖条件中使用 %
示例:

%.o:%.c
	$(CC) –c  $< -o $@

// 解析
%.o			匹配该makefile文件上面的.o
%.c			匹配该makefile文件上面的.c
$(CC)		表示gcc
$<  		表示依次取出依赖条件
$@  		表示依次取出目标值

函数

makefile中所有的函数必须都有返回值

wildcard

查找指定目录下指定类型的文件,一个参数

// 找到./src 目录下所有后缀为.c的文件,赋给变量src
src = $(wildcard ./src/*.c)
patsubst

匹配替换,从src中找到所有.c 结尾的文件,并将其替换为.o

// 把src变量中所有后缀为.c的文件替换成.o
obj = $(patsubst %.c ,%.o ,$(src))

// 指定.o 文件存放的路径 ./obj/%.o
ob = $(patsubst ./src/%.c, ./obj/%.o, $(src))

入门示例

示例一

环境

# ls
head.h main.c add.c sub.c mul.c makefile

makefile

#目标:依赖
app:main.c add.c sub.c mul.c
	gcc main.c add.c sub.c mul.c -o app #gcc命令

该makefile的缺点是,每次生成目标app时,需要对main.c add.c sub.c mul.c四个文件进行编译。

示例二

环境

# ls
head.h main.c add.c sub.c mul.c makefile

makefile

#目标:依赖
#第一个目标作为终极目标
app:main.o add.o sub.o mul.o
	gcc main.o add.o sub.o mul.o -o app #gcc命令

#目标:依赖
#非终极目标
main.o:main.c
	gcc -c main.c  #gcc命令

#目标:依赖
#非终极目标
add.o:add.c
	gcc -c add.c  #gcc命令

#目标:依赖
#非终极目标
mul.o:mul.c
	gcc -c mul.c  #gcc命令

#目标:依赖
#非终极目标
sub.o:sub.c
	gcc -c sub.c #gcc命令

该makefile的相比示例一要好,因为每次生成目标app时,仅需要对main.o add.o sub.o mul.o四个文件进行链接即可。如果当前目录下已有main.o add.o sub.o mul.o并且是最新的,就不需要重新对main.c add.c sub.c mul.c四个文件进行编译了。

如果不是最新,仅需对不是最新的编译,然后链接即可。例如,假设add.o不是最新的(add.c的日期比add.o的日期新),那么该makefile会对add.c编译成add.o,然后和不需要重新编译的main.o sub.o mul.o链接生成app。节省了编译不需要更新的文件的时间。

示例三

环境

# ls
head.h main.c add.c sub.c mul.c makefile

makefile

#我们自定义的变量
obj=main.o add.o sub.o mul.o
target=app
#makefile维护的默认变量也可以修改
CC=gcc
CPPFLAGS=-I

#目标:依赖
$(target):$(obj)
	$(CC) $(obj) -o $(target) #gcc命令

#%模式匹配
%.o:%c
	$(CC) -c $< -o $@ #gcc命令

该makefile和示例二相比,用了变量、默认变量、自动变量、模式匹配等。节省了代码量,节省了重复的地方。

示例四

环境

//查看当前目录树状图
# tree
.
├── include
│   └── head.h
├── lib
│   ├── libMyCalc.a
│   └── libMyCalc.so
├── makefile
└── src
    ├── add.c
    ├── div.c
    ├── main.c
    ├── mul.c
    └── sub.c

makefile

#自定义变量
target=app
INCLUDES = -I./include #头文件路径 
LIBS = -MyCalc #库文件名字 
LIB_PATH = -L./lib #库目录

#修改默认变量
CC=gcc
CPPFLAGS=-I

# 找到./src 目录下所有后缀为.c的文件,赋给变量src
src=$(wildcard ./src/*.c)

# 把src变量中所有后缀为.c的文件替换成.o 并且指定.o 文件存放的路径 ./src/%.o
obj=$(patsubst ./src/%.c, ./src/%.o , $(src))

#$(info $(src) ) 打印变量
#$(info $(obj) ) 打印变量

#目标:依赖
$(target):$(obj)
	$(CC) $(obj) -o $(target) $(INCLUDES) #gcc命令

#目标:依赖 (%代表模式匹配)
%.o:%.c
	$(CC) -c $< -o $@ $(INCLUDES) #gcc命令

#目标:依赖(空) 
.PHONY:clean #声明为伪目标 解决如下场景: 如果当前目录下有同名clean文件,则不能执行clean对应的命令。因为涉及到了比较文件新旧决定是否重编译。
clean:
	rm $(obj) $(target)	#gcc命令

#目标:依赖(空)
.PHONY:hello #声明为伪目标 解决如下场景: 如果当前目录下有同名hello文件,则不能执行hello对应的命令。因为涉及到了比较文件新旧决定是否重编译。
hello:
	-mkdir ./bb #命令前面加"-"的意义是: 如果该命令执行失败,不会报错终止,而是继续下面的命令执行
	echo "hello, makefile"	#打印字符串命令	

执行效果:

// 执行makefile中的终极目标
# make
gcc -c src/mul.c -o src/mul.o -I./include  #gcc命令
gcc -c src/main.c -o src/main.o -I./include  #gcc命令
gcc -c src/add.c -o src/add.o -I./include  #gcc命令
gcc -c src/div.c -o src/div.o -I./include  #gcc命令
gcc -c src/sub.c -o src/sub.o -I./include  #gcc命令
gcc  ./src/mul.o   ./src/main.o   ./src/add.o   ./src/div.o   ./src/sub.o  -o app -I./include  #gcc命令

//查看当前目录树状图
# tree
.
├── app
├── include
│   └── head.h
├── lib
│   ├── libMyCalc.a
│   └── libMyCalc.so
├── makefile
└── src
    ├── add.c
    ├── add.o
    ├── div.c
    ├── div.o
    ├── main.c
    ├── main.o
    ├── mul.c
    ├── mul.o
    ├── sub.c
    └── sub.o
// 执行makefile中的clean伪目标
# make clean
rm  ./src/mul.o   ./src/main.o   ./src/add.o   ./src/div.o   ./src/sub.o  app	#gcc命令

//查看当前目录树状图
# tree
.
├── include
│   └── head.h
├── lib
│   ├── libMyCalc.a
│   └── libMyCalc.so
├── makefile
└── src
    ├── add.c
    ├── div.c
    ├── main.c
    ├── mul.c
    └── sub.c
// 执行makefile中的hello伪目标
# make hello
mkdir ./bb #命令前面加"-"的意义是: 如果该命令执行失败,不会报错终止,而是继续下面的命令执行
echo "hello, makefile"	#打印字符串命令	
hello, makefile
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值