06项目自动化构建工具-make/Makefile

make是一个命令,makefile是一个文件,通常该文件会在当前工作目录下存放。
在VS当中,项目管理(多文件管理)是VS帮我们自动管理的。
但是在Linux中,维护项目文件关系的工作(比如同时编译链接多个文件),需要让make、makefile来完成。所以makefile带来的好处就是“自动化编译”,一旦写好,只需一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。


文章目录


依赖关系和依赖方法

如果对A文件作出修改会影响文件B,那B就依赖于A,比如B是由文件A编译链接出来的。
以链表举例子,一个可执行程序list包含三个list.c、list.h、main.c,最终生成的可执行程序是由list.omain.o所链接的,所以list依赖于list.omain.o。而list.cmain.o又是各自的.c文件通过预处理、编译以及汇编得到的,.c文件的改变会影响.o,所以说.o文件依赖于.c文件。

如果文件B依赖于文件A,那么通过文件A得到文件B的方法,就是文件B依赖于文件A的依赖方法。
比如将list.omain.o链接形成list就是依赖方法。.c文件通过预处理、编译以及汇编得到.o文件就是依赖方法。


使用Makefile实现多文件编译

以链表为例:
06项目自动化构建工具-make/Makefile

我们大可以直接对多个源文件进行编译,进而生成可执行程序。:
06项目自动化构建工具-make/Makefile

但进行多文件编译的时候一般不使用源文件直接生成可执行程序,而是先用每个源文件各自生成自己的二进制文件,然后再将这些二进制文件通过链接生成可执行程序。
原因有两点:

  • 如果直接使用源文件生成可执行程序,那么其中一个源文件进行了修改,再生成可执行程序的时候就需要将所以的源文件重新进行编译链接。
  • 如果是先用每个源文件各自生成自己的二进制文件,那么其中一个源文件进行了修改,就只需重新编译生成该源文件的二进制文件,然后再将这些二进制文件通过链接生成可执行程序即可。

06项目自动化构建工具-make/Makefile

就像VS会生成.obj文件一样:
06项目自动化构建工具-make/Makefile

另外, 编译链接的时候不需要加上头文件,因为编译器通过源文件的内容可以知道所需的头文件名字,而通过头文件的包含方式(<>包含和" ”包含),链接的时候编译器就知道应该从何处去寻找所需的头文件。

上面的方法对于文件比较少的情况还好,当文件比较多时(比如上百个),那gcc后面跟的文件个数就多了,而且也会有漏掉或写错的可能。很明显这种方式是不好的。

此时使用make和Makefile了,将会大大减工作量:

  • 在源文件所在目录下创建一个名为Makefile的文件
  • 编写Makefile文件,编写的规则包括两部分:依赖关系和依赖方法。通常先写出文件的依赖关系,然后写出这些文件之间的依赖方法,依次写下去:
    06项目自动化构建工具-make/Makefile

比如这里list依赖list.o和main.o,而依赖方法就是将通过gcc将main.o和list.o链接起来,同时list.o依赖list.c,main,o依赖main.c

  • 编写完成后执行make即可

06项目自动化构建工具-make/Makefile

上面的写法还是非常繁琐,因为gcc后还要写各种文件,使用通配符可以避免这种情况:

  • $@:表示依赖关系中的目标文件(冒号左侧)。
  • $^:表示依赖关系中的依赖文件列表(冒号右侧全部)。
  • $<:表示依赖关系中的第一个依赖文件(冒号右侧第一个)。
  • %:表示同类型的文件。

所以Makefile就可以这样写:
06项目自动化构建工具-make/Makefile

使用通配符%,可以将大量同类型的文件,只用一条规则就完成构建。

%.o:%.c等价于list.o:list.cmain.o:main.c

06项目自动化构建工具-make/Makefile

make的原理

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“list”这个文件,并把这个文件作为最终的目标文件。
  3. 如果list文件不存在,或是list所依赖的后面的list.o和main.o文件的文件修改时间要比list这个文件新,那么,他就会执行后面所定义的命令来生成list这个文件。
  4. 如果list所依赖的.o文件不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
  5. 当然,.c文件和.h文件是存在的啦,于是make会生成 list.o和main.o 文件,然后再用 这俩.o 文件声明make的终极任务,也就是执行文件list了。
  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  8. make只管文件的依赖性,即,如果在找了依赖关系之后,冒号后面的文件还是不在,那么make就不工作。

使用Makefile清理项目

也可以使用Makefile清理项目:
06项目自动化构建工具-make/Makefile
clean.PHONY修饰成伪目标,不是真实存在的文件clean。

像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,
所以要用make执行。即命令make clean,以此来清除所有的目标文件,以便重编译。
06项目自动化构建工具-make/Makefile

伪目标的特性是,总是被执行的。如果clean不被 .PHONY修饰成伪目标,那么当前目录存在一个clean文件的时候,make clean这条命令就不会被执行:
06项目自动化构建工具-make/Makefile

综上,Makefile全部内容如下:
06项目自动化构建工具-make/Makefile

上一篇:5.makefile


下一篇:<ubbot&Makefile>uboot下的文件目录结构和主Makefile的分析