幽映每白日,清辉照衣裳。这篇文章主要讲述Linux(程序设计):02---make与Makefile的设计与应用相关的知识,希望能为你提供帮助。
一、概念
- 执行make命令时,需要一个Makefile文件,以告诉make命令需要怎么样的去编译和链接程序
- Makefile是一个文本形式的数据库文件,其中包含一些规则来告诉make处理哪些文件以及如何处理这些文件
二、特点
Make是GNU的开源工具
- 概念与Make的帮助文档见:??http://www.gnu.org/software/make/??
- 因为Makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令
- ?自动化编译:?一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
三、Makefile的基本格式
?make与makefile是如何工作的?
- 当我们输入make命令后,make会在当前工作目录下寻找Makefile文件
- 如果找到Makefile文件,它会找到Makefile文件中的第一个目标文件,并把这个目标文件作为最终的目标文件
- 如果这个目标文件不存在或者目标文件依赖于后面的.o文件/其他文件时,那么make就会执行目标文件后面的.o文件/其他文件来生成前面这个目标文件,类似于递归
Makefile的注释
因为#是Makefile的注释,所以如下你想要在Makefile中使用#符号,必须使用转义字符进行转义:?\\#?
- #:Makefile中只有行注释
Makefile的换行
- 执行命令过长时,可以使用\\换行,但是\\后面不可以再跟其他字符,空白符也不行
Make的能力
- Make使最终用户能够构建和安装包,而无需知道如何完成的详细信息 - 因为这些详细信息记录在您提供的makefile中
- 根据更改的源文件,自动生成需要更新的文件。如果一个非源文件依赖于另一个非源文件,它还会自动确定更新文件的正确顺序 因此,如果您更改了一些源文件然后运行Make,则无需重新编译所有程序。它仅更新直接或间接依赖于您更改的源文件的非源文件
- Make不限于任何特定语言。对于程序中的每个非源文件,makefile指定用于计算它的shell命令。这些shell命令可以运行编译器来生成目标文件,生成可执行文件的链接器, ?
?ar?
?更新库,或者TeX或Makeinfo来格式化文档
- Make不仅限于构建包。您还可以使用Make来控制安装或卸载软件包,为其生成标签表,或者您想要经常做的任何其他事情,以便在写下如何操作时使其值得
目标文件:依赖文件
执行命令
- ?目标文件:?就是我们想要生成的文件
- ?依赖文件:?生成目标文件所依赖的文件
- ?执行命令:?利用依赖文件生成目标文件所执行的命令
四、make的执行
?备注:?
- 目标文件的时间戳比任何一个依赖文件的时间戳晚,就生成目标文件
- 目标文件的时间戳比依赖文件的时间戳都早,就更新目标文件
- 缩进:“执行命令”前面有一个Tab键空格
test:prog.o code.o
gcc –o test prog.o code.o
prog.o:prog.c prog.h code.h
gcc –c prog.c –o prog.o
code.o:code.c code.h
gcc –c code.c –o code.o
五、Makefile的显示规则、隐式规则
①没有指定执行目标
- 概念:只输入make,会在当前目录下寻找makefile或Makefile或GNUmakefile脚本文件,并执行脚本文件中的第一个目标。通常我们建议使用“Makefile”
- 例如:make==> 那么就执行生成test的语句块
②指定执行目标
- 概念:make + 目标==> 执行Makefile文件中的指定目标
- 例如:make prog==> 执行生成prog目标文件的语句块
③指定执行其他名称脚本
- 如果有特殊要求,不想make命令执行的是makefile或Makefile文件,可以使用-f或者-file参数
- 例如:make-ffilename==> 执行filename文件,而不去执行makefile/Makefile文件
六、Makefile变量的分类?Makefile的变量分为以下3类:?
显示规则:
?注意:?
- 当我们执行一个目标时,如果这个目标的依赖文件没有,那么make就回去向下检查是否有生成这个依赖文件的命令,如果有就去执行(这是自动执行的)
?案例:?当我们执行make时,make会去生成test这个目标文件,但是prog.o、code.o这两个依赖文件在目录中不存在,那么:
- 依赖性是从文件从上向下的,不能从下向上
- 显示规则下的依赖文件时手动给出的
?
- 通过依赖性,make向下寻找是否有生成prog.o、code.o这两个文件的命令
- 通过向下寻找,可以寻找到生成这两个目标文件的命令,那么就隐式的执行下面两个生成prog.o、code.o的命令
- 隐式生成prog.o、code.o之后,就去执行生成test目标的命令,最终生成test文件
?test:prog.o code.o gcc –o test prog.o code.o prog.o:prog.c prog.h code.h gcc –c prog.c –o prog.o code.o:code.c code.h gcc –c code.c –o code.o?
?
隐式规则:
?注意:?
- 概念:通过显示规则我们知道,我们目标文件的依赖文件没有生成时,就会向下寻找生成依赖文件的生成命令,但是这些生成命令都是手动给出的。通过隐式规则,我们可以省略生成这些依赖文件的命令
?案例:?
- 隐式规则下,在目录下必须有能通过命令生成依赖文件的同名文件
?
- 我们将上面的Makefile进行改写,省去了生成prof.o、code.o的命令,因为make会隐式的生成.o文件,再用这些.o文件生成test(但是目录下必须有prog.c、code.c这样的同名文件,隐式规则才会生效)
?test:prog.o code.o gcc –o test prog.o code.o?
?
- ?用户自定义变量?
- ?预定义变量?
- ?自动变量及环境变量?
七、Makefile变量的赋值?Makefile的变量赋值也分为以下3类:?
①用户自定义变量
?定义以及使用:?
- ?概念:?用户自己定义的(通常建议大写)
?
- 定义之后通过 “$(变量名) ”或 “$变量名” 定义
?hello:hello.c gcc -g -o hello hello.c?
?
?
- 将上面内容进行更改,使用变量,就是下面的格式
?TARGET = hello//定义变量 OBJ = hello.c//定义变量 FLAGS = -g -o//定义变量$(TARGET):$(OBJ) gcc $(FLAGS) $(TARGET) $(OBJ)?
?
②预定义变量
- ?概念:?系统自带的变量,有的有默认值(默认值也可以更改),有的没有默认值
- 定义以及使用与用户自定义变量是一样的
文章图片
??TARGET = hello//定义变量 OBJ = hello.c//定义变量 FLAGS = -g -o//定义变量 CC = gcc//定义变量$(TARGET):$(OBJ) $(CC) $(FLAGS) $(TARGET) $(OBJ)?
?
③自动变量及环境变量
?系统自带的一些变量,不能修改,直接使用,有特殊意义:?
?例如:?
- ?$@:?代表目标文件
- ?$^:?代表依赖文件
- ?$< :?代表第一个依赖文件
- ?$?:?所有时间戳比目标文件晚的依赖文件
- ?$*:?不包含扩展名的目标文件名称
?
- 我们将上面的Makefile改为下面的Makefile
?TARGET = hello OBJ = hello.c FLAGS = -g -o$(TARGET):$(OBJ) $(CC) $(FLAGS) $(TARGET)$(OBJ)?
???TARGET = hello OBJ = hello.c FLAGS = -g -o$(TARGET):$(OBJ) $(CC) $(FLAGS) $@$^?
?
- ?格式一:变量= value?
- ?格式二:变量 := value?
- ?格式三:变量 += value?
八、伪目标(.PHONY)
?格式?一
【Linux(程序设计):02---make与Makefile的设计与应用】
- ?变量= value?
- 特点:这种变量在第一次定义之后就不可以改变(就是我们上面所使用的方式)
?格式二?
?
- ?变量 := value?
- 特点:这种变量在第一次定义之后,还可以通过 “+=” 追加变量内容
?OBJS := test1.o test2.otest:$(OBJS) gcc -o test $(OBJS)OBJS += test3.o //现在OBJS = test1.o test2.o test3.o?
?
格式三:
- ?变量 += value?
- 特点:就是对用 “:=”方式定义的变量进行追加内容,上面有案例
- ?概念:?伪目标是执行时没有依赖文件,并且在磁盘上不会生成文件,只是用来执行命令
- 加不加.PHONY的区别:如果没有使用.PHONY,那么当在当前目录下有一个clean文件时就会报错;加了就不会报错
- 例如下面有一个伪目标clean,当我们执行make clean时,就去执行rm -r *命令(两种方式在于有无.PHONY)
#方式一
.PHONY:clean
clean:
rm -r *
#方式二
clean:
rm -r *
九、Makefile的隐藏输出
用伪目标生成多个文件
?
- 当我们执行make all时,就回去执行生成prog1 prog2 prog3的命令
?all:prog1 prog2 prog3 .PHONY:allprog1:prog1.o utils.o gcc -o prog1 prog1.o utils.o prog2:prog2.o gcc -o prog2 prog2.o prog3:prog3.o gcc -o prog3 prog3.o?
?
- 我们知道makefile中的命令执行之后会在控制台中输出出来,如果不想要命令输出在控制台上,可以在命令之前加一个“@”符号
test:prog.o code.o
gcc –o test prog.o code.o
prog.o:prog.c
@gcc –c prog.c –o prog.o
code.o:code.c
@gcc –c code.c –o code.o
十、通配符?常用的通配符(这些通配符在所有语言中通用的,都是统一标准的):?
- ?%:任意一个?
- ??:匹配?
- ?*:所有 ?
十一、函数?Makefile定义了一系列函数?
*通配符
?
- 代表所有的字符
?#make clean命令删除目录下所有的.c文件clean: rm *.c?
?
%通配符
- 只指代一个字符
- he%l===> heel、hell、heal都是
?通配符
- 匹配1-n个字符
- h?o===> heo、heeo、hello都算
十二、条件判断
wildcard函数
?
- 功能:提取当前目录下的所有.c文件的名称,返回值是这些.c文件名称的字符串
?#SRC这个变量是目录下所有.c文件名的字符串列表SRC = https://www.songbingjia.com/android/$(wildcard *.c)?
?
patsubst函数
?
- 功能:字符串转换函数,将一些字符串转换为另一种格式的字符串
?#OBJS是一系列.o文件名的字符串SRC = https://www.songbingjia.com/android/$(wildcard *.c) OBJS=$(patsubst %.c,%.o,$(SRC)) #将SRC中的所有.c字符串变为.o字符串?
?
- 待续
- 待续
- -C dir:读取指定目录下的Makefile文件
- -f file:将当前目录下指定的file文件作为Makefile文件执行
- -i:忽略所有命令执行错误
- -I dir:指定被包含的Makefile所在目录
- #include < filename>
- include foo.make *.mk $(bar)等价于: include foo.make a.mk b.mk c.mk e.mk f.mk
推荐阅读
- Linux系统编程应用 V4L2编程基础
- Linux(程序设计):05---gcc的基本用法
- Linux(程序设计):06---动态函数库与静态函数库(ldconfigldd命令与/etc/ld.so.conf)
- 服务/软件管理(06---Linux查看主机路由(route命令))
- Circle Linux镜像在阿里云镜像站首发上线
- 服务/软件管理(07---Linux下查看MAC与ARP table(arp命令))
- 服务/软件管理(10---Linux的网卡(ethtool命令))
- Linux-find命令
- Linux(程序设计):41---TCP网络编程