bugmake - Bugs: bug #59490, target may not be remade if...

 
 

bug #59490: target may not be remade if prerequisite has no recipe

Submitter:  Greg Minshall <minshall>
Submitted:  Fri 20 Nov 2020 06:52:47 AM UTC
   
 
Severity:  3 - Normal Item Group:  Bug
Status:  Not A Bug Privacy:  Public
Assigned to:  None Open/Closed:  Closed
Component Version:  4.3 Operating System:  POSIX-Based
Fixed Release:  None Triage Status:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Wed 02 Dec 2020 08:02:21 AM UTC, comment #5: 

thanks, both.

i apologize for my posted question being incomplete!

i'm very sympathetic to this:

> However, your makefile is lying to make; it says that the
> recipe for b1 builds just b1, but in fact it also builds c1
> "behind make's back".

(as, in general, i'd rather be a truth-teller).

i guess for public release, i had better not rely on "&:", until >= 4.3 make(1) become widely distributed.

thanks, by the way, for the fact that (afaict) if i have

b1 c1 &: a1
   <some recipe>
d1: c1
   <some other recipe>

but, in a run, <some recipe> is run, b1 changes, but c1 is not changed, then d1 is not remade.

cheers.

Greg Minshall <minshall>
Fri 27 Nov 2020 07:33:02 AM UTC, comment #4: 

I've checked other implementations of make that aim to be POSIX compatible and they also do not rebuild d1 in this situation.  I can't find any text in POSIX that specifies how this should behave.  Indeed, the POSIX spec is very limited in its discussion of targets that do not have commands.

In fact one other make implementation I found will never consider d1 to be out of date no matter how many times you run it, if the c1 target doesn't have a recipe.

Paul D. Smith <psmith>
Group administrator
Fri 20 Nov 2020 08:12:01 PM UTC, comment #3: 

Your attached makefile shows the issue you're trying to get at, but the example in your question is incomplete: it's missing the fact that (a) you run "make d1" and (b) the file "c1" must already exist before the makefile runs.  If "c1" doesn't exist, then "d1" will get rebuilt.

It's not actually the case that this is due to the directory cache, at least not exactly.  I have a set of changes locally that "fix" the directory cache problem by invalidating the cache every time make invokes a command of any type.  However it doesn't change the behavior in this case.

The reason for the behavior is that make starts with d1, then decides it needs c1.  Then it tries to build "b1", and succeeds.  However, your makefile is lying to make; it says that the recipe for b1 builds just b1, but in fact it also builds c1 "behind make's back".  Since make has no idea that c1 was modified, it does not re-check the timestamp for c1.

Whether this is right or not, I'm not sure.  I'd have to re-check the manual and the POSIX spec.  It's certainly the way GNU make has worked for 30 years or so.

If you just want to avoid the problem, another alternative to using an empty recipe (assuming you have GNU make 4.3) is to tell make the truth: that one rule builds both targets.  You can do that with:


b1 c1 &: a1
        touch b1
        touch c1


(and remove the "c1: b1" prerequisite).

Paul D. Smith <psmith>
Group administrator
Fri 20 Nov 2020 06:48:32 PM UTC, comment #2: 

Greg, you observe the effect of make fs cache.
In order to avoid this effect you need to tell make explicitly that c1 is to be rebuilt when b1 changes.

e.g.

b1: a1
        touch b1
c1: b1
        touch c1
d1: c1
        touch d1

Dmitry Goncharov <dgoncharov>
Fri 20 Nov 2020 11:54:24 AM UTC, comment #1: 

though maybe it's not so simple?  e.g., if b is remade, but c doesn't change, then probably d shouldn't change.

i guess my naive hope/expectation is that b will be remade, then c's date/time will be compared with that of d to decided if d should be remade.

Greg Minshall <minshall>
Fri 20 Nov 2020 06:52:47 AM UTC, original submission:  

i have a feeling this is already known, and maybe accepted, behavior, but it seems wrong, non-intuitive, to me.

if i have a dependency chain like

b1: a1
  touch b1
  touch c1
c1: b1
d1: c1
  touch d1


then, if b1 needs to be re-made, d1 will not be remade, even though c1's prerequisite b1 is out of date.

if i change to 'c1: b1;', it works.

i find the behavior surprising, and i would think worthy of changing.  (i'm guessing this is an optimization?)

with the attached Makefile, a 'make test' will show failure (or, success, should it succeed).

Greg Minshall <minshall>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #50308:  Makefile added by minshall (2KiB - application/octet-stream - make test)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by psmith (Posted a comment)
  • -email is unavailable- added by dgoncharov (Posted a comment)
  • -email is unavailable- added by minshall
  • -email is unavailable- added by minshall (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 4 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2021-03-15 psmith StatusNone Not A Bug
        Open/ClosedOpen Closed
    2020-11-20 minshall Attached File- Added Makefile, #50308
        Carbon-Copy- Added minshall

    Back to the top

    Powered by Savane 3.13-02a9.
    Corresponding source code