bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Erroneously not updating intermediate/secondary dependency


From: Luke Shumaker
Subject: Erroneously not updating intermediate/secondary dependency
Date: Fri, 22 Feb 2019 14:45:03 -0500
User-agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM/1.14.9 (Gojō) APEL/10.8 EasyPG/1.0.0 Emacs/26 (x86_64-pc-linux-gnu) MULE/6.0 (HANACHIRUSATO)

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]