50

Section 4.13 of the GNU Make manual describes the so-called double-colon rules:

Double-colon rules are rules written with ‘::’ instead of ‘:’ after the target names. They are handled differently from ordinary rules when the same target appears in more than one rule.

When a target appears in multiple rules, all the rules must be the same type: all ordinary, or all double-colon. If they are double-colon, each of them is independent of the others. Each double-colon rule's commands are executed if the target is older than any prerequisites of that rule. If there are no prerequisites for that rule, its commands are always executed (even if the target already exists). This can result in executing none, any, or all of the double-colon rules.

Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just as rules with different targets are processed.

The double-colon rules for a target are executed in the order they appear in the makefile. However, the cases where double-colon rules really make sense are those where the order of executing the commands would not matter.

Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.

Each double-colon rule should specify commands; if it does not, an implicit rule will be used if one applies. See section Using Implicit Rules.

I kinda grok the meaning of each sentence of this section individually, but it's still not clear to me what double-colon rules are for. As for being rare, I have not yet seen any open-source project whose Makefile did not begin with

all::

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

pevik
  • 4,523
  • 3
  • 33
  • 44
lindelof
  • 34,556
  • 31
  • 99
  • 140
  • 2
    One reason for having `all::` up front: It makes `all` the default target. An alternative is to use `.DEFAULT_GOAL = all` up front, but that requires a system with make version 3.81. There are lots of Unix computers whose `make` is either GNU make older than 3.81, or some other make that supports double colon rules. – David Hammen Mar 08 '17 at 00:16

5 Answers5

26

Each :: rule is processed independently, so it can be simpler. For example, the single rule:

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

can be replaced with two simpler rules:

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

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

Utilities like AutoMake have an easier time spitting out many simple rules than a few complex ones.

A great answer with more examples was posted, then taken down, then found here:

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

Thanks to R.K. Owen for writing it, and Edward Minnix for finding it again!

  • 1
    Thanks to the wayback machine, you can still see the old post: https://web.archive.org/web/20180122002430/http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html – Edward Minnix Aug 07 '18 at 13:34
  • Thanks! I'm adding your link to my comment. – William H. Hooper Aug 08 '18 at 18:30
  • I am not sure I understand that example from the wayback machine... why not simply have `prereqs := $(shell for file in *.c; do printf "%s " ${file/.c/.o}; done` and call `mainx : $(prereqs)` and for clean do `-$(RM) $(prereqs)`? – BUFU Nov 13 '20 at 10:34
  • 2
    If the makefile were actually written by a human being, looking at all the tasks at once and synthesizing a pattern, your rules would be fine. The point is that Automake is appending dependencies and clean:: rules to the makefile one at a time. It may not be knowable in advance whether all the mainx dependencies generated by a run of Automake fit the neat pattern you described. As it runs, Automake can tack additional dependencies onto mainx using regular : syntax, but without the :: it can't append actions to clean. – William H. Hooper Nov 15 '20 at 02:43
12

There are 3 situations where the double colon are useful:

  1. Alternate between the compile rules based on which prerequisite is newer than the target. The following example is based on "Example 19-3. Double-colon rules" from http://books.gigatux.nl/mirror/cinanutshell/0596006977/cinanut-CHP-19-SECT-3.html

Sample .c file:

c@desk:~/test/circle$ cat circle.c 
#include <stdio.h>

int main (void)
{
  printf("Example.\n");
  return 0;
}

Makefile used:

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

Outcome:

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. Make a pattern rule terminal.

The following example explains this situation: the a.config file is obtained from a.cfg, which in turn is obtained from a.cfg1 (a.cfg being the intermediate file).

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

Outcome (as the %.config rule is terminal, make inhibits the creation of the intermediate a.cfg file from a.cfg1):

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

Without the double colon for the %.config, the outcome is:

c@desk:~/test/circle1$ make a.config
a.cfg from a.cfg1
a.config from a.cfg
rm a.cfg
  1. Make a rule that executes always (useful for clean rules). The rule must not have prerequisites!

c@desk:~/test/circle3$ cat Makefile

CP=/bin/cp  
a.config::  
    @echo "Always" >> $@  

a.config::  
    @echo "Always!" >> $@  

clean:  
    -$(RM) *.config  

Outcome:

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!
Costin Zanfir
  • 129
  • 1
  • 3
  • The only one getting into the nasty, dark corners. But official references would be nice! – hmijail Mar 31 '16 at 08:14
  • 1
    The lack of official documentation is the reason this subject is considered a "nasty, dark corner". – Costin Zanfir Apr 03 '16 at 15:28
  • 1
    No, not really. A feature which is explained nowhere might as well be a bug (which might have unintended side effects or disappear in the next version). For example, your case 2 **is** in the manual. And case 3 is so confusingly explained that I'm not sure you are mixing it with .PHONY targets, that's why I ask. – hmijail Apr 04 '16 at 06:48
  • 1
    ... and case 3 is **also** in the manual. So, again, providing the references would be particularly good in these dark corners. – hmijail Apr 04 '16 at 08:01
  • 1
    @hmijail, I liked your comments, but you could as well have provided those links then, if you'd looked them up anyway, right?... ;) – Sz. Aug 20 '19 at 21:37
6

They are handy for non-recursive makefiles and targets like clean. That is, an individual .mk file can add its own commands to the clean target already defined elsewhere.

Documentation gives an answer:

Double-colon rules are somewhat obscure and not often very useful; they provide a mechanism for cases in which the method used to update a target differs depending on which prerequisite files caused the update, and such cases are rare.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    For one thing `my-clean` will take a name and will have to be made .PHONY unless double-colon rule is used. Updated the answer. – Maxim Egorushkin Oct 26 '11 at 08:09
  • 1
    A reference (and/or example) for the "add its own commands to [a target] defined elsewhere" would be nice. Also, the documentation link is only one of the cases. – hmijail Mar 31 '16 at 08:12
6

Just as the documentation says, double-colon rules are rarely very useful. They are a nice, little way of not naming the individual targets of a composite phony target (like all::), but not really necessary in this role. I can only form one contrived example where they are necessary:

Suppose you have a logfile L that is concatenated from several other logfiles L1, L2, .... You formulate a number of double-colon rules like:

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

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

Nowadays in GNU make, you would of course use $^ for this kind of magic, but it is listed as an inspired feature on GNU make's feature tab.

thiton
  • 35,651
  • 4
  • 70
  • 100
-1

I'll contribute a simple example to hopefully make the usage clear:

Experiment with the following 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

Run make a.faux, it will causes dep1.fake and dep2.fake to run. Delete dep1.fake and run make a.faux again, only dep1.fake will run.

Zhengyang
  • 354
  • 3
  • 5
  • You forgot to mention that in both cases you run `make a.faux` that both double colon recipes run. – Lewis R Jul 14 '20 at 09:27