makefile 简明教程

5 Makefile项目管理

脚本文件:把一系列命令放在一个文件中,批量执行

命名:makefile Makefile

一个规则:

​ 目标:依赖条件

​ 命令(命令前是1个table缩进)

两个函数:

#wildcard函数,配合通配符找出文件夹中所有	.c文件
src=$(wildcard ./*.c)	
#将所有的.c的文件的后缀更换成.o
obj=$(patsubst %.c,%.o,$(src))

三个自动变量:

三个自动变量只能用于命令行当中,不能用于目标和依赖条件!!!

$@:代表目标文件;

$<:代表依赖条件的第一条;

$^:代表所有的依赖条件;

5.1 一个规则

基本原则

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

2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有更新,则目标必须更新

1)分析各个目标和依赖之间的关系

2)根据依赖关系自底向上执行命令;

3)根据修改时间比目标新,确定更新;

4)如果目标不依赖任何条件,则执行对应命令,以示更新

文件目录如下:

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make1$ tree
.
├── add.c
├── cal.h
├── Makefile
├── sub.c
└── test.c

0 directories, 5 files

对应的Makefile的文件如下:

test: test.o add.o sub.o
	gcc test.o add.o sub.o -o test -I.
test.o:test.c
	gcc -c test.c -o test.o
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
#每个文件分开的好处是    当单个文件改动时,其它文件不需要重新编译
#只需要编译改动的文件,然后重新链接

make命令将检查makefile文件,并将第一条语句作为终极目标;所以最好将总的生成步骤放在最前面;

解决上面的弊端,可以使用ALL命令指定makefile的最终目的;

ALL:a.out

5.2 两个函数

makefile中常用的两个函数:

#找到当前目录下所有后缀为.c的文件,赋值给src
src=$(wildcard ./*.c)
#把src变量里面所有后缀为.c的文件替换成.o
#将参数3中含有参数1的部分替换为参数2
obj=$(patsubst %.c,%.o,$(src))

$(src)代表将函数取值;上述函数调用完之后,变量

src= add.c sub.c test.c

obj=add.o sub.o test.o

有了两个函数之后的makefile可以改写成如下形式:

#指定最终目标
ALL:main
#使用两个函数,src变量代表源文件,obj代表编译生成的.o文件
src=$(wildcard ./*.c)	#add.c sub.c test.c
obj=$(patsubst %.c,%.o,$(src))	#add.o sub.o test.o
main:$(obj)
	gcc $(obj) -o main -I.
test.o:test.c
	gcc -c test.c -o test.o -I.
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
#单独执行 make clean命令,会将文件中的 *.o文件和main文件删除
#添加	make clean -n选项,是模拟执行命令,会在命令行显示将要删除的文件
clean:
	rm -rf $(obj) main
clean:
	-rm -rf $(obj) a.out
#单独执行 make clean命令,会将文件中的 *.o文件和main文件删除
#添加 make clean -n选项,是模拟执行命令

clean命令没有依赖,rm之前的“-”,作用是删除不存在的文件时,不报错;

5.3 三个自动变量

3个自动变量:

$@:在规则的命令中,表示规则中的目标(不可以用于目标或者依赖项中);

$^:在规则的命令中,表示规则的所有依赖条件

$<:在规则的命令中,表示规则中的第一个依赖条件;如果将该自动变量应用与模式规则中,它可将依赖条件列表中的依赖,依次取出,套用模式规则;

有了3个自动变量,上面的makefile可以进一步的改写为,

ALL:main
src=$(wildcard ./*.c)	#add.c sub.c test.c
obj=$(patsubst %.c,%.o,$(src))	#add.o sub.o test.o
main:$(obj)
	gcc $^ -o $@ -I.
test.o:test.c
	gcc -c $< -o $@ -I.
add.o:add.c
	gcc -c $< -o $@
sub.o:sub.c
	gcc -c $< -o $@
clean:
	-rm -rf $(obj) main

5.4 模式规则

上一节的makefile将每个.c 编译成.o的过程中,命令都是相同的,即:

gcc -c $< -o $@

这样可以使用模式规则将多条指令改写为下面的形式:

%.o:%.c
	gcc -c $< -o $@

上面的makefile可以进一步改写成为:

ALL:main
src=$(wildcard ./*.c)	#add.c sub.c test.c
obj=$(patsubst %.c,%.o,$(src))	#add.o sub.o test.o
main:$(obj)
	gcc $^ -o $@ -I.
%.o:%.c
	gcc -c $< -o $@
clean:
	-rm -rf $(obj)
#单独执行 make clean命令,会将文件中的 *.o文件和main文件删除
#添加	make clean -n选项,是模拟执行命令

通过多次的更新,实现了makefile的可扩展功能,在原来文件的基础上,添加乘法模块,mul.c,makefile并不需要重新编写,

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make3$ tree
├── add.c
├── cal.h
├── makefile
├── mul.c
├── sub.c
└── test.c
0 directories, 6 files

5.5 扩展

静态模式规则:

下面的语句是,向obj变量中的.o文件,生成.c文件;

$(obj):%.o:%c
	gcc -c $< -o $@

生成伪目标:

示例:在上面的文件夹中新增一个clean文件,即通过命令 touch clean,文件目录如下:

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make3$ tree
.
├── add.c
├── cal.h
├── clean
├── makefile
├── mul.c
├── sub.c
└── test.c

0 directories, 7 files

之后再执行 make clean命令,会出现错误:

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make3$ make clean
make: “clean”已是最新。

这是因为文件夹下的clean文件,干扰了make clean文件的执行,尤其是在clean这种没有依赖项的命令中,在这种情况下,可以通过添加伪目标解决,如下:

伪目标:不生成文件,但是要执行目标;

ALL:main
src=$(wildcard ./*.c)	#add.c sub.c test.c
obj=$(patsubst %.c,%.o,$(src))	#add.o sub.o test.o
main:$(obj)
	gcc $^ -o $@ -I.
%.o:%.c
	gcc -c $< -o $@
clean:
	-rm -rf $(obj)
#伪目标
.PHONY:clean ALL

添加编译参数:

可以将编译参数添加到 myArgs里面,然后使$(myArgs)将其中的参数取出;

ALL:main
src=$(wildcard ./*.c)	#add.c sub.c test.c
obj=$(patsubst %.c,%.o,$(src))	#add.o sub.o test.o
myArgs=-Wall -g
main:$(obj)
	gcc $^ -o $@ -I. $(myArgs)
%.o:%.c
	gcc -c $< -o $@ $(myArgs)
clean:
	-rm -rf $(obj)
#伪目标
.PHONY:clean ALL

库变量

是makefile库中自己定义的变量,有的变量有默认值,由的变量没有默认值

CC:默认是 CC =cc c语言编译工具

CPPFLAGS: C++默认参数

CFLAGS: C默认参数

LDFLAGS: 动态链接参数

同时编译同一个目录下的多个文件实例

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make5$ tree
.
├── add.c
├── makefile
├── mul.c
└── sub.c

0 directories, 4 files

要求每个 %.c文件都编译成为一个单独的 %.out的可执行文件

makefile的编写如下:

src=$(wildcard *.c)
# obj=$(patsubst %.c,%.o,$(src))
out=$(patsubst %.c,%.out,$(src))
ALL: $(out)
$(out):%.out:%.c
	gcc $< -o $@
clean:
	-rm -rf $(out)
.PHONY:ALL clean

5.6 标准示例

文件的目录如下:

daniel@daniel-Vostro-5471:~/文档/OS/test/make_test/make4$ tree
.
├── inc
│   └── cal.h
├── main
├── makefile
├── obj
└── src
    ├── add.c
    ├── mul.c
    ├── sub.c
    └── test.c

要求:将编译文件放到obj目录中

makefile文件编写如下:

#编译总目标文件
ALL:main
#设置变量
src=$(wildcard ./src/*.c)	#./src/ add.c sub.c mul.c test.c
# #  %是等价代换的意思,将第一个变量中取出的%的值,放到第二个%上
obj=$(patsubst ./src/%.c,./obj/%.o,$(src))#./obj/ add.o sub.o mul.o test.o
# echo:
# 	echo $(src) $(obj)
#头文件位置
inc_path=./inc
#设置编译参数
myArgs=-Wall -g 
#编译
main:$(obj)
	gcc $^ -o $@ $(myArgs)
# 将obj目录更换为src目录
# 头文件展开在预处理阶段运行,所以17行不需要添加头文件
$(obj):./obj/%.o:./src/%.c
	gcc -c $< -o $@ $(myArgs) -I $(inc_path)
clean:
	-rm -rf $(obj)
.PHONY: ALL clean

不使用makefile为命令,也可以运行,比如给文件其名字 m6(mv makefile m6)

运行方法是:make -f m6

很多文件的命名方式是:****.mk,可能就是makefile文件

make 可以进行多线程编译,make -j4或者make -j8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值