make kindaclean; make --debug=all says:

    Finished prerequisites of target file 'a-derived.src'.
    Prerequisite 'a.out' of target 'a-derived.src' does not exist.
   No need to remake target 'a-derived.src'.

https://www.gnu.org/software/make/manual/html_node/Chained-Rules.html#Chained-Rules
 teaches:

The first difference is what happens if the intermediate file does not exist. 
If an ordinary file b does not exist, and make considers a target that depends 
on b, it invariably creates b and then updates the target from b. But if b is 
an intermediate file, then make can leave well enough alone. It won’t bother 
updating b, or the ultimate target, unless some prerequisite of b is newer than 
that target or there is some other reason to update that target.

By using .SECONDARY with no prerequisites, you've marked everything as 
intermediate.  Marking just a.out as .SECONDARY seems enough to cause the 
problem.

________________________________
From: Bug-make <bug-make-bounces+martin.dorey=hds....@gnu.org> on behalf of 
Luke Shumaker <luke...@lukeshu.com>
Sent: Friday, February 22, 2019 11:45
To: bug-make@gnu.org
Subject: Erroneously not updating intermediate/secondary dependency

***** EXTERNAL EMAIL *****

I believe that I have found a bug present in both Make 4.2.1 (as shipped by Arch
Linux) and in the latest git commit (214865ed5c66d8e363b16ea74509f23d93456707).

Here is a simple Makefile demonstrating the bug:

        all: a-derived.out
        .PHONY: all

        kindaclean:
                rm -f -- *.out
        clean: kindaclean
                rm -f -- a-derived.src
        .PHONY: kindaclean clean

        %.out: %.src
                { echo 'build'; date; ls -l $^; } > $@

        a-derived.src: a.out
                { echo 'generate'; date; ls -l $^; } > $@
        a-derived.out: a.out # Make sure that "a.out" isn't skipped as 
intermediate

        .SECONDARY:

For clarity, here is the dependency graph; "==" indicates an explicit
rule, "--" indicates an implicit rule:

        all >===> a-derived.out >---> a-derived.src >===> a.out >---> a.src
                               `>=======================>'

The bug is that when running

        $ echo foo > a.src

        $ make
        { echo 'build'; date; ls -l a.src; } > a.out
        { echo 'generate'; date; ls -l a.out; } > a-derived.src
        { echo 'build'; date; ls -l a-derived.src a.out; } > a-derived.out

        $ make kindaclean
        rm -f -- *.out

        $ make
        { echo 'build'; date; ls -l a.src; } > a.out
        { echo 'build'; date; ls -l a-derived.src a.out; } > a-derived.out

The "a-derived.src" does not get updated, despite both of thes
conditions being met: (1) its dependency "a.out" getting updated, and
(2) it being used in a later recipe.

We can instrument the Makefile to more explicitly demonstrate the
failure:

        define sanitycheck
          if ! test -e $1; then \
            echo '=> dependency "$(strip $1): $(strip $2)" skipped because 
dependent "$(strip $1)" does not exist'; \
          elif ! test -e $2; then \
            echo '=> dependency "$(strip $1): $(strip $2)" skipped because 
dependency "$(strip $2)" does not exist'; \
          elif test $2 -nt $1; then \
            echo '=> dependency "$(strip $1): $(strip $2)" failed because 
dependency "$(strip $2)" is newer than dependant "$(strip $1)"'; \
            ls -l $1 $2; \
            exit 1; \
          else \
            echo '=> dependency "$(strip $1): $(strip $2)" passed'; \
          fi
        endef

        all: a-derived.out
                @$(call sanitycheck, a.out         , a.src         )
                @$(call sanitycheck, a-derived.src , a.out         )
                @$(call sanitycheck, a-derived.out , a-derived.src )
        .PHONY: all

        kindaclean:
                rm -f -- *.out
        clean: kindaclean
                rm -f -- a-derived.src
        .PHONY: kindaclean clean

        %.out: %.src
                { echo 'build'; date; ls -l $^; } > $@

        a-derived.src: a.out
                { echo 'generate'; date; ls -l $^; } > $@
        a-derived.out: a.out # Make sure that "a.out" isn't skipped as 
intermediate

        .SECONDARY:

Which yields:

        $ echo foo > a.src

        $ make
        { echo 'build'; date; ls -l a.src; } > a.out
        { echo 'generate'; date; ls -l a.out; } > a-derived.src
        { echo 'build'; date; ls -l a-derived.src a.out; } > a-derived.out
        => dependency "a.out: a.src" passed
        => dependency "a-derived.src: a.out" passed
        => dependency "a-derived.out: a-derived.src" passed

        $ make kindaclean
        rm -f -- *.out

    $ # wait a momenent, so the timestamps are visibly different

        $ make
        { echo 'build'; date; ls -l a.src; } > a.out
        { echo 'build'; date; ls -l a-derived.src a.out; } > a-derived.out
        => dependency "a.out: a.src" passed
        => dependency "a-derived.src: a.out" failed because dependency "a.out" 
is newer than dependant "a-derived.src"
        -rw-r--r-- 1 lukeshu lukeshu 89 Feb 22 13:45 a-derived.src
        -rw-r--r-- 1 lukeshu lukeshu 85 Feb 22 13:47 a.out
        make: *** [Makefile:17: all] Error 1

--
Happy hacking,
~ Luke Shumaker

_______________________________________________
Bug-make mailing list
Bug-make@gnu.org
https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.gnu.org%2Fmailman%2Flistinfo%2Fbug-make&amp;data=01%7C01%7CMartin.Dorey%40hitachivantara.com%7C39c24e17d2914b68964308d698fed009%7C18791e1761594f52a8d4de814ca8284a%7C0&amp;sdata=6uJzMYFWkMGPLpN7OCR32wm2d7lCsdQ0vX7KhL3YRbA%3D&amp;reserved=0
_______________________________________________
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make

Reply via email to