首页 文章

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

提问于
浏览
28

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

双冒号规则是在目标名称后面用'::'而不是':'编写的规则 . 当同一目标出现在多个规则中时,它们的处理方式与普通规则不同 . 当目标出现在多个规则中时,所有规则必须是相同的类型:所有规则或所有双冒号 . 如果它们是双冒号,则每个都是独立的 . 如果目标比该规则的任何先决条件更旧,则执行每个双冒号规则的命令 . 如果该规则没有先决条件,则始终执行其命令(即使目标已存在) . 这可能导致执行任何,任何或所有双冒号规则 . 具有相同目标的双冒号规则实际上彼此完全分离 . 每个双冒号规则都是单独处理的,就像处理具有不同目标的规则一样 . 目标的双冒号规则按它们在makefile中出现的顺序执行 . 但是,双冒号规则确实有意义的情况是执行命令的顺序无关紧要的情况 . 双冒号规则有点模糊,通常不太有用;它们为用于更新目标的方法根据导致更新的先决条件文件而不同的情况提供了一种机制,这种情况很少见 . 每个双冒号规则应指定命令;如果没有,则使用隐式规则(如果适用) . 请参阅使用隐式规则部分 .

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

all::

因此: What's the intended purpose of double-colon rules in Makefiles?

4 回答

  • 11

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

    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.欧文写作,爱德华明尼克斯再次找到它!

  • 5

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

    Documentation给出了答案:

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

  • 4

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

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

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

    现在在GNU make中,你当然会使用 $^ 这种魔法,但它被列为GNU make的功能选项卡上的灵感功能 .

  • 5

    有三种情况,双冒号是有用的:

    示例.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
    
    • 制作模式规则终端 .

    下面的例子解释了这种情况: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
    
    • 制定一个始终执行的规则(对于干净的规则很有用) . 规则必须没有先决条件!

    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!
    

相关问题