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

While investigating differences between single-colon rules (:) and double-colon rules (::) in Makefiles

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

  • Expectation: The include directive should force the target file to be generated (regardless of rule type).
  • Observation: Double-colon rules with empty prerequisites failed to generate files during include, but single-colon rules worked as expected.
  • Confusion: Why do double-colon rules with empty prerequisites conflict with the priority logic of include?

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:

  • Single-colon rules work with include, while double-colon rules with empty prerequisites (Experiment 1) fail.

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 <.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.

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

  • Expectation: The include directive should force the target file to be generated (regardless of rule type).
  • Observation: Double-colon rules with empty prerequisites failed to generate files during include, but single-colon rules worked as expected.
  • Confusion: Why do double-colon rules with empty prerequisites conflict with the priority logic of include?

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:

  • Single-colon rules work with include, while double-colon rules with empty prerequisites (Experiment 1) fail.

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./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.

Share Improve this question asked Mar 2 at 14:36 Zhang XuanZhang Xuan 553 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

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.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745120304a4612374.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信