Zhang Xuan
Zhang Xuan

Reputation: 35

Unexpected Interaction Between Double-Colon Rules (`::`) and `include` in Makefiles

While investigating differences between single-colon rules (:) and double-colon rules (::) in Makefiles, I observed some confusing behaviors:


Experiment 1: Double-Colon Rule + Empty Prerequisites (Failure)

Content of Makefile:

test0.txt::
    touch test0.txt
test.txt::
    touch test.txt
include test.txt

Result:

xuanyi@Shwan:~/try/playground$ tree
.
└── Makefile

1 directory, 1 file
xuanyi@Shwan:~/try/playground$ head -n 20 Makefile 
test0.txt ::
        touch test0.txt

test.txt ::
        touch test.txt

include test.txt
xuanyi@Shwan:~/try/playground$ make
touch test0.txt
xuanyi@Shwan:~/try/playground$ tree
.
├── Makefile
└── test0.txt

1 directory, 2 files
xuanyi@Shwan:~/try/playground$ 

The question is include test.txt did not trigger the double-colon rule, yet the unrelated test0.txt rule executed.


Experiment 2: Single-Colon Rule + Empty Prerequisites (Success)

Content of Makefile:

test0.txt::
    touch test0.txt
test.txt:
    touch test.txt
include test.txt

Result:

xuanyi@Shwan:~/try/playground$ tree
.
└── Makefile

1 directory, 1 file
xuanyi@Shwan:~/try/playground$ head -n 20 Makefile 
test0.txt ::
        touch test0.txt

test.txt :
        touch test.txt

include test.txt
xuanyi@Shwan:~/try/playground$ make
touch test.txt
touch test0.txt
xuanyi@Shwan:~/try/playground$ tree
.
├── Makefile
├── test.txt
└── test0.txt

1 directory, 3 files
xuanyi@Shwan:~/try/playground$ 

Key Difference:


Experiment 3: Double-Colon Rule + Existing Prerequisite (Success)

Content of Makefile:

test0.txt::
    touch test0.txt
test.txt:: invalid_file
    touch test.txt
include test.txt

Result:

xuanyi@Shwan:~/try/playground$ tree
.
└── Makefile

1 directory, 1 file
xuanyi@Shwan:~/try/playground$ head -n 20 Makefile 
test0.txt ::
        touch test0.txt

test.txt :: invalid_file
        touch test.txt

include test.txt
xuanyi@Shwan:~/try/playground$ touch invalid_file
xuanyi@Shwan:~/try/playground$ tree
.
├── Makefile
└── invalid_file

1 directory, 2 files
xuanyi@Shwan:~/try/playground$ make
touch test.txt
touch test0.txt
xuanyi@Shwan:~/try/playground$ tree
.
├── Makefile
├── invalid_file
├── test.txt
└── test0.txt

1 directory, 4 files
xuanyi@Shwan:~/try/playground$ 

About my environment:

xuanyi@Shwan:~/try/playground$ make --version
GNU Make 4.3
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
xuanyi@Shwan:~/try/playground$ hostnamectl
 Static hostname: Shwan
       Icon name: computer-container
         Chassis: container ☐
      Machine ID: #####
         Boot ID: #####
  Virtualization: wsl
Operating System: Ubuntu 24.04.1 LTS                      
          Kernel: Linux 5.15.167.4-microsoft-standard-WSL2
    Architecture: x86-64

I am confused about the result that double-colon rules are triggered by include only if prerequisites exist, but fail with empty prerequisites (Experiment 1). Why do double-colon rules with empty prerequisites conflict with include's priority logic? Does Make apply implicit conditions to double-colon rules?

Let me know if further adjustments are needed.

Upvotes: 2

Views: 22

Answers (1)

MadScientist
MadScientist

Reputation: 101021

First, please always mention the version of GNU Make and the type and version of the operating system you're running it on.

If you enable debugging output you will see that make informs you of what is happening:

$ make -d
...
Makefile 'test.txt' might loop; not remaking it.
...

This message should (IMO) be displayed as part of the --trace output, but it's not unfortunately.

The GNU Make manual discusses the behavior of double-colon rules with no prerequisite:

If there are no prerequisites for that rule, its recipe is always executed (even if the target already exists).

Because of this, if GNU Make were to allow double-colon rules with no prerequisites to recreate makefiles then it would be an infinite loop of creating the makefile, re-invoking make, creating the makefile, re-invoking make, etc.

This is also discussed directly in the GNU Make manual section on re-making makefiles:

If the makefiles specify a double-colon rule to remake a file with a recipe but no prerequisites, that file will always be remade (see Double-Colon Rules). In the case of makefiles, a makefile that has a double-colon rule with a recipe but no prerequisites will be remade every time make is run, and then again after make starts over and reads the makefiles in again. This would cause an infinite loop: make would constantly remake the makefile and restart, and never do anything else. So, to avoid this, make will not attempt to remake makefiles which are specified as targets of a double-colon rule with a recipe but no prerequisites.

Upvotes: 0

Related Questions