Makefile中的双冒号规则是什么?

时间:2011-10-25 14:45:52

标签: makefile gnu-make

GNU Make手册的4.13节描述了所谓的双冒号规则:

  

双冒号规则是在目标名称后面用'::'而不是':'编写的规则。当同一目标出现在多个规则中时,它们的处理方式与普通规则不同。

     

当目标出现在多个规则中时,所有规则必须是相同的类型:所有规则或所有双冒号。如果它们是双冒号,则每个都是独立的。如果目标比该规则的任何先决条件更旧,则执行每个双冒号规则的命令。如果该规则没有先决条件,则始终执行其命令(即使目标已存在)。这可能导致执行无冒号,任何或所有双冒号规则。

     

具有相同目标的双冒号规则实际上彼此完全分开。每个双冒号规则都是单独处理的,就像处理具有不同目标的规则一样。

     

目标的双冒号规则按它们在makefile中出现的顺序执行。但是,双冒号规则确实有意义的情况是那些执行命令的顺序无关紧要的情况。

     

双冒号规则有点模糊,通常不太有用;它们为用于更新目标的方法根据导致更新的先决条件文件而不同的情况提供了一种机制,这种情况很少见。

     

每个双冒号规则应指定命令;如果没有,则使用隐式规则(如果适用)。请参阅使用隐式规则部分。

我有点单独理解本节每个句子的含义,但我仍然不清楚用于的双冒号规则。至于罕见,我还没有看到任何开源项目,其Makefile

开头
all::

因此: Makefile中双冒号规则的目的是什么?

5 个答案:

答案 0 :(得分:13)

每个::规则都是独立处理的,因此它可以更简单。例如,单一规则:

libxxx.a : sub1.o sub2.o
    ar rv libxxx.a sub1.o
    ar rv libxxx.a sub2.o

可以用两个更简单的规则代替:

libxxx.a :: sub1.o
    ar rv libxxx.a sub1.o

libxxx.a :: sub2.o
    ar rv libxxx.a sub2.o

像AutoMake这样的工具可以更容易地分出许多简单的规则,而不是几个复杂的规则。

发布了更多示例的精彩答案,然后删除,然后在此处找到:

https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html

感谢R.K.欧文写这篇文章,爱德华明尼克斯再次找到它!

答案 1 :(得分:7)

有三种情况可以使用双冒号:

  1. 基于哪个先决条件比目标更新的编译规则之间的备用。以下示例基于http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html
  2. 中的“示例19-3。双冒号规则”

    示例.c文件:

    c@desk:~/test/circle$ cat circle.c 
    #include <stdio.h>
    
    int main (void)
    {
      printf("Example.\n");
      return 0;
    }
    

    使用Makefile:

    c@desk:~/test/circle$ cat Makefile 
    # A makefile for "circle" to demonstrate double-colon rules.
    
    CC = gcc
    RM = rm -f
    CFLAGS = -Wall -std=c99
    DBGFLAGS = -ggdb -pg
    DEBUGFILE = ./debug
    SRC = circle.c
    
    circle :: $(SRC)
            $(CC) $(CFLAGS) -o $@ -lm $^
    
    circle :: $(DEBUGFILE)
            $(CC) $(CFLAGS) $(DBGFLAGS) -o $@ -lm $(SRC)
    
    .PHONY : clean
    
    clean  :
            $(RM) circle
    

    结果:

    c@desk:~/test/circle$ make circle
    gcc -Wall -std=c99 -o circle -lm circle.c
    make: *** No rule to make target 'debug', needed by 'circle'.  Stop.
    c@desk:~/test/circle$ make circle
    gcc -Wall -std=c99 -o circle -lm circle.c
    gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
    c@desk:~/test/circle$ vim circle.c 
    c@desk:~/test/circle$ make circle
    gcc -Wall -std=c99 -o circle -lm circle.c
    c@desk:~/test/circle$ vim debug 
    c@desk:~/test/circle$ make circle
    gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c
    
    1. 制作图案规则终端。
    2. 以下示例解释了这种情况:a.config文件是从a.cfg获得的,而a.cfg又是从a.cfg1获得的(a.cfg是中间文件)。

      c@desk:~/test/circle1$ ls
      a.cfg1  log.txt  Makefile
      c@desk:~/test/circle1$ cat Makefile 
      CP=/bin/cp
      
      %.config:: %.cfg
              @echo "$@ from $<"
              @$(CP) $< $@
      
      %.cfg: %.cfg1
              @echo "$@ from $<"
              @$(CP) $< $@
      
      clean:
              -$(RM) *.config
      

      结果(因为%.config规则是终端,make禁止从a.cfg1创建中间a.cfg文件):

      c@desk:~/test/circle1$ make a.conf
      make: *** No rule to make target 'a.conf'.  Stop.
      

      如果没有%.config的双冒号,结果是:

      c@desk:~/test/circle1$ make a.config
      a.cfg from a.cfg1
      a.config from a.cfg
      rm a.cfg
      
      1. 制定一个始终执行的规则(对于干净的规则很有用)。规则必须没有先决条件!
      2. c @ desk:〜/ test / circle3 $ cat Makefile

        CP=/bin/cp  
        a.config::  
            @echo "Always" >> $@  
        
        a.config::  
            @echo "Always!" >> $@  
        
        clean:  
            -$(RM) *.config  
        

        结果:

        c@desk:~/test/circle3$ make a.config
        c@desk:~/test/circle3$ cat a.config 
        Always
        Always!
        c@desk:~/test/circle3$ make a.config
        c@desk:~/test/circle3$ cat a.config
        Always
        Always!
        Always
        Always!
        

答案 2 :(得分:5)

它们非常适用于非递归的makefile和clean之类的目标。也就是说,单个.mk文件可以将自己的命令添加到已在其他位置定义的clean目标。

Documentation给出了答案:

  

双冒号规则有点模糊,通常不太有用; 它们为用于更新目标的方法根据导致更新的先决条件文件而不同的情况提供了一种机制,这种情况很少见。

答案 3 :(得分:5)

正如文档所说,双冒号规则很少有用。它们是一种很好的,没有命名复合虚假目标的单个目标的方法(如all::),但在这个角色中并不是必需的。我只能在必要时形成一个人为的例子:

假设您有一个日志文件L,它与其他几个日志文件L1,L2,....连接起来。您可以制定一些双冒号规则,如:

L :: L1
     cat $< >> $@ && rm $<

L :: L2
     cat $< >> $@ && rm $<

现在在GNU make中,您当然会使用$^来表达这种魔力,但它在GNU make的功能选项卡中被列为灵感来源。

答案 4 :(得分:0)

我将提供一个简单的示例,希望可以清楚地说明用法:

使用以下makefile进行实验:

  a.faux:: dep1.fake
      $(info run a dep1.fake)
      touch a.faux

  a.faux:: dep2.fake
      $(info run a dep2.fake)
      touch a.faux

  dep1.fake:
      touch dep1.fake

  dep2.fake:
      touch dep2.fake

运行make a.faux,它将导致dep1.fakedep2.fake运行。删除dep1.fake,然后再次运行make a.faux,将仅运行dep1.fake