makefile入门实战

本篇博客主要试介绍基础的Makefile使用,常用的变量和函数。看完后能理解makefile书写原理,自己写一些简单的makefile。


本专栏知识点是通过<零声教育>的音视频流媒体高级开发课程进行系统学习,梳理总结后写下文章,对音视频相关内容感兴趣的读者,可以点击观看课程网址:零声教育



⼀个规则是由⽬标(targets)、先决条件(prerequisites)以及命令(commands)所组成。
规则的功能就是指明 make 什么时候以及如何来为我们重新创建⽬标。
规则的语法:

	targets : prerequisites
		command

当没有指明具体的⽬标是什么时,那么 make 以 Makefile ⽂件中定义的第⼀个⽬标作为这次运⾏的⽬标。
对于make ⼯具,⼀个⽂件是否改动不是看⽂件⼤⼩,⽽是其时间戳。
如果先决条件中相关的⽂件的时间戳⼤于⽬标的时间戳,即先决条件中的⽂件⽐⽬标更新,则知道有变化,那么需要运⾏规则当中的命令重新构建⽬标。

在现实中也难免存在所定义的⽬标与所存在的⽂件是同名的,Makefile 利用假⽬标来处理。
采用==.PHONY== 关键字来定义。

一、变量

1.1 自动变量

$@⽤于表示⼀个规则中的⽬标。当我们的⼀个规则中有多个⽬标时, $@所指的是其中任何造成命令被运⾏的⽬标。
$^则表示的是规则中的所有先择条件。
$<表示的是规则中的第⼀个先决条件。

Makefile
.PHONY: clean
CC = gcc
RM = rm
EXE = simple
OBJS = main.o foo.o
$(EXE): $(OBJS)
$(CC) -o $@ $^
main.o: main.c
$(CC) -o $@ -c $^
foo.o: foo.c
$(CC) -o $@ -c $^
clean:
$(RM) $(EXE) $(OBJS)

1.2 特殊变量

$(MAKE) :make
$(MAKECMDGOALS):⽤户输⼊的⽬标,当我们只运⾏ make 命令时,第⼀个⽬标将成为缺省⽬标,即 all ⽬标,但 MAKECMDGOALS 仍然是空,⽽不是all

1.3 变量类别

递归扩展变量:只⽤⼀个“=”符号定义
简单扩展变量:⽤“:=”操作符定义,make 只对其进⾏⼀次扫描和替换
条件赋值变量:条件赋值符“?=”定义,当变量以前没有定义时,就定义它并且将左边的值赋值给它,如果已经定义了那么就不再改变其值

斌值的同时完成后缀替换操作:

Makefile
.PHONY: all
foo = a.o b.o c.o
bar := $(foo:.o=.c)
all:
@echo "bar = $(bar)"
执⾏
$make
bar = a.c b.c c.c

1.4 函数

addprefix 函数:
⽤来在给字符串中的每个⼦串前加上⼀个前缀,其形式是:

$(addprefix prefix, names...)

示例:

Makefile
.PHONY: all
without_dir = foo.c bar.c main.o
with_dir := $(addprefix objs/, $(without_dir))
all:
@echo $(with_dir)

执⾏
$make
objs/foo.c objs/bar.c objs/main.o

filter 函数:
⽤于从⼀个字符串中,根据模式得到满⾜模式的字符串,其形式是:

$(filter pattern..., text)
Makefile
.PHONY: all
sources = foo.c bar.c baz.s ugh.h
sources := $(filter %.c %.s, $(sources))
all:
@echo $(sources)

执⾏
$make
foo.c bar.c baz.s

filter-out 函数:
⽤于从⼀个字符串中根据模式滤除⼀部分字符串,其形式是:

$(filter-out pattern..., text)
result = $(filter-out main%.o, main1.o foo.o main2.o bar.o)

patsubst 函数:
是⽤来进⾏字符串替换的,其形式是:

$(patsubst pattern, replacement, text)
objects := $(patsubst %.c, %.o, $(mixed))

strip 函数:
⽤于去除变量中的多余的空格,其形式是:

$(strip string)
stripped := $(strip $(original))

wildcard (通配符)函数:
用于得到我们所需的⽂件,其形式是:

$(wildcard pattern)
SRCS = $(wildcard *.c)

二、复杂项目Makefile

2.1 创建目录

Makefile
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
DIRS = objs exes
all: $(DIRS)
$(DIRS):
	$(MKDIR) $@
clean:
	$(RM) $(RMFLAGS) $(DIRS)

make 之后,会生成 exes 和objs两个文件
make clean 之后,会删除

2.2 增加头文件

complicated 项⽬的Makefile中加⼊对于源程序进⾏编译的部分。
假设makefile当前目录已有以下3个文件:foo.hfoo.cmain.c。现在需要利用这些文件编译出可执行文件complicated

foo.h
#ifndef __FOO_H
#define __FOO_H
void foo ();
#endif

foo.c
#include <stdio.h>
#include “foo.h”
void foo ()
{
	printf (“This is foo ()!\n”);
} 

main.c
#include “foo.h”
int main ()
{
	foo ();
	return 0;
}

Makefile文件如下:

Makefile
.PHONY: all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -fr
CC = gcc
EXE = complicated
DIRS = objs exes
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
all: $(DIRS) $(EXE)
$(DIRS):
	$(MKDIR) $@
$(EXE): $(OBJS)
	$(CC) -o $@ $^
%.o: %.c
	$(CC) -o $@ -c $^
clean:
	$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)

先利用.c文件编译为.o文件,之后生成complicated。

执⾏
$make
mkdir objs
mkdir exes
cc -o foo.o -c foo.c
cc -o main.o -c main.c
cc -o complicated foo.o main.o
$ls
Makefile complicated exes foo.c foo.h foo.o main.c main.o objs
$./complicated
This is foo ()!
$make clean
rm -fr objs exes complicated foo.o main.o
$ls
Makefile foo.c foo.h main.c

2.3 将文件放到目录里

利用addprefix()函数,将⽬标⽂件或是可执⾏程序分别放⼊所创建的 objs 和 exes ⽬录中。

Makefile
DIR_OBJS = objs
DIR_EXES = exes
DIRS = $(DIR_OBJS) $(DIR_EXES)

OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))

利用 addprefix 函数的运⽤为每⼀个⽬标⽂件加上“objs/”前缀外

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

君莫笑lucky

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

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

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

打赏作者

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

抵扣说明:

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

余额充值