Makefile概述
- makefile的概述
- 在提供人工方便方面: “自动化编译”:一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
- ”自动编译管理器”自动体现在哪里?
根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入makefile文件的内容来执行大量的编译工作。用户只需编写一次简单的编译语句就可以了。
(2)在提升机器效率方面: 提升编译效率:再次编译,只编译修改的文件
- 如何编译多个文件?
- 方法一:暴力法
Gcc add/add_int.c add/add_float.c sub/sub_int.c sub/sub_float.c -o test
- 方法二:makefile
步骤:
<1>vi makefile //创建makefile文件
<2>在内件写make
模板:
目标:依赖
<TAB>命令
内容1:
test:add.c sub.c test.c
gcc add.c sub.c test.c -o test
<3>make
这时候会自动执行mainfile的内容
其中的问题:
(1)当我们修改文件时,make之后会全部编译,主要是我们没有把命令分开写,导致会把所有命令重新运行一遍,降低效率.
解决方式:把make命令分开写
<3> 替代上述<3>
这样写会有问题,只运行第一个命令,后面命令不做
问题原因:系统默认只运行第一个命令,认为命令有缺失才会补全命令
解决方法:最后一条链接命令写到第一个
test:add.o sub.o test.o
gcc add.o sub.o test.o -o test
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
test.o:test.c
gcc -c test.c -o test.o
2.如何删除多个.o文件
(1)方法一:暴力法
rm *.o
(2)方法二:make
步骤
<1>在文件中补充
clean:
rm *.o
<2>make clean
可能出现的问题
当我们有一个叫clean文件时,会出错
解决方法:
<1> 替代上述的<1>
#伪目标
.PHONY:clean
clean:
rm *.o
- makefile创建变量的目的
简言之:方便代码
用来代替一个文本字符串:
- 系列文件的名字
2. 传递给编译器的参数
3. 需要运行的程序
4. 需要查找源代码的目录
5. 你需要输出信息的目录
6. 你想做的其它事情。
3.自定义变量的方法
x = a //变量在声明时需要给予初值
$(x)或${x} //取值 小括号或者中括号都可以
如果你要使用真实的 $ 字符,那么你需要用 $$ 来表示。
<1>例子
test:add.c sub.c test.c
gcc add.c sub.c test.c -o test
问:如何修改成自定义变量?
(1)方法一: 一口气定义法:
SRC = add.c sub.c test.c
test:$(SRC)
gcc ${SRC} -o test
(2)方法二: 逐次定义法
SRC=add.c
SRC+=sub.c
SRC+=test.c
test:$(SRC)
gcc ${SRC} -o test
补充:
上述我们用的是 +=
4.makefile自动变量
$* 不包含扩展名的目标文件名称
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
$< 第一个依赖文件的名称
$? 所有时间戳比目标文件晚的的依赖文件,并以空格分开
$@ 目标文件的完整名称
$^ 所有不重复的目标依赖文件,以空格分开
$% 如果目标是归档成员,则该变量表示目标的归档成员名称
<1>使用自动变量例子
(目的:展示使用方式与使用内容)
(如何查看:echo $..展示代表命令+结果)
test:add.o sub.o test.o
gcc add.o sub.o test.o -o test
添加打印:
- 第一种:
echo $+ //打印所有依赖文件,可重复
echo $^ //打印所有不重复文件
echo $< //打印第一个依赖文件,第一个变量?
- 第二种:上述命令运行时会吧echo$+命令也写上去,取消前加@
@echo $+
@echo $^
@echo $< //只打印结果,不打印echo命令
- 第三种:添加运行时的提醒标识
@echo $$+ = $+ //打印前加上($+ =)
@echo $^
@echo $<
add.o:add.c
gcc -c add.c -o add.o
- $* 与 $@
echo $* //命令+结果不包含扩展名的目标文件名称
echo $@ //命令+结果目标文件的完整名称
sub.o:sub.c
gcc -c sub.c -o sub.o
test.o:test.c
gcc -c test.c -o test.o
4.1为什么要使用自动变量?
<方式一:不用自动变量>
#变量的定义和赋值
SRC = add.o sub.o test.o
test:$(SRC)
gcc ${SRC} -o test
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
test.o:test.c
gcc -c test.c -o test.o
#伪目标
.PHONY:clean
clean:
rm *.o
-----------------------------------------------------------------------------------------------------
<方式二:使用自动变量>
#自动变量SRC = add.o sub.o test.o
test:$(SRC)
gcc ${SRC} -o $@
add.o:add.c
gcc -c $^ -o $@
sub.o:sub.c
gcc -c $^ -o $@
test.o:test.c
gcc -c $^ -o $@
#伪目标
.PHONY:clean
clean:
rm *.o
-----------------------------------------------------------------------------------------------------
在使用自动变量的时候,方便
- Makefile的隐含变量
作用:是对上述的进一步优化.
#变量的定义和赋值
#SRC = add.o sub.o test.o
SRC = add.o
SRC += sub.o
SRC += test.o
#两步编译.c->.o->exe
test:$(SRC)
gcc ${SRC} -o test
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
test.o:test.c
gcc -c test.c -o test.o
--------------------------------------------------------------------------------------------------------
#隐含变量
SRC = add.o sub.o test.o
CC = gcc //CC替代gcc
#CC = arm-linux-gcc //不同编译器时用的这个
CFLAGS = -c -g -Wall -I /home/linux/Makefile/include/<绝对目录>
<也可以直接写include前面不写/,这是相对目录>
#两步编译.c->.o->exe
test:$(SRC)
$(CC) ${SRC} -o $@
%.o:%.c
$(CC) $(CFLAGS) $^ -o $@
<注意>
- 下面是上面的极简化版
- SRC替代依赖文件,CC替代gcc,CFLAGS替代-c/-g等指令
- CFLAGS C编译器的选项,无默认值。
6.Makefile条件判断
(1)例子: 如果我们当前架构是否为x86,如果是,赋值CC=gcc
ARCH = x86
ifneq ($(ARCH),X86)
#不干事
else
CC = gcc
Endif
使用变量:
$(CC) ${SRC} -o $@
(2)例子等价上面,只是ifneq<判断不相等>换成ifdef<判断定义>
ifdef ARCH
CC = gcc
else
#不干事
endif
7.Makefile函数
例子:
#函数
SRC = $(wildcard *.c) //返回当前目录下所有.c源文件列表
OBJ = $(patsubst %.c, %.o<前两个参数意义.c文件替换成.o文件>, $(SRC))
//当前目录所有.c文件替换成.o文件
CC = gcc
CFLAGS = -c -g -Wall -I /home/linux/Makefile/include/
#两步编译.c->.o->exe
test:$(OBJ)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGS) $^ -o $@
- make的-l-f之类使用
- -f例子
make -f makefile2
//自定义运行makefile文件,默认makefile
- -i例子
make -f makefile2 -i
//编译时,忽略错误,继续运行,这样在大型项目时候可以一次找出更多错误
- -n例子
make -n //打印执行的命令,但不执行命令
- -s例子
make -s //不打印命令,只执行命令
- -w例子
make -w //显示执行的目录地址,如/home/linux/include
- -C例子
问题背景:
像工程文件一样,文件放在自己的目录下
(1)在home文件下的makefile
-----------------------------------------------------------------------------------------------------------
CC = gcc
CFLAGS = -c -g -Wall -I /home/linux/Makefile/include/
SRCDIR = ./src
OBJDIR = $(shell pwd)/obj
SRC = $(wildcard $(SRCDIR)/*.c)
OBJ = $(patsubst %.c, $(OBJDIR)/%.o, $(notdir $(SRC)))
<1>以上是建立的变量
CFLAGS 替代参数
SRCDIR OBJDIR 地址替代,注意:下面SRCDIR 作为依赖,不可用$(shell pwd)shell命令
SRC 返回指定目录全部.c
OBJ .c替换到指定文件的.o
-----------------------------------------------------------------------------------------------------------
export CC CFLAGS OBJ OBJDIR
<2>以上是变量分享给其他目录下,就是加上这个,src下也可以使用此类变量
-----------------------------------------------------------------------------------------------------------
all:$(SRCDIR) ECHO test
$(SRCDIR):ECHO
make -C $@
ECHO:
@echo "begin......."
#两步编译
test:$(OBJ)
$(CC) $^ -o $@
<3>以上是伪目标all,加上两个参数$(SRCDIR),ECHO test
<问题:$(SRCDIR):ECHO为什么必须要加上ECHO?>
必须加上依赖才会满足命令定义
<3.1>$(SRCDIR):ECHO
make -C $@ 运行obj文件下makefile,根据内容生成obj文件下.o
<3.2>test:$(OBJ)
$(CC) $^ -o $@ 运行obj文件下.o生成test文件
-----------------------------------------------------------------------------------------------------------
#伪目标
.PHONY:clean
clean:
$(RM) *.o
-----------------------------------------------------------------------------------------------------------
(2)在src文件下的makefile
all:$(OBJ)
$(OBJDIR)/%.o:%.c
$(CC) $(CFLAGS) $^ -o $@
似乎是有%.c%.o时要写一个伪目标,不然找不到.