Makefile概览

在嵌入式开发领域中,大量的开发环境是通过使用 make 工具来构建的。而要使用 make 工具,就离不开编写 Makefile。
make 一般主要被用来管理一个软件程序项目 (用来完成大型软件的自动编译),但是它不仅仅可以用来管理软件程序,还可以做很多其他的事情,比如文件同步等。
makefile 是被 make 使用的“描述”文件,它描述要被 make 所管理的项目中的文件间的关系(比如对于一个 C 程序项目来说,.h 文件和 .c 文件之间的关系, .c 和 .o 之间的关系等),和如何维护这个项目的状态(比如对于一个程序项目来说,就有编译可执行文件,产生文档,清除所有除源代码文件之外的文件等)。它相当于 make 的指挥官。

3个概念: 规则 = 目标 + 依赖关系 + 命令

1、一条简单规则

all:
	echo "Hello World"
all -- 目标  all 不依赖其它目标  echo ... 命令  整个就是一个规则
①、Windows 下如果使用 mingw,则命令行输入 mingw32-make
②、命令所在行必须以 TAB 开头(文本编辑器中不要设置为空格代替字符)
③、若一个 Makefile 有多个目标,则可以在运行 make 命令时加以选择;当没有指定具体目标时,

make 将以文件中的第一个目标作为这次运行的目标,也就是默认目标。

2、两条简单规则

all: test
	@echo "Hello World"
test:
	@echo "just for test"
all, test -- 两个目标  all 依赖于 test(test 是 all 的先决条件)
①、命令若以 @ 开头,表示这条命令的内容不会在命令窗口打印出来
②、当 make 某个目标时,make 会在构建这个目标之前先构建它的先决目标
当 make all 时,会先打印 "just for test",再打印 "Hello World"
③、采用 Makefile 进行代码编译时,Makefile中 所存在的先决条件大多是具体的程序文件。

3、简单项目编译规则

--foo.c--
#include <stdio.h>

void foo()
{
	printf("This is foo()!\n");
}
--main.c--
extern void foo();

int main ()
{
	foo();
	return 0;
}
--Makefile--
all: main.o foo.o
	gcc -o simple main.o foo.o
main.o: main.c
	gcc -o main.o -c main.c
foo.o: foo.c
	gcc -o foo.o -c foo.c
clean:
	rm simple.exe main.o foo.o
①、clean 目标:删除 make 生成的文件,还原环境
②、all 中生成的是 simple,而 rm 的却是simple.exe。mingw 环境 gcc 生成可执行文件时会遵照 Windows 的规则,增加一个 .exe 后缀。
③、make 之后,如果再次运行 make,则会打印“gcc -o simple main.o foo.o”
  解释:make 在分析一个规则以创建目标,如果发现先决条件中文件的时间戳大于目标的时间戳,即先决条件文件比目标更新,则会重新执行命令,否则跳过;
  在这里,all 是第一条规则中的目标,而 all 文件在编译时不会生成,所以这条命令还是会执行,如果将 all 改成simple.exe(simple 也会再次执行),则不会再次执行。

4、假目标

假设现目录中存在一个 clean 文件(可以 touch 命令创建),如果此时再运行“make clean”,将会发现make总是提示 clean文件是最新的,而不会去对项目执行清楚操作。这是因为,make 会将 clean 当作文件来处理,由于当前目录下找到了这个文件,加上 clean 目标没有任何先决条件,所以 make 构建 clean 时就会 clean 文件是最新的,从而跳过命令的执行。这种情况就需要使用假目标了。更新后的 Makefile 如下
--Makefile--
.PHONY: clean
simple.exe: main.o foo.o
	gcc -o simple main.o foo.o
main.o: main.c
	gcc -o main.o -c main.c
foo.o: foo.c
	gcc -o foo.o -c foo.c
clean:
	rm -fr simple.exe main.o foo.o
现在 make clean 就会按预期执行清除工作了。
①、假目标使用 .PHONY 关键字定义
②、当采用 .PHONY 声明一个目标时,make 不会将其当做一个文件来处理,每次构建假目标时它所在的规则中的命令一定会被执行。

5、变量

通过使用变量可以让 Makefile 更具可维护性,变量的作用就相当于全局字符串。
更改 Makefile 文件如下:
--Makefile--
.PHONY: clean

MAKE = mingw32-make
CC = gcc
RM = rm

EXE = simple.exe
OBJS = main.o foo.o

$(EXE): $(OBJS)
	$(CC) -o $(EXE) $(OBJS)
main.o: main.c
	$(CC) -o main.o -c main.c
foo.o: foo.c
	$(CC) -o foo.o -c foo.c
clean:
	$(RM) -fr $(EXE) $(OBJS)
①、 特殊变量。Makefile中有两个特殊变量会经常用到: MAKE MAKECMDGOALS,MAKE 变量表示当前处理 Makefile 的命令名(当需要在当前 Makefile 中运行另一个 Makefile 时也会用到它),之后在命令行中只需输入 make,Makefile 会自动将其解释为 mingw32-make;MAKECMDGOALS 表示用户输入 make之 后所带的目标。
②、变量名右值可以为空,引用变量需要采用 $(变量名) 或者 ${变量名} ;
③、 自动变量,根据规则上下文自动获取
$*  不包含扩展名的目标文件名称
$+  所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
$<  第一个依赖文件的名称
$?  所有时间戳比目标文件晚的依赖文件,并以空格分开
$@  目标文件的完整名称
$^  所有不重复的依赖文件,以空格分开
借助自动变量,可以对 Makefile 进行精简(如果项目很大,就不用为每个目标文件写一个不同的规则了)
--Makefile--
.PHONY: clean

MAKE = mingw32-make
CC = gcc
RM = rm

EXE = simple.exe
OBJS = main.o foo.o

$(EXE): $(OBJS)
	$(CC) -o $@ $^
%.o : %.c
	$(CC) -o $@ -c $^
clean:
	$(RM) -fr $(EXE) $(OBJS)
④、变量赋值
递归赋值,采用 = 进行赋值,右侧将会递归展开(由此可能带来死循环)
简单赋值,采用 := 进行赋值,单次展开
条件赋值,采用 ?= 进行赋值,当变量没有定义时定义它
追加赋值,采用 += 进行赋值,相当于字符串的连接
⑤、命令的值可以来自 Makefile 文件、用户实际运行的 make 命令或者 Shell 环境
⑥、比较高级的变量引用:
foo = a.c b.c c.c
bar := $(foo:.c=.o)
这样转化以后,bar 就是 a.o b.o c.o
⑦、在变量名前加 override 可以保护变量值不被更改

6、函数

①、$( abspath _name) 将 _name 表示的路径转化成绝对路径
ROOT := $(abspath /usr/../lib) # ROOT := /lib
②、$( addprefix _prefix, _names) 将名字列表 _names中 的每个名字添加前缀 _prefix
without_dir = foo.c bar.c main.o 
with_dir := $(addprefix objs/, $(without_dir))
③、$( addsuffix _suffix, _names) 添加后缀
④、$( filter _pattern, _text) 从名字列表 _text 根据模式 _pattern 进行过滤得到剩余部分
sources = foo.c bar.c baz.s ugh.h
sources := $(filter %.c %.s, $(sources))
#sources = foo.c bar.c baz.s
⑤、$( filter-out _pattern, _text) 从名字列表 _text 根据模式 _pattern 进行过滤得到过滤部分
⑥、$( eval _text)
将  _text 的内容作为 makefile 的一部分再次展开
⑦、$( notdir _names) 从路径 _names 中抽取出文件名
file_name := $(notdir code/foo/src/foo.c code/bar/src/bar.c)
#file_name := foo.c bar.c
⑧、$( patsubst _pattern, _replacement, _text) 将名字列表 _text 中符合 _pattern 的名字替换为 _replacement,返回替换后的名字列表
mixed = foo.c bar.c main.o
objs := $(patsubst %.c, %.o, $(mixed))
#objs := foo.o bar.o main.o
⑨、$( realpath _names) 获取 _names 所对应的真是路径名
ROOT := $(realpath ./..)
#假设当前路径为 /home/xx ,ROOT := /home
⑩、$( strip _string) 清楚名字列表中的多余空格
original = foo.c     bar.c
stripped := $(strip $(original))
#stripped := foo.c bar.c 
、$( wildcard _pattern),获取当前工作目录中满足 _pattern 模式的文件或者目录名列表
SRCS = $(wildcard *.c)
#假设当前目录有文件a.c b.c c.c main.o,SRCS := a.c b.c c.c
借助 patsubst 和 wildcard 函数,可以更改前文的 Makefile 如下
--Makefile--
.PHONY: clean

MAKE = mingw32-make
CC = gcc
RM = rm

EXE = simple.exe
SRCS = $(wildcard *.c)
OBJS = $(wildcard %.c, %.o, $(SRCS))

$(EXE): $(OBJS)
	$(CC) -o $@ $^
%.o : %.c
	$(CC) -o $@ -c $^
clean:
	$(RM) -fr $(EXE) $(OBJS)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值