Makefile学习入门

一、学习时遇到的问题

        在学习Makefile时,首先是对其的语法不太了解,形成对项目的Makefile文件阅读很吃力;其次是在寻找资源上,着实的浪费了很大的精力;最后就是对makefile的工做原理只知其一;不知其二,致使走了不少弯路。html

        下面我将本身对Makefile的理解和认为好的资料分享给你们,但愿你们在接触它时,能够少走弯路。数组

二、为何须要Makefile

        一、在大型的项目中,源文件和目录不计数,文件间的依赖关系及其所在路径很是复杂;模块化

        二、文件间的编译顺序,哪些须要先编译,哪些须要后编译,哪些须要从新编译,咱们不能经过简单的编译命令来完成;     函数

        三、当咱们仅仅修改了部分文件的代码,咱们不能经过只编译更新过的文件来更快的完成编译或者说是模块化编译。工具

这些问题,Makefile均可以解决,  一旦写好,只须要一个make的命令,整个工程就会彻底自动编译,极大的提升了软件开发的效率。学习

三、Makefile是什么

        能够理解为一种自动化编译的工具,里面包含了整个工程项目的编译规则,而且能够将项目分红多个模块进行分别编译,并且里面能够包含执行操做系统的命令。当咱们须要编译代码时,只须要一个命令就可完成整个工程项目的编译或者某个模块的编译。ui

四、Makefile的工做原理

        你们都编译过工程项目,对编译过程应该了解,简单说就是:源文件首先会生成中间目标文件,再由中间目标文件生成执行文件具体说就是:在编译时,编译器只检测程序语法,和函数、变量是否被声明。若是函数未被声明,编译器会给出一个警告,但能够生成 Object File。而在连接程序时,连接器会在全部的 Object File 中找寻函数的实现,若是找不到,那到就会报连接错误码(Linker Error)。若是向具体了解编译过程,能够参考http://my.oschina.net/u/1783725/blog/680722spa

    Makefile格式操作系统

       格式1: target ... : prerequisites ...
                              command   (命令须要tab键)
                              ...
                              ....net

        格式2:targets : prerequisites ; command
                            command  (命令须要tab键)
                            ...

        target 也就是一个目标文件,能够是 Object File,也能够是执行文件。还能够是一个标签(Label)

        prerequisites 就是要生成那个 target 所须要的文件或是目标。

        command 也就是 make 须要执行的命令。 (任意的 Shell 命令)

    工做原理:    target 这一个或多个的目标文件,依赖于prerequisites 中的文件,其生成规则定义在 command 中

                           通俗的说:target 目标的生成,须要知足prerequisites 条件,条件知足才能执行command 来生成目标。 

                           具体的说:若是prerequisites 中若是有一个以上的文件比 target 文件要新(更新日期要新)的话,command 所定义的命令就会被执行。这就是 Makefile 的规则。在编译时,make会比较 targets 文件和 prerequisites 文件的修改日期, 若是 prerequisites 文件的日期要比 targets 文件的日期要新,或者 target 不存在的话,那么,make 就会执行后续定义的命令。

    例子

edit : main.o kbd.o command.o display.o \
		insert.o search.o files.o utils.o
	cc -o edit main.o kbd.o command.o display.o \
		insert.o search.o files.o utils.o
main.o : main.c defs.h
	cc -c main.c
kbd.o : kbd.c defs.h command.h
	cc -c kbd.c
command.o : command.c defs.h command.h
	cc -c command.c
display.o : display.c defs.h buffer.h
	cc -c display.c
insert.o : insert.c defs.h buffer.h
	cc -c insert.c
search.o : search.c defs.h buffer.h
	cc -c search.c
files.o : files.c defs.h buffer.h command.h
	cc -c files.c
utils.o : utils.c defs.h
	cc -c utils.c
clean :
	rm edit main.o kbd.o command.o display.o \
		insert.o search.o files.o utils.o

五、Makefile如何工做

        一、make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
        二、若是找到,它会找文件中的第一个目标文件(target) ,在上面的例子中,他会找到“edit”这个文件,并把这个文件做为最终的目标文件。
        三、若是 edit 文件不存在,或是 edit 所依赖的后面的[.o]文件的文件修改时间要比edit 这个文件新,那么,他就会执行后面所定义的命令来生成 edit 这个文件。
        四、若是 edit 所依赖的.o 文件也存在,那么 make 会在当前文件中找目标为.o 文件的依赖性,若是找到则再根据那一个规则生成.o 文件。 (这有点像一个堆栈的过程)
        五、固然,你的 C 文件和 H 文件是存在的啦,因而 make 会生成 .o 文件,而后再用 .o文件生命 make 的终极任务,也就是执行文件 edit 了。

    注意:make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件,在找寻的过程当中, 若是出现错误, 好比最后被依赖的文件找不到, 那么 make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make 根本不理。make 只管文件的依赖性,即,若是在我找了依赖关系以后,冒号后面的文件仍是不在,那么对不起,我就不工做啦。

            经过上述分析,咱们知道,像 clean 这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,咱们能够显示要 make 执行。即命令——“make clean” ,以此来清除全部的目标文件,以便重编译。

六、工程中make 工做时的执行步骤  

        第5点说的是一个make文件中makefile的执行流程,而第6点说的是整个项目中(多个make文件)makefile的执行流程。

        一、读入全部的 Makefile。
        二、读入被 include 的其它 Makefile。
        三、初始化文件中的变量。
        四、推导隐晦规则,并分析全部规则。
        五、为全部的目标文件建立依赖关系链。
        六、根据依赖关系,决定哪些目标要从新生成。
        七、执行生成命令。  

        经过上面的总结,你们对Makefile应该有一个大致的了解了吧,下面将会对其细节作一下总结。

七、Makefile中的五中规则

        一、显示规则。显示规则说明了,如何生成一个或多的的目标文件。这是由 Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
        二、隐晦规则。因为咱们的 make 有自动推导的功能,因此隐晦的规则可让咱们比较粗糙地简略地书写 Makefile,这是由 make 所支持的。
        三、变量的定义。在 Makefile 中咱们要定义一系列的变量,变量通常都是字符串,这个有点像 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
        四、文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另外一个 Makefile,就像 C 语言中的 include 同样;另外一个是指根据某些状况指定 Makefile 中的有效部分,就像 C 语言中的预编译#if 同样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
        五、注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本同样,其注释是用“#”字符,这个就像 C/C++中的“//”同样。若是你要在你的 Makefile 中使用“#”字符,能够用反斜框进行转义,如: “\#” 
    最后,还值得一提的是,在 Makefile 中的命令,必需要以[Tab]键开始。

八、Makefile中基础

(1)伪目标和.PHONY

 伪目标:“伪目标”并非一个文件,只是一个标签。 make 没法生成它的依赖关系和决定它是否要执行,必须显示地指明这个“目标”才能让其生效
                 “伪目标”的取名不能和文件名重名,否则其就失去了“伪目标”的意义了,可使用一个特殊的标记“.PHONY”来显示地指明一个目标是 “伪目标” 
                 伪目标一样能够做为“默认目标” ,只要将其放在第一个,也能够为伪目标指定所依赖的文件。

                  使用“.PHONY”标记,放在文件首部的第一个目标,不会被make做为执行目标。

(2)通配符

    make 支持通配符: “*” , “?”和“[...]”,通配符能够用在变量中,起做用必须用到wildcard   如objects := $(wildcard *.o)

    注意:一、%.o: %.c                表示的是目标集为当前目录下全部.o结尾的文件,依赖集为当前目录下全部.c结尾的文件

    如某目录下有 test01.c   test02.c   test03.c文件,则%.o:%.c就表示3个,分别为 test01.o:test01.c      test02.o:test02.c        test03.o:test03.c 。具体是否会生成.o文件,还须要看makefile文件中的依赖关系,需不须要生成.o文件。

   二、.c.o           是老式风格的"后缀规则"——双后缀,意义就是".c"是源文件的后缀,".o"是目标文件的后缀

   后缀规则不容许任何的依赖文件,若是有依赖文件的话,那就不是后缀规则,那些后缀通通被认为是文件名

.c.o:
    $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

(3)指定特定的makefile执行文件

     Makefile    make -f Make.Linux 或 make --file Make.AIX

(4)引用其它的makefile文件

    格式     include <filename>      

     如:    include foo.make a.mk b.mk c.mk e.mk f.mk

(5)一些经常使用变量    

    一、“$@”表示目标的集合,就像一个数组, “$@”依次取出目标,并执于命令,如:

bigoutput   littleoutput : text.g
generate   text.g   -$(subst output,,$@) > $@
等价于:
bigoutput : text.g
      generate text.g -big > bigoutput
littleoutput : text.g
           generate text.g -little > littleoutput

  二、“$<”表示第一个依赖文件,依次取出目标,并执于命令

%.o:%.c
	$(CC) $(CFLAGS) -c  -o $@  $<

    依次取出.o的目标文件和.c的第一个依赖文件进行编译。有多少个.o文件,就进行多少次编译。 

三、”$^“ 表示全部的依赖文件

  四、“@”字符在命令行前一般, make 会把其要执行的命令行在命令执行前输出到屏幕上。当咱们用,那么,这个命令将不被 make 显示出来

九、最后给你们推荐一下资料吧

(1)、《跟我一块儿写makefile》,一部很精辟的书,简明扼要,全书无尿点

(2)、http://www.cnblogs.com/wang_yb/p/3990952.html (Makefile 使用总结 ),里面的有关makefile的函数很全,能够当作API来用

沙米的能力有限,但愿你们留言,一块儿交流。

相关文章
相关标签/搜索