一、Makefile的书写规则

  targets : prerequisites (注意冒号两边有空格)
        command   (注意前面用tab键开头)
        ... 
或是这样: 
      targets : prerequisites ; command 
            command 
            ... 

  解释:

  1 targets (目标)可以是一个或多个,可以是Object File,也可以是执行文件,甚至可以是一个标签。

  2 prerequisites (需要的条件)就是生成目标所需要的文件或目标

  3 command (命令)就是生成目标所需要执行的脚本

  就是说一条makefile规则规定了编译的依赖关系,也就是目标文件依赖于条件,生成规则用命令来描述。在编译时,如果需要的条件的文件比目标更新的话,就会执行生成命令来更新目标。

       如果命令太长,你可以使用反斜框(‘\’)作为换行符。make对一行上有多少个字符没有限制。规则告诉make两件事,文件的依赖关系和如何成成目标文件。 

  下面举个简单的例子说明。如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。

  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就可以进行编译,执行make clean就可以删除所有目标文件。解释一下,也就是说生成最终的目标文件edit,依赖于一系列的.o目标文件,而这些.o文件又是需要用源文件来编译生成的。

  需要注意的是,clean后面没有条件,而clean本身也不是文件,它只不过是一个动作名字其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。

  make是如何工作的

  在默认的方式下,也就是我们只输入make命令。那么,

 

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

  makefile中使用变量

  前面的知识已经足以让你自己完成一个简单的makefile了,不过makefile的精妙之处远不止如此,下面来看看如何在makefile中使用变量吧。

  在上面的例子中,先让我们看看edit的规则:

 

      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

 

  我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文 件,那么我们需要在两个地方加(应该是三个地方,还有一个地方在clean中)。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果 makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们 可以使用变量。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。

  于是,我们使用变量objects

  objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

  这样一来,原来的makefile变成如下的样子:

  objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)
    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 $(objects)

  这样看起来方便多了吧,也更加省事了。如果有新的.o文件怎么办?当然是在objects里面添加了,这样只需要一处改变,很方便吧。

  让make自动推导

  GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。

  只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一 个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来,于是,我们的makefile再也不用写得这么复杂。我们的是新的makefile又出炉了。

  objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

 

    main.o : defs.h
    kbd.o : defs.h command.h
    command.o : defs.h command.h
    display.o : defs.h buffer.h
    insert.o : defs.h buffer.h
    search.o : defs.h buffer.h
    files.o : defs.h buffer.h command.h
    utils.o : defs.h

  clean :
            rm edit $(objects)

  当然,如果你觉得那么多[.o]和[.h]的依赖有点不爽的话,好吧,没有问题,这个对于make来说很容易,谁叫它提供了自动推导命令和文件的功能呢?来看看最新风格的makefile吧。

  objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

 

    $(objects) : defs.h
    kbd.o command.o files.o : command.h
    display.o insert.o search.o files.o : buffer.h
    clean :
            rm edit $(objects)

  不过话说回来,本人并不推荐这种方法。虽然简单,但是这种方法破坏了文件本身的依赖关系。如果文件过多的话,可能你自己都不清楚了。

  

  怎么样,makefile是不是既简单又强大?其实makefile远比这更强大,容我日后再慢慢介绍,今天就先到这里。


二、ifeq,ifneq,ifdef,ifndef的使用

(1)ifeq的用法

         ifeq ($(变量名), 变量值 )

           ........

         else ifeq ($(..), ..)

           .........

         else

           .........

         endif


    (2)makefile中需要用ifeq进行逻辑与判断,但是ifeq并没有像其他编程语言那样有 逻辑或(||)  逻辑与(&&) 的符号可用。这时候需要变通一下。

        1)逻辑与变通实现:

        举例说明:比如需要判断两个变量 VALUE1 和 VALUE2 的值都存在才执行某个动作,这需要逻辑与的判断

        C语言的逻辑:  if ( VALUE1  &&  VALUE2){

                                           do something....

                                   } 

       没有&&符号,我们可以这样变通:将两个变量链接起来再判断

        ifneq ($(VALUE1)$(VALUE2),)

               do something....

        endif

     

       如果变量 VALUE1 和 VALUE2 都有具体的值,比如需要进行这样的判断: VALUE1 == V1 && VALUE2 == V2, 可以按如下的写法;

       ifeq ($(VALUE1)_$(VALUE2), V1_V2)    ### 当然中间的下划线 "_" 可以用其他字符代替  

               do something....

        endif


     2) 逻辑或变通实现,同样是上面的两个变量

         if( VALUE1 == V1 || VALUE2 == V2 ) {...} 可以用findstring函数做如下变通实现:

         #如果VALUE1或者VALUE2为V1或V2,则findstring 不会返回空。

         ifneq ($(findstring $(VALUE1)$(VALUE2),  V1  V2),)

            do something...

         endif

    (3)ifneq,ifdef,ifndef

第二个条件关键字是“ifneq”,语法是: 


ifneq (<arg1>;, <arg2>;)
ifneq '<arg1>;' '<arg2>;'
ifneq "<arg1>;" "<arg2>;"
ifneq "<arg1>;" '<arg2>;'
ifneq '<arg1>;' "<arg2>;"

其比较参数“arg1”和“arg2”的值是否相同,如果不同,则为真。和“ifeq”类似。

第三个条件关键字是“ifdef”。语法是:

ifdef <variable-name>;

如果变量<variable-name>;的值非空,那到表达式为真。否则,表达式为假。当然,<variable-name>;同样可以是一个函数的返回值。注意,ifdef只是测试一个变量是否有值,其并不会把变量扩展到当前位置。还是来看两个例子:

示例一:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif

示例二:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif

第一个例子中,“$(frobozz)”值是“yes”,第二个则是“no”。
第四个条件关键字是“ifndef”。其语法是: 

ifndef <variable-name>;

这个我就不多说了,和“ifdef”是相反的意思。

在<conditional-directive>;这一行上,多余的空格是被允许的,但是不能以[Tab]键做为开始(不然就被认为是命令)。而注释符“#”同样也是安全的。“else”和“endif”也一样,只要不是以[Tab]键开始就行了。

特别注意的是,make是在读取Makefile时就计算条件表达式的值,并根据条件表达式的值来选择语句,所以,你最好不要把自动化变量(如“$@”等)放入条件表达式中,因为自动化变量是在运行时才有的。

而且,为了避免混乱,make不允许把整个条件语句分成两部分放在不同的文件中。

大牛的文章:http://blog.csdn.net/haoel/article/details/2887


Logo

更多推荐