1. makefile
- makefile文件是用来管理项目工程文件,通过执行
make
命令,make
就会解析并执行makefile文件 - Makefile命名:makefile或者Makefile
1.1 makefile基本规则
目标:依赖
命令
基本规则三要素:
- 目标:要生成的目标文件
- 依赖:目标文件由哪些文件生成
- 命令:通过执行该命令由依赖文件生成目标
例子:
当前目录下有
main.c fun1.c fun2.c sum.c
根据这个基本规则编写一个简单的makefile文件,生成可执行文件main
vi makefile
**version1
main: main.c fun1.c fun2.c sum.c
gcc -o main main.c fun1.c fun2.c sum.c
** 如果此时修改了main.c,比如加上一个空格,使用make之后,其他的c文件也会全部重新编译
** 生成目标--检查-->依赖条件:存在(如果目标的时间 > 依赖的时间 不更新 否则说明修改了需要更新)-->通过命令生成目标
不存在-->寻找新规则用来生成依赖条件
**version2
main: main.o fun1.o fun2.o sum.o
gcc -o main main.o fun1.o fun2.o sum.o
main.o: main.c
gcc -c main.c -I./
fun1.o: fun1.c
gcc -c fun1.c
fun2.o: fun2.c
gcc -c fun2.c
sum.o: sum.c
gcc -c sum.o
**如果此时修改了main.c 对于目标为fun1.o fun2.o sum.o的编译就不会执行了
**弊端是如果目录中有几十个.c,就很痛苦
1.2 makefile中的变量
在makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使makefile易于维护,修改起来变得简单。
三种变量:
-
普通变量
-
变量定义直接用
=
-
使用变量值用
$(变量名)
foo = abc //定义变量并赋值 bar = $(foo) // 使用变量
定义了两个变量
foo bar
,其中bar
的值是foo
变量值的引用
-
-
自带变量
除了用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值:
CC=gcc #arm-linux-gcc 指定编译器 CPPFALGS: C预处理器的选线 -I CFLAGS: C编译器的选项 -Wall -g -c LDFLAGS: 链接器的选项 -L -l
-
自动变量==(只能在规则中的命令使用)==
-
$@
:表示规则中的目标 -
$<
:表示规则中的第一个条件main: main.c fun1.c fun2.c sum.c
这里main.c
就是第一个条件 -
$^
:表示规则中的所有条件,组成一个列表,以空格隔开,如果者个列表中有重复的项,则消除重复项
-
例子:
vim makefile
## version3
target = main #给目标起名字
objects = main.o fun1.o fun2.o sum.o
CC = gcc
CPPFALGS= -I./
$(target): $(objects)
$(CC) -o $@ $^
main.o: main.c
$(CC) - c $< $(CPPFLAGS)
fun1.o: fun1.c
$(CC) -c $<
fun2.o: fun2.c
$(CC) -c $<
sum.o: sum.c
$(CC) -c $<
## 但是还是要写这么多行
## 可以找到一个共同的规则,给简化
## main.o 依赖 main.c fun.o: fun.c sum.o:sum.c
## 即:xxx.o: xxx.c
-
模式规则:
规则的目标定义中可以包含
%
,表示一个或者多个在依赖条件中同样可以使用
%
,取值取决于其目标比如:
main.o:main.c fun1.o:fun1.c fun2.o:fun2.c
## version4 target = main #给目标起名字 objects = main.o fun1.o fun2.o sum.o CC = gcc CPPFALGS= -I./ $(target): $(objects) $(CC) -o $@ $^ %.o: %.c $(CC) - c $< $(CPPFLAGS) ##main.o: main.c ## $(CC) - c $< $(CPPFLAGS) ##fun1.o: fun1.c ## $(CC) -c $< ##fun2.o: fun2.c ## $(CC) -c $< ##sum.o: sum.c ## $(CC) -c $<
1.3 makefile函数
两个常用的:
wildcard
–查找指定目录下的指定类型的文件
src=$(wildcard *.c)
// 找到当前目录下所有后缀为.c的文件,赋值给src
patsubst
–匹配替换
obj=$(patsubpt %.c,%.o,$(src))
// 把src
变量里所有后缀为.c的文件替换成.o
## version5
target = main #给目标起名字
src=$(wildcard *.c)
objects = $(patsubpt %c, %.o, $(src))
CC = gcc
CPPFALGS= -I./
$(target): $(objects)
$(CC) -o $@ $^
以上版本的缺点是,每次重新编译都需要手工清理中间.o文件和最终目标文件
1.4 makefile的清理操作
用途:清除编译生成的中间.o文件和最终目标文件
make clean
:如果当前目录下有同名clean文件,则不执行clean对应的命令,解决方案:
伪目标声明:
.PHONY:clean
声明目标为伪目标之后,makefile将不会检查该目标是否存在或者该目标是否需要更新
-
clean
命令中的特殊符号:-
-
此条命令出错,make
也会继续执行后续的命令。如:-rm main.o
rm -f:
强制执行,比如要删除的文件不存在使用-f
不会报错 -
@
不显示命令本身,只显示结果。如:@echo clean done
-
-
其它
- make默认执行第一个出现的目标(
main
),可通过make dest
指定要执行的目标(make clean
) make -f
:-f
执行一个makefile文件名称,使用make
执行指定的makefile:make -f mainmak
- make默认执行第一个出现的目标(
## version
target = main #给目标起名字
objects = main.o fun1.o fun2.o sum.o
CC = gcc
CPPFALGS= -I./
$(target): $(objects)
$(CC) -o $@ $^
clean:
# rm *.o
rm $(objects) $(target)
-
这样写的话,使用
make clean
时,会显示make:'clean' is up to date
这是因为
clean
不需要依赖,那clean
这个文件就会一直是最新的,不需要进行更新 -
因此需要将
clean
当做是个伪目标,不需要让他检查更新 -
另外,如果加上之后,成功执行了
clean
,再次执行会显示无法删除xxx.o,没有这个文件或者目录,加上-f就行
## version
target = main #给目标起名字
objects = main.o fun1.o fun2.o sum.o
CC = gcc
CPPFALGS= -I./
$(target): $(objects)
$(CC) -o $@ $^
## 当做是伪目标
.PHONY:clean
clean:
# rm *.o
rm -f $(objects) $(target)