第二十八节(MakeFile语法)

新建一个目录编写几个c文件,然后利用gcc命令将其链接为可执行程序

第二十八节(MakeFile语法)_第1张图片
image.png

首先利用gcc -c将这些c文件编译为.o文件
例如:

gcc -c divi.c

编译完成后

image.png

利用 gcc -o 命令将这些.o文件链接为可执行文件

gcc divi.o main.o minus.o multi.o plus.o -o app

链接完成后会生成一个app可执行文件

image.png

运行命令,可以看到正确的输出结果:

hhh:makefile huozhenpeng$ ./app
ret:10

现在利用makefile语法来完成上述所有的步骤
新建一个文件,名字就叫做makefile

第二十八节(MakeFile语法)_第2张图片
image.png
app:divi.o plus.o main.o minus.o multi.o
    gcc divi.o plus.o main.o minus.o multi.o -o app
divi.o:divi.c
    gcc -c divi.c
plus.o:plus.c
    gcc -c plus.c
main.o:main.c
    gcc -c main.c
minus.o:minus.c
    gcc -c minus.c
multi.o:multi.c
    gcc -c multi.c

在命令行窗口输入命令make

hhh:makefile huozhenpeng$ make

然后就会生成中间文件(.o)并利用.o文件生成可执行文件app

第二十八节(MakeFile语法)_第3张图片
image.png

运行app可执行文件

hhh:makefile huozhenpeng$ ./app
ret:10

一个简单的makefile语法的格式:

一个简单的 Makefile 描述规则组成:
TARGET... : PREREQUISITES... 
        COMMAND
...
...

target:规则的目标。通常是最后需要生成的文件名或者为了实现这个目的而必需 的中间过程文件名。可以是.o文件、也可以是最后的可执行程序的文件名等。另外,目 标也可以是一个make执行的动作的名称,如目标“clean”,我们称这样的目标是“伪目标”

还是上面的程序,我们修改makefile文件

app:divi.o plus.o main.o minus.o multi.o
    gcc divi.o plus.o main.o minus.o multi.o -o app
divi.o:divi.c
    gcc -c divi.c
plus.o:plus.c
    gcc -c plus.c
main.o:main.c
    gcc -c main.c
minus.o:minus.c
    gcc -c minus.c
multi.o:multi.c
    gcc -c multi.c
clean:
    rm -f *.o
第二十八节(MakeFile语法)_第4张图片
image.png

执行make命令,生成了.o和app可执行文件

第二十八节(MakeFile语法)_第5张图片
image.png

执行make clean命令,成功删除了.o文件

第二十八节(MakeFile语法)_第6张图片
image.png

但是如果我们在这个目录中有个clean文件的时候,make clean 命令就不会起作用了

第二十八节(MakeFile语法)_第7张图片
image.png

执行make命令:

第二十八节(MakeFile语法)_第8张图片
image.png

执行make clean 命令:

image.png

无法删除.o文件
如果我们需要书写这样一个规则:规则所定义的命令不是去创建目标文件,而是通过 make 命令行明确指定它来执一些特定的命令。像常见的 clean 目标:

clean:
        rm *.o temp

规则中“rm”不是创建文件“clean”的命令,而是删除当前目录下的所有.o 文件和 temp 文件。当工作目录下不存在“clean”这个文件时,我们输入“make clean”,“rm *.o temp”总会被执行。这是我们的初衷。
但是如果在当前工作目录下存在文件“clean”,情况就不一样了,同样我们输入 “make clean”,由于这个规则没有任何依赖文件,所以目标被认为是最新的而不去执 行规则所定义的命令,因此命令“rm”将不会被执行。这并不是我们的初衷。为了解 决这个问题,我们需要将目标“clean”声明为伪目标。将一个目标声明为伪目标的方 法是将它作为特殊目标.PHONY”的依赖
修改makefile文件:

app:divi.o plus.o main.o minus.o multi.o
    gcc divi.o plus.o main.o minus.o multi.o -o app
divi.o:divi.c
    gcc -c divi.c
plus.o:plus.c
    gcc -c plus.c
main.o:main.c
    gcc -c main.c
minus.o:minus.c
    gcc -c minus.c
multi.o:multi.c
    gcc -c multi.c
.PHONY:clean
clean:
    rm -f *.o

然后make clean命令就可以正常工作了,就是目录中存在一个名字为clean的文件。

定义变量与通配符

定义变量

在实际工作中大家都比较认同的方法是,使用一个变量 “objects”、“OBJECTS”、“objs”、“OBJS”、“obj”或者“OBJ”来作为所有的.o 文 件的列表的替代。

模式规则

在模式规则中,目标文件是一个带有模式字符“%”的文件,使用模式来匹配目标文件。文件名中的模式字符“%”可以匹配任何非空字符串,除模式字符以外的部分要 求一致。例如:“%.c”匹配所有以“.c”结尾的文件(匹配的文件名长度最少为3个字 母),“s%.c”匹配所有第一个字母为“s”,而且必须以“.c”结尾的文件,文件名长度 最小为5个字符(模式字符“%”至少匹配一个字符)。

自动化变量

$@
表示规则的目标文件名,如果目标是一个文档文件(Linux中,一般称.a文件为 文档文件,也称为静态库文件),那么它代表这个文档的文件名。在多目标模式 规则中,它代表的是哪个触发规则被执行的目标文件名

$%
当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则 的目标是“foo.a(bar.o)”,那么,“$%”的值就为“bar.o”,“$@”的值为“foo.a”。 如果目标不是静态库文件,其值为空。

$<
规则的第一个依赖文件名。如果是一个目标文件使用隐含规则来重建,则它代表
由隐含规则加入的第一个依赖文件。

$?
所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件)。

$^
规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的 只能是所有库成员(.o文件)名。一个文件可重复的出现在目标的依赖中,变量 “$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件

还有好多,就简单了解这几个吧。
现在利用定义变量、通配符、自动化变量的方式来简化上面的makefile文件。
于是上面的makefile就可以简化为:

objects=divi.o plus.o main.o minus.o multi.o
app:$(objects)
    gcc $(objects) -o app
%.o:%.c
    gcc -c $^ -o $@
.PHONY:clean
clean:
    rm -f *.o

你可能感兴趣的:(第二十八节(MakeFile语法))