初识 makefile 的结构(二)

        我们在上节中说到 makefile 的本质就是一个脚本程序,用来解释执行的。那么它的意义是用于定义源文件间的依赖关系,说明如何编译各个源文件并生成可执行文件。我们来看看依赖的定义,如下

图片.png

        下来我们来分析下 makefile 中元素的意义:a> targets:通常是需要生成的目标文件名,make 所需执行的命令名称;b> perequisities:当前目标所依赖的其他目标或文件;c> command:完成目标所需要执行的命令。我们来说说规则中的注意事项:a> targets 可以包含多个目标,使用空格对多个目标名进行分隔;b> perequisities 可以包含多个依赖,使用空格对多个依赖进行分隔;c> [ Tab ] 键 '\t',每一个命令行必须以 [ Tab ] 字符开始,[ Tab ] 字符告诉 make 此行是一个命令行;d> 续行符 \,可以将内容分开写到下一行,提高代码可读性。

        下来我们看看一个 makefile 的依赖示例,如下

图片.png

        依赖规则是:a> 当目标对应的文件不存在,执行对应命令;b> 当依赖在时间上比目标更新,执行对应命令;c> 当依赖关系连续发生时,对比依赖链上的每一个目标。在这讲个小技巧:makefile 中可以在命令前加上 @ 符,作用为命令无回显。

        我们还是以代码为例来进行分析说明

all : test
    @echo "make all"

test : 
    @echo "make test"

        我们定义的目标 all 的依赖是 test,而 test 目标则没有依赖,只是执行打印语句。当 test 目标正确执行后,all 目标的执行语句便会进行正常输出。也就是说,先打印 make test,在输出 make all。我们来看看编译结果

图片.png

        那为什么只打印出这两句,没有打印出上一节我们看到的 echo "make all" 呢?原因就是我们在它们前面加的 @  无回显符号,下来我们去掉 @ 符号看看编译效果

图片.png

        以后如果我们不想看到 echo 那条命令本身的话,可以加上 @ 无回显符号。下来我们来看个 make 的编译案例,结构如下

图片.png

        我们来根据上面的结构编写相应的 makefile 程序,看看执行效果


func.c 源码

#include <stdio.h>

int foo()
{
    printf("void foo()\n");
}


main.c 源码

extern void foo();

int main()
{
    foo();

    return 0;
}


makefile 源码

hello.out : func.o main.o
    gcc -o hello.out func.o main.o

func.o : func.c 
    gcc -o func.o -c func.c

main.o : main.c
    gcc -o main.o -c main.c

        我们来看看编译结果

图片.png

        我们看到已经实现了。我们再来在 func.c 中打印的语句前加上 hello,再来看看编译结果

图片.png

        我们看到再次进行编译时,它只编译了 func.c 文件,没有编译 main.c 文件,这也极大的提升了嵌入式编译的效率。那么在这块有个小技巧,在工程开发中可以将最终可执行文件名和 all 同时作为 makefile 中第一条规则的目标,如下

图片.png

        我们再次来编译,看看编译结果

图片.png

        我们看到它说 hello.out 是最新的,执行的结果和我们之前是一样的。因此这个小技巧可以极大的提高我们因重复编译带来的效率低下的问题。我们也可以直接 make all 进行再次编译,如下

图片.png

        这次因为源文件都没有改动,所以只执行了 hello.out 目标后面的语句。提高对 makefile 结构的学习,总结如下:1、makefile 用于定义源文件间的依赖关系;2、makefile 说明如何编译各个源文件并生成可执行文件;3、makefile 中的目标之间存在连续依赖关系;4、依赖存在并且命令执行成功是目标完成的充要条件。


        欢迎大家一起来学习 makefile 语言,可以加我QQ:243343083

猜你喜欢

转载自blog.51cto.com/12810168/2126854